Chart.js: Problem with multiple charts in different tabs

Hi!

I’m using bootstrap for the layout and drawing multiple chats in different tabs:

<ul class="nav nav-tabs" role="tablist">
  <li class="active"><a href="#chart1" role="tab" data-toggle="tab">Chart 1</a></li>
  <li><a href="#chart2" role="tab" data-toggle="tab">Chart 2</a></li>
</ul>

<div class="tab-content">
  <div class="tab-pane active" id="chart1">
    <canvas id="myChart1" width="400" height="400"></canvas>
  </div>
  <div class="tab-pane" id="chart2">
    <canvas id="myChart2" width="400" height="400"></canvas>
  </div>
</div>

With the following javascript:

$(function() {
    'use strict';

    var line_chart_options = {
        scaleGridLineColor : "rgba(0,0,0,.05)"
    };
    var data = {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
    var data = {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [
            {
                label: "My First dataset",
                fillColor: "rgba(220,220,220,0.2)",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: [65, 59, 80, 81, 56, 55, 40]
            },
            {
                label: "My Second dataset",
                fillColor: "rgba(151,187,205,0.2)",
                pointHighlightStroke: "rgba(151,187,205,1)",
                data: [28, 48, 40, 19, 86, 27, 90]
            }
        ]
    };
    var ctx = $("#myChart1").get(0).getContext("2d");
    var myLineChart1 = new Chart(ctx).Line(data, line_chart_options);

    var ctx = $("#myChart2").get(0).getContext("2d");
    var myLineChart1 = new Chart(ctx).Line(data, line_chart_options);
});

But when I add responsive: true option

    var line_chart_options = {
        scaleGridLineColor : "rgba(0,0,0,.05)",
        responsive: true
    }

it stops showing a chart in the second tab.

Is there any way to get it to work?

Thank you in advance!

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 25 (4 by maintainers)

Most upvoted comments

No success with previous solutions and workarounds. No destroy(), rebuild(), clear(), redraw(), resize(), update(); reAnything() has save me. This ugly hack is the only thing that is working for me:


//dispatch event resize to trigger graph re-render
$('a[data-toggle=tab').on('shown.bs.tab', function (e) {
  window.dispatchEvent(new Event('resize'));   
});

I have this problem if I try to render in a parent with negative margins (even when not the direct parent, and only when < -10px 🙄 ). Seems like the width is getting calculated to 0 for the canvas, but the internal chart state (chart.chart) thinks it has the correct size. So when you run chart.resize() it kicks out early.

I am able to force a resize by doing this immediately after chart creation:

chart.chart.width = 0
chart.resize()

Thank you for your response!

I rewrote my javascript so it destroys and creates a chart each time a user changes a tab:

$(function() {
    'use strict';

    var line_chart_options = {
        scaleGridLineColor : "rgba(0,0,0,.05)",
        responsive: true
    };
    var data = {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [
            {
                label: "My First dataset",
                fillColor: "rgba(220,220,220,0.2)",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: [65, 59, 80, 81, 56, 55, 40]
            },
            {
                label: "My Second dataset",
                fillColor: "rgba(151,187,205,0.2)",
                pointHighlightStroke: "rgba(151,187,205,1)",
                data: [28, 48, 40, 19, 86, 27, 90]
            }
        ]
    };
    var ctx1 = $("#myChart1").get(0).getContext("2d");
    var myLineChart1 = new Chart(ctx1).Line(data, line_chart_options);

    var ctx2 = $("#myChart2").get(0).getContext("2d");
    var myLineChart2 = new Chart(ctx2).Line(data, line_chart_options);

    $('#tab2').on('shown.bs.tab', function (e) {
        myLineChart1.destroy();
        myLineChart1 = new Chart(ctx1).Line(data, line_chart_options);
    });

    $('#tab2').on('shown.bs.tab', function (e) {
        myLineChart2.destroy();
        myLineChart2 = new Chart(ctx2).Line(data, line_chart_options);
    });
});

But it still works only if I delete responsive: trueparameter from chart options.

Most likely it’ll be because the size of the container div is 0 because it’s hidden.

Try creating / destroying each chart when you show/hide the relevant tab. That way you’ll have the added bonus of seeing your chart animate when you click on the tab.

Also in your code you’re redefining myLineChart1 for your second line chart.

Let me know if that works and I’ll close this.

I have the same problem on a working chart without any tab or hidden technique. The problem occurs when i press F5 on Chrome. I don´t test on other browsers. Benogle solve my problem. Thanks man!!!

chart.chart.width = 0 chart.resize()

This works perfectly!!!

SOLVED!!

(Work for me, i have 20 tabs)

window.onload = function() { //tabs is an object array that contains properties (each id tab and every canvas id) for (var i = 0; i < tabs.length; i++) { $(‘.nav-tabs a[href="#’+tabs[i].tab_id+‘"]’).tab(‘show’);

    var barChartData = {
        labels : ["Label 1","Label 2","Label 3"],
        datasets : [
            {
            fillColor : "rgba(220,220,220,0.5)",
            strokeColor : "rgba(220,220,220,0.8)",
            highlightFill: "rgba(220,220,220,0.75)",
            highlightStroke: "rgba(220,220,220,1)",
            data : [50 , 20, 100]
            }
            ]

        }

        var ctx = document.getElementById(''+tabs[i].canvas_id+'').getContext("2d");
        window.myBar = new Chart(ctx).Bar(barChartData, {   responsive : true        });
};
//at the end show first tab
if (tabs.length>0){
    $('.nav-tabs a[href="#fn_'+tabs[0].tab_id+'"]').tab('show');
}

}

