ChartJS charts not generating within tabs

淺唱寂寞╮ 提交于 2019-12-21 19:49:38

问题


I'm trying to use ChartsJS within a tabbing system. The first chart in the first tab is rendered, but subsequent charts are not.

I believe this is because the tabs have display:none, so when the charts are first generated they are created in a div with zero dimensions.

This fixes the issue, but breaks the tabs:

.vertical-nav>div.tab-content {
    display: block !important;
}

With that in mind I've tried all kinds of ways to regenerate the charts after the tab is open, or force display:block just before generating the chart. Nothing works.

Here's my attempt to regenerate the charts:

jQuery(document).ready(function() {

    jQuery('.vertical-nav ul li span').click(function(){

        // Target the canvas within the correct tab
        var tabIndex = jQuery(this).parent().index();
        var canvasID = jQuery('.vertical-nav .tab-content:eq( ' + tabIndex + ' ) canvas').attr('id');

        theChart = charts[canvasID].chart;
        builtChart = charts[canvasID].builtChart;

        // Destroy all of the charts so that we can rebuild them
        for (var key in charts) {
            if (charts.hasOwnProperty(key)) {
                charts[key].builtChart.destroy();
            }
        }

        // get the chart data and options from the charts object
        newData = charts[canvasID].data;
        newOptions = charts[canvasID].options;

        // create the new chart
        newChart = document.getElementById(canvasID).getContext("2d");
        new Chart(newChart).Line(newData, newOptions);

    });
})

The staging site is: http://telcomplusplc.uberleaf.com/company/?tab=our-growth

I've even tried setting a timeout to delay the chart generation until the tab is displayed, but no luck.

You can see in the URL above that the first chart generates and regenerates as it should. It's just the rest of them that don't (presumably because they are with a display:none div on first generation).

Any help is much appreciated. Happy to give more info if needed.

Update

When the window is resized, the chart is redrawn. Here's the code for that (in chart.js):

// Attach global event to resize each chart instance when the browser resizes
helpers.addEvent(window, "resize", (function(){
    // Basic debounce of resize function so it doesn't hurt performance when resizing browser.
    var timeout;
    return function(){
        clearTimeout(timeout);
        timeout = setTimeout(function(){
            each(Chart.instances,function(instance){
                // If the responsive flag is set in the chart instance config
                // Cascade the resize event down to the chart.
                if (instance.options.responsive){
                    instance.resize(instance.render, true);
                }
            });
        }, 50);
    };
})());

I think what I need is to be able to fire that from a click function. I've tried an failed, my JS skills aren't that good.


回答1:


If you use display:none then chartjs doesn't know the size to make the chart and then doesn't. If you switch to jquery.hide()/show() it will work. Here's a jsfiddle

*The fiddle works without it but if you have a lot of content then you may need to also hide the area temporarily.

Javascript

var data1 = {
    labels: ["January", "February", "March", "April", "May", "June", "July"],
    datasets: [{ data: [65, 59, 80, 81, 56, 55, 40] }]
};
var data2 = {
    labels: ["January", "February", "March", "April", "May", "June", "July"],
    datasets: [{ data: [65, 59, 80, 81, 56, 55, 40] }]
};

// Load each chart and hide() the tab immediately.

var ctx = document.getElementById('chart1').getContext('2d');
var chart1 = new Chart(ctx).Bar(data1);
$('#tab1').hide();

var ctx = document.getElementById('chart2').getContext('2d');
var chart2 = new Chart(ctx).Line(data2);
$('#tab2').hide();

/* 
// will not work because chart is not rendered
$('#tab1_btn').on('click',function(){ 
    $('#tab1').css('display','block'); 
    $('#tab2').css('display','none') })
$('#tab2_btn').on('click',function(){ 
    $('#tab1').css('display','none'); 
    $('#tab2').css('display','block') })
*/

$('#tab1_btn').on('click',function(){ 
    $('#tab1').show(); 
    $('#tab2').hide() 
})
$('#tab2_btn').on('click',function(){ 
    $('#tab1').hide(); 
    $('#tab2').show() 
})

// if you have a lot of content in multiple tabs 
// it may be necessary to temporarily cover the content
$('#tab_cover').hide();

HTML

<button id="tab1_btn">tab1</button>
<button id="tab2_btn">tab2</button>
<div id="tab_cover"> </div>
<div id="tabs">
    <div id="tab1" class="tab">
        <canvas id="chart1" class="chart" width="400" height="300"></canvas>
    </div>
    <div id="tab2" class="tab">
        <canvas id="chart2" class="chart" width="400" height="300"></canvas>
    </div>
</div>

CSS

/* will not work because chart is not rendered
.tab { display:none } */
.chart { width:50% }
.float { float:right; width:50%; }
#tab_cover { background:#9ff; height: 100% !important; width:100%; position: absolute; z-index: 300; }



