新手问题 [已解决] 同时使用 tab 和 lazy_high_chart,怎么使图表宽度为 100%?

chairy11 · 2015年06月02日 · 最后由 jasontang168 回复于 2015年06月06日 · 4118 次阅读

问题:

使用 lazy_high_chart 画图,同时把图表放在 bootstrap 的 nav-tab 下面。

  • 情况一:打开页面是默认 active 的那个 tab-content,显示的 chart 是正常 100% 宽度。

  • 情况二:点击 tab,切换到相应的 tab-content,因为之前这个区域是 display:none 的,所以它得不到正常宽度,所以会显示默认宽度 600px。但我需要它显示的是 100% 宽度。

怎样才能以最简洁的方式让它显示 100% 宽度呢?

注:

  • 尝试一: 修改 css 为 scss svg rect{ width: 100%; } 无效。 它自动生成的 html 为 erb <rect x="0" y="0" width="600" height="400" strokeWidth="0" fill="#FFFFFF" class=" highcharts-background"></rect>

其它:正在研究这个官方例子另一个例子:我觉得它能解决这个问题,但好像代码太复杂了……我用不着这么多……

解决方案

回帖有几个解决方案,但我自己还没有用对。 目前比较简洁的是一个 css hack 方法

.tab-content > .tab-pane{
        display: block;
        height: 0;
        overflow-y: hidden;
        &.active{
          height: auto;
        }
      }

lazy_high_chart 或者其他 chart 组件,通常为了方便应用,一般都是通过初始化参数指定,或者直接从上层容器获取宽度,高度信息,所以请检查一下改变一下放置 chart 容器的宽度是不是正确。

#1 楼 @lgn21st 因为我是响应式页面,所以我自己也不知道具体宽度是多少,就没有设置。 有个设置的地方,但要填写的是数字,不让填写百分比,你看它都没有单位……

chart: {
            width: 400,
            height: 300
        },

#2 楼 @chairy11 肯定有办法,莫灰心,方法很多。

比如文档里面是否有说明这里的 width 是否可以传入一个 function,在 function 内去计算容器宽度可能也是一个办法。

#3 楼 @lgn21st 可是为了简洁一点,我现在是只在 controller 里面设置所有参数,在 view 中显示,就没有再在 js 文件中写什么了…… 如果要计算什么的,我想想,是不是应该在 view 中去改些什么东东……

现在我的写法是 view 中:

<div role="tabpanel" class="text-center">
  <ul class="nav nav-tabs text-center" role="tablist">
    <li role="presentation" class="active">
      <a href="#per_week"  class="btn btn-default" aria-controls="per_week" role="tab" data-toggle="tab">一周</a>
    </li>
    <li role="presentation">
      <a href="#per_month"  class="btn btn-default" aria-controls="per_month" role="tab" data-toggle="tab">一月</a>
    </li>
    <li role="presentation">
      <a href="#per_year"  class="btn btn-default" aria-controls="per_year" role="tab" data-toggle="tab">一年</a>
    </li>
  </ul>

  <!-- Tab panes -->
  <div class="tab-content">
    <article role="tabpanel" class="tab-pane active" id="per_week">
      <%= high_chart("asset_growth_per_week_chart", @asset_growth_per_week_chart)  %>
    </article>
    <article role="tabpanel" class="tab-pane" id="per_month">
      <%= high_chart("asset_growth_per_month_chart", @asset_growth_per_month_chart)  %>
    </article>
    <article role="tabpanel" class="tab-pane" id="per_year">
      <%= high_chart("asset_growth_per_year_chart", @asset_growth_per_year_chart)  %>
    </article>
  </div>

</div>

controller 中