You can omit the for loop and use directly:

window.onload = function() { $(‘.nav-tabs a[href="tab1’"]‘).tab(‘show’); var ctx = document.getElementById(’‘canvas_tab1’').getContext(“2d”); window.myBar = new Chart(ctx).Bar(char1_data_object, { responsive : true });

$('.nav-tabs a[href="tab2'"]').tab('show');
var ctx = document.getElementById(''canvas_tab2'').getContext("2d");
window.myBar = new Chart(ctx).Bar(char2_data_object, {  responsive : true        });

//finally show tab1
$('.nav-tabs a[href="tab1'"]').tab('show');

}

PS: Sorry for my awful english, i do my best

Cheers for that.

Alrighty - the crux of the issue is when you first create the chart on the hidden second tab, the width/height of the container element is 0 because it’s hidden.

So, the solution is to create the chart instance when the canvas & container element is visible in the DOM, then create the chart when it becomes visible in a tab.

So here, we’re destroying the chart that’s going out of view, and reinitialising the one we’re showing: ~~http://jsfiddle.net/7a4YL/~~ (Edit: wrong link - http://jsfiddle.net/291w2jLk/)

I appreciate it’s a little bit wonky, but to responsively resize the canvas, Chart.js needs to know the size of the parent container, and when it reports 0, it causes a bit of a problem.

Let me know if that works.

Assuming your chart has a class of “.chart”, here’s a really simple function for Bootstrap 3 for that allows for a dynamic number of tabs by destroying and recreating graphs on change. Also doesn’t require global variables, allows you to customise the chart for each canvas (use data attributes on the canvas) and doesn’t require mad hide / show hacks.

var charts = {};

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    var current = $(e.target).attr('href').slice(1),
        previous = $(e.relatedTarget).attr('href').slice(1),
        chart = $('#' + current).find('.chart');
    if (charts[previous]) {
        console.log('Deleting previous chart: ' + previous);
        charts[previous].destroy();
        charts[previous] = null;
    }
    if (chart) {
        console.log('Creating new chart: ' + current);
        charts[current] = graph(chart);
    }
});

function graph(chart) {
    return new Chart(chart[0].getContext("2d")).Bar(...);
}

It looks like it doesn’t react on myLineChart2.resize()method. When I switch a tab it draws a chart too small:

chart

So in this case one needs to resize the window manually in order to see the graph.