回答2:


I've found a solution. I was close with the code I had in the question. It seems that I need to destroy and resize the charts.

I also had to change the display status of the tabs manually.

Here's what works for me:

    function createNewChart(canvasID) {
        // get the chart data and options from the charts object
        newData = charts[canvasID].data;
        newOptions = charts[canvasID].options;

        // create the new chart
        theChart = document.getElementById(canvasID).getContext("2d"); console.dir(theChart);
        new Chart(theChart).Line(newData, newOptions);
    }

    jQuery('.vertical-nav ul li').click(function(){

        // Target the canvas within the correct tab
        var tabIndex = jQuery(this).index();
        var canvasID = jQuery('.vertical-nav .tab-content:eq( ' + tabIndex + ' ) canvas').attr('id');

        theChart = charts[canvasID].chart;
        builtChart = charts[canvasID].builtChart;

        // Destroy all of the charts so that we can rebuild them
        for (var key in charts) {
            if (charts.hasOwnProperty(key)) {
                jQuery('.vertical-nav .tab-content:eq( ' + tabIndex + ' )').css('display', 'block');
                jQuery('.vertical-nav .tab-content:eq( ' + tabIndex + ' ) .tab-content-chart').css('display', 'block');
                charts[key].builtChart.destroy();
                charts[key].builtChart.resize();
            }
        }

        createNewChart(canvasID);

    }); 



回答3:


I was running into the same issues when using hidden divs that only display upon certain selections from a drop-down. What I found to work is similar to what ow3n did. I created the graphs and then had them only generate once the selection was made.

HTML:

<div>
    <select>
        <option value="option-1">Option 1</option>
        <option value="option-2">Option 2</option>
        <option value="option-3">Option 3</option>
    </select>
</div>
<div class="chart1">
    <canvas id="chart1"></canvas>
</div>

<div class="chart2">
    <canvas id="chart2"></canvas>
</div>

<div class="chart3">
    <canvas id="chart3"></canvas>
</div>

Javascript:

//example of chart variables (I only included 1 example)
    var chart1 = {
        labels : ["2009","2010","2011","2012","2013","2014"],
        labelAlign: 'center',
        datasets : [
            {
                label: "Visitor Average",
                fillColor : "rgba(255,255,255,0)",
                strokeColor : "rgba(0,34,221,1)",
                pointColor : "rgba(0,34,221,1)",
                pointStrokeColor : "#fff",
                pointHighlightFill : "#fff",
                pointHighlightStroke : "rgba(0,34,221,1)",
                data: [28, 48, 40, 19, 86, 27]
            },
            {
                label: "Baseline Average",
                fillColor : "rgba(255,255,255,0)",
                strokeColor : "rgba(255,0,0,1)",
                pointColor : "rgba(255,0,0,1)",
                pointStrokeColor : "#fff",
                pointHighlightFill : "#fff",
                pointHighlightStroke : "rgba(255,0,0,1)",
                data: [65, 59, 80, 81, 56, 55]
            }
        ]

    }

window.onload = function(){
    var ctx1 = document.getElementById("chart1").getContext("2d");
    window.myLine1 = new Chart(ctx1).Line(chart1,  {
        responsive: true,
    });
}

//change graph per drop-down selection
    $(document).ready(function(){
        $("select").change(function(){
            $( "select option:selected").each(function(){
                if($(this).attr("value")=="option-1"){
                    $(".chart2").hide();
                    $(".chart3").hide();
                    $(".chart1").show();
                    var ctx1 = document.getElementById("chart1").getContext("2d");
                    window.myLine1 = new Chart(ctx1).Line(chart1,  {
                        responsive: true,
                    });
                }
                if($(this).attr("value")=="option-2"){
                    $(".chart2").show();
                    $(".chart1").hide();
                    $(".chart3").hide();
                    var ctx2 = document.getElementById("chart2").getContext("2d");
                    window.myLine2 = new Chart(ctx2).Line(chart2, {
                        responsive: true,
                    });
                }
                if($(this).attr("value")=="option-3"){
                    $(".chart3").show();
                    $(".chart1").hide();
                    $(".chart2").hide();
                    var ctx3 = document.getElementById("chart3").getContext("2d");
                    window.myLine3 = new Chart(ctx3).Line(chart3, {
                        responsive: true,
                    });
                }
            });
        }).change();
    }); 



回答4:


Taking bootstrap's tab as an example, my solution is to add class .loading-data to .tab-content before rendering using chart.js and remove the class after the rendering is done.

.tab-content.loading-data .tab-pane {
  display: block;
}

In this way, the .tab-panes will display in the instant of chartjs's rendering.



来源:https://stackoverflow.com/questions/29238743/chartjs-charts-not-generating-within-tabs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!