# 资产增长 - 每周
   @asset_growth_per_week_chart = LazyHighCharts::HighChart.new('graph') do |f|
     f.chart({ type: 'line'} )
     series = {
         name: '资金数量',
         data: [7.0, 6.9, 9.5, 14.5, 18.4, 21.5, 25.2]
     }
     f.series(series)
     f.xAxis({categories: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']})
     f.yAxis({title: {text: '资产数量 (万)'}})
     f.plot_options(line:{
                        allowPointSelect: true,
                        cursor: "pointer" ,
                        color: 'rgb(122, 201, 237)',
                        dataLabels:{enabled: true},
                        enableMouseTracking: false
                    })
   end

#4 楼 @chairy11 具体细节我不够时间看,问问看其他人是否有经验,或者晚点我忙完手上的事情可以帮你看看。

楼主这个问题我也碰到过类似的,使用 lazy 在多个 tab pane 生成图,第一个是 100% 宽度,后面几个切换就是 pane 的宽度,很窄,然后浏览器缩小下,然后放大,就变成 100% 宽度了。

#2 楼 @chairy11 楼主,目前我也没有找到解决方案,盼论坛大牛提供解决方法。

@jasontang168 @chairy11

就像 @lgn21st 提及的那样,首先看这个选项支不支持类似于 label formatter 那样传入函数:

labels: {
  formatter: %|function(){ return this.value + '#{x_suffix}' }|.js_code
}

但是,非常遗憾,我查了一下 API,好像不支持,那么就只能使用纯 JS 的方式解决问题了。先获取 tab 宽度,然后使用 setSize 这个函数设置宽度就可以了,详情请仔细阅读 API,哈哈!

chart.setSize(chartWidth);

在处理响应式页面的时候我用的是: $(this).highcharts().reflow() $(this)是 highchart 的 DOM obj bs nav-tab 不是有事件调用吗?绑定 tab 的 click/shown 然后调用 reflow() 有没有试过?

#8 楼 @xhj6 有啊,在 view 中使用,就是丑陋了点。比如我上一个饼图,在 view 中是这么写的

<%= high_chart("asset_allocation_chart", @asset_allocation_chart) do |c| %>
        <%= raw "options.tooltip.formatter = function() {return '<b>'+ this.point.name +'</b>: '+ this.y +' %';}"  %>
        <%= raw "options.plotOptions.pie.dataLabels.formatter = function() {
        if (this.y > 5) return this.point.name + ': ' + Math.round(this.percentage*100)/100 + ' %';; }"  %>
    <% end %>

感觉像是把 js 代码写到 html 里,挺别扭的其实……

#9 楼 @gihnius 没明白。 因为我没有手动去 init tab 相关函数,现在不都是Unobtrusive JavaScript的么?我没有针对这个 tabpanel 写任何的 js,因为 html 里面已经写了data-toggle="tab"

有没有不写 js 来实现的解决方案?

#11 楼 @chairy11 如果不显示不用 display:none; 来做,改用 opacity: 0; 试试呢?

#12 楼 @miclle 我怎么觉得这么怪?按我的理解,如果 opacity:0,那它是在那里的,三个 tab-content 都在层叠在那,只是有两个透明了你看不见。但你鼠标 hover 或点击,难道不应该就碰到的始终是最上面那层?永远碰不到最下面那层?

#12 楼 @miclle 额,试了试,先覆盖 bootstrap 默认的,再修改 opacity

.tab-content{
        .tab-pane{
          display: block;
          opacity: 0;
          &.active, :hover{
            opacity: 1;
          }
        }
}

结果宽度倒是对了,但它三个本来是相对定位,所以 A 图在最上面,B 图在中间,C 图在最下面。 切换 tab 的时候,只显示 A,或 B,或 C,但位置不变,也就是说,显示 B 的时候,A 的位置 C 的位置就会是空白……

#12 楼 @miclle 现在效果是实现了,直接用 css 覆盖,然后用绝对定位,但感觉非常不优雅,那还真不如用 js 获取高度再改了。

.tab-content{
  position: relative;
  .tab-pane{
    display: block;
    opacity: 0;
    &.active{
      opacity: 1;
    }
  }
  article{
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
  }
}

#11 楼 @chairy11

对于本问题,@gihnius 的答案是最优解(我提的 reSize 也行,只不过要指定一下宽度,稍显麻烦了一些),具体实现可参考如下代码:

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  $('.chart', e.relatedTarget).highcharts().reflow();
})

注意以上代码未经测试,不一定可用,但思路应该是这样的,你后面改 CSS 就越走越远了。

另外,你把 js 写入 HTML 中,当然就很丑了啊,js 就应该在 js 文件中,而向传递 formatter 的函数,lazyhighcharts 给出的正确做法是写入 Controller 中(或 Model 中),具体写法见我在 8 楼给出的代码示例。

#12 楼 @miclle 看来还是得用 CSS 方法。不过这种用的不是透明度,而是 height.

.tab-content > .tab-pane{
        display: block;
        height: 0;
        overflow-y: hidden;
        &.active{
          height: auto;
        }
      }

#16 楼 @xhj6 不知道为什么,我用 js 就是没出效果。还是用 css 方案吧。

#7 楼 @jasontang168 我找到一个解决方案,请看原帖。

#18 楼 @chairy11 覆写 bootstrap 的 CSS 文件?

#20 楼 @chairy11 你 QQ 或者微信多少,可以实时交流下吗?

#21 楼 @jasontang168 我现在报废一台用了不到一年的苹果电脑,心情不好,不要找我。你就直接用上面那个 scss 的去覆盖对应的元素就行了!

#22 楼 @chairy11 谢谢楼主,塞翁失马,焉知非福。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号