amCharts不显示最初隐藏的div的图表

时间:2012-04-04 14:38:49

标签: javascript svg rendering

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

div可见性切换的确切方法是通过Bootstrap's tabbed navbar

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

这是一个jsFiddle which illustrates the problem;如果您切换到第2部分(在Chrome,Firefox中),则图表最初不可见。调整显示大小会使其显示。

10 个答案:

答案 0 :(得分:24)

我找到了初始行为和解决方法的原因 - 并且它都是特定的amCharts(与SVG本身无关)所以我相应地重新标记了这个标题。

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

非活动选项卡设置了display: none属性,因此DOM的这部分甚至不会被渲染,因此两个大小属性都返回零。这最终会导致amCharts在为隐藏div调用chart.write时创建一个0x0 SVG图表。

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


总而言之,我认为有两种方法可以解决这个问题:

  • 当且仅当其标签可见时,请致电chart.write以获取图表。
  • 当标签更改时,调用每个图表的handleResize方法。

(第一个选项避免了渲染不可见图表的初始命中,但每次更改标签时都会进行完全重绘。后者需要预先点击,但此后可能更快。对于奖励分数,最好解决方案是在每次调整大小之间呈现每个图表一次,第一次变为可见,但这会更复杂,因为它会涉及干扰默认事件监听器等等。)

更新:呈现不可见的图表会更加复杂化;特别是,我发现高度计算的问题没有考虑域轴所需的空间,因此将图表拉出其div。调用handleResize并未解决此问题 - 事先调用measureMargins看起来应该可以正常工作但却没有。 (可能有一种方法可以在此之后调用它以使其工作,例如resetMargins,但此时它开始感觉非常不稳定...)

因此我认为在不可见的div上首次渲染图表是不切实际的,所以我选择了上面的子弹组合。我在第一次看到图表的标签时会听到,然后为相应的图表对象调用chart.write - 每当标签发生变化时,所有之前呈现的图表都被告知要处理调整大小。

答案 1 :(得分:4)

*已编辑*

这是更新的fiddle。只有在显示选项卡后才会呈现画布。 我将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);
});

我想这并不是你想要的,但我希望它暂时有用。

答案 2 :(得分:3)

我遇到了同样的问题,但是我的解决方案是display的替代方法:none,你可以在css中使用这个类

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

这个屏幕的消失但是对于amchart是可见的,所以图表的分辨率永远不会丢失!!!!

答案 3 :(得分:1)

我完全赞同Andrzej Doyle。

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

以下内容适用于全球定义的购物车。

    function refreshchart(){
        chart.handleResize();
    };

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:1)

我也遇到了问题并通过使初始化程序成为函数来修复它。 Working fiddle

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

function makeChart() {
     var chart = AmCharts.makeChart("chartdiv", {
         //all the stuff
     });
}

答案 6 :(得分: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>

答案 7 :(得分:1)

<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>

答案 8 :(得分:0)

另一种解决方法是

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

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

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

希望这会有所帮助......

答案 9 :(得分:0)

我在不同的标签上有两个amcharts 。 要放在#chartdiv上的股票图表和要放在#chartdivpie上的饼图。 这就是我解决问题的方法。

我的自定义css - 覆盖bootstrap -

#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');
    })