21

我正在使用amCharts (在幕后使用Raphaël )将一些图表呈现为 SVG;并且注意到如果 SVG 在最初不可见的 div 中呈现,则当 div 变得可见时浏览器不会立即呈现图像。但是,如果我修改显示,例如通过调整浏览器大小或 Ctrl-鼠标滚轮缩放,则在重新绘制页面时,SVG 图像将按预期呈现。

div 可见性切换的确切方法是通过Bootstrap 的选项卡式导航栏

我承认对 SVG 不是很有经验 - 这是浏览器渲染的问题,还是 amCharts 的 SVG 标记的问题,或者当我知道 SVG 的可见性已经改变时,我是否需要显式调用某种重绘方法?

这是一个说明问题的jsFiddle;如果您切换到第 2 部分(在 Chrome、Firefox 中),图表最初是不可见的。调整显示大小会使其出现。

4

10 回答 10

26

我已经找到了初始行为和解决方法的原因——而且都是 amCharts 特定的(与 SVG 本身无关),所以我相应地改写了标题。

发生的情况是,当 amCharts 创建 SVG 时,它需要(或至少决定)以绝对值定义宽度和高度。这些基于目标 div 的大小,通过offsetWidthoffsetHeight属性获得。

非活动选项卡具有display: none属性集,因此这部分 DOM 甚至没有被渲染,因此对于两个 size 属性都返回零。这最终导致 amCharts 在chart.write调用隐藏 div 时创建一个 0x0 SVG 图表。

调整大小可以解决问题,因为每个图表都会为窗口事件注册一个侦听器,该onresize事件会调用图表的handleResize方法。这会根据 div 的新(当前)尺寸强制重新计算宽度和高度。


所以总而言之,我认为有两种替代方法可以处理这个问题:

  • chart.write当且仅当其选项卡可见时才调用图表。
  • handleResize选项卡更改时调用每个图表的方法。

(第一个选项避免了渲染不可见图表的初始命中,但每次更改选项卡时都会重新绘制。后者会预先受到影响,但之后可能更快。对于奖励分数,最好的解决方案是在每次调整大小之间仅呈现每个图表一次,第一次变得可见,但这要复杂得多,因为它会涉及干扰默认事件侦听器等。)

更新:渲染不可见图表还有进一步的复杂性;特别是,我发现高度计算的问题没有考虑域轴所需的空间,因此将图表从其 div 中拉伸出来。这不是通过调用来解决的handleResize-measureMargins事先调用看起来应该可以工作,但没有。(可能还有另一种方法可以在此之后调用以使其工作,resetMargins但此时它开始感觉非常不稳定......)

因此,我认为第一次在不可见的 div 上渲染图表是不切实际的,所以我结合了上面的项目符号。我倾听第一次可见图表的选项卡,然后调用chart.write适当的图表对象 - 并且只要制表符更改,就会告知所有以前呈现的图表来处理调整大小。

于 2012-04-04T16:07:32.503 回答
4

* 已编辑 *

这是一个更新的小提琴。只有在显示选项卡后才会呈现画布。我将 chartdiv id 存储在一个数组中并检查其中是否存在。

* 已编辑 *

我发现的唯一解决方案是在显示特定选项卡后显示图表。

正如你在这个jsFiddle中看到的。

var tabs = $('.tabbable').tab()

tabs.on('shown', function(e){
   id = $(e.target).attr('href');        
   chartdiv_id = $(id).find('.chartdiv').attr('id');                        
   doChart(chartdiv_id, true);
});

我想这不是您正在寻找的东西,但我希望它暂时有所帮助。

于 2012-04-04T15:36:38.110 回答
4

我有同样的问题,但我的解决方案是 display:none,你可以在 css 中使用这个类

.hidden {
   position: absolute !important;
   top: -9999px !important;
   left: -9999px !important;
}

这种屏幕消失但对 amchart 可见,因此图表的分辨率永远不会丢失大小!!!!

于 2013-06-06T01:43:19.390 回答
2

这可能会帮助您解决问题。我的 amchart 显示在不同的选项卡 pan 中。由于调整大小问题,SVG 组件不允许他们显示该 div。

$(window).resize(function() {
    setTimeout(function() {
        chart.write("chartdiv1");
    }, 300);
});

创建图表时再次调整窗口大小..

于 2014-05-30T11:59:14.707 回答
2

我也遇到了这个问题,并通过使初始化程序成为一个函数来解决它。工作小提琴

$("#button").click(function(){
    $("#chartdiv").toggle();
    makeChart();
});

function makeChart() {
     var chart = AmCharts.makeChart("chartdiv", {
         //all the stuff
     });
}
于 2014-06-19T14:24:32.253 回答
2
<a href="#" class="show_charts">Show me charts</a>
<div class="charts_div" style="display:hidden;">
some charts here
</div>
<script>
    $(document).on('click', '.show_charts', function(){
        $('.charts_div').toggle();
        //just redraw all charts available on the page
        for(var i = 0; i < AmCharts.charts.length; i++) {
            AmCharts.charts[i].validateData();
        }
    });
</script>
于 2015-10-05T19:33:42.330 回答
1

我完全同意 Andrzej Doyle 的观点。

在带有自定义选项卡(不是 jquery 选项卡)的 cs-cart 上单击所选 div (选项卡)时在图表上发出 handleresize 对我有用。

以下工作在全局定义的购物车蜂鸣中起作用。

    function refreshchart(){
        chart.handleResize();
    };
于 2014-02-27T13:58:31.640 回答
1
var chart = null;
AmCharts.ready(function () {
    chart = AmCharts.makeChart('chart', .....);
});
$(document).ready(function(){
    $("#view_chart").click(function(){
        chart.validateSize();
    });
});


<button type="button" id="view_chart">View Chart</button>
<div style="display:none;" id="chart"></div>
于 2015-09-17T17:31:34.583 回答
0

另一种解决方法是

drawTransactionTypeChart();
setTimeout(function(){hidePieCharts();},1);

最初设置display:inline为 div 是图表容器,它会被渲染。

然后在 1ms 后设置display:none使用。setTimeout()

希望这可以帮助...

于 2013-12-19T11:21:27.267 回答
0

我在不同的选项卡上有两个 amcharts。将放置在#chartdiv 上的股票图表和将放置在#chartdivpie 上的饼图。这就是我解决问题的方法。

我的自定义 css - 覆盖引导程序 -

#chartdivpie { width: 1138px; height: 500px; }
.tab-content .tab-pane {
   position: absolute;
   top: -9999px;
   left: -9999px;
   display: inline;
}
.tab-content .tab-pane.active {
    position: inherit !important;
}

jQuery 调用

$('#myTab a').click(function (e) {
      e.preventDefault()
        $(this).tab('show');
        chart.invalidateSize();
        chart.write('chartdiv');
    })
于 2014-03-09T22:40:18.053 回答