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!
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.
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.
Here is a corresponding JSFiddle: http://jsfiddle.net/vero4ka/WEh84/
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.
For me it's not working.
I need to manually zoom in/out to let the browser show the graph in responsive mode.
It looks like it doesn't react on myLineChart2.resize()method. When I switch a tab it draws a chart too small:

So in this case one needs to resize the window manually in order to see the graph.
Hi all, I'm doing something similar and wanted to note that this seems to have been introduced in https://github.com/nnnick/Chart.js/commit/10227f852b1f73ef0ceea05c7f4c4d39bda4ccd5. I'm looking through the code and trying to figure out what is causing this to happen. I'll let you know if I figure out a way around this.
EDIT: I looked around in the code for a while but couldn't find out a good solution. I have ended up re-rendering the graphs as needed. This isn't ideal but this one issue is a small price to pay relative to how much better 1.0.1 is than 0.2.
Ugh. Sorry this was my fault - somehow managed to post the wrong jsfiddle link.
We just need to make sure the canvas is visible in the DOM when we initialise the chart.
So, in your example, we can create instantiate the chart when we show the tab, and then destroy the other chart instance in the (now) hidden tab.
Here's (the correct) example: http://jsfiddle.net/291w2jLk/
So how will this work with charts that have dynamic values? My charts are constantly updated with real-time information so recreating them is not that simple :(
@nnnick Thanks, but what about multiple tabs? This seems to work for only two tabs.
Dynamic charts and multiple tabs: Solved!
I maintain a list of labels and a list of value arrays in memory, separate from the chart. Every time new data arrives, I update both the memory lists and the charts (multiple charts is multiple sets of labels and values arrays).
When changing tabs, I destroy the 'old' chart and recreate the 'new' chart from the in-memory data.
Note that there is some strange behavior. When you create charts with dynamic data, you must instantiate the chart with at least 2 sets of x/y values. If you don't the chart appears corrupted.
It looks like @nnnick and @ChristianSchuit have taken care of this issue so far. Closing for now.
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');
}
}
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
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(...);
}
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'));
});
@renatodeleao I'm having the opposite experience. If I manually fire a resize event like that, all the charts I have on any tab disappear.
@vero4karu Your solution works thanks. Could you provide an adaptation working with each()
This is what I have:
var myChart = null;
function load_chart(containerId) {
if(myChart != null){
myChart.destroy();
};
$(containerId + " .chart").each(function(i, canva){
var chart_id = $(canva).attr('id');
var ctx = document.getElementById(chart_id).getContext("2d");
myChart = new Chart(ctx).Radar(chartJS[chart_id], {
responsive : true,
maintainAspectRatio: true
});
});
}
I d'like to use dynamic "myChart" variables.
I have tried to store them in an array of objects but I have a problem to destroy them properly if the amount of charts is different from one tab to another.
@rafasashi Did you end up getting this to work with each() ?
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()
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!!!!!!
I have found a rather easy and somewhat lazy option. You can set all tabs to "tab-pane active" This way all your charts on the tabs show and render, then
setTimeout(yourFunction, 250);
function yourFunction()
{
$('.nav-tabs a[href="#anytabExceptdefault"]').tab('show')
$('.nav-tabs a[href="#backtoyourdefaultTab"]').tab('show')
Hello,
I am having same issue,when switching between multiple tabs.Resizing the window shows graph only in active tab.
In addition am having the following error in console:
EXCEPTION: TypeError: chart.ctx is null
Any idea on this?
So here's how i solved this:
<ul class="nav nav-tabs " id="nav-tab" role="tablist">
<li class="nav-item">
<a class="nav-link active chart-tab" id="a" href="#" data-toggle="tab">A</a>
</li>
<li class="nav-item">
<a class=" nav-link chart-tab" id="b" href="#" data-toggle="tab">B</a>
</li>
</ul>
<div id="nav-tabContent">
<canvas id="chart" height="400px"></canvas>
</div>
And added custom jquery listener
$(".chart-tab").on("click", function() {
chart.destroy();
// change next line to whatever fits your needs
chart = new Chart(ctx, groups[$(this).attr("id")]);
$(".chart-tab").removeClass("active");
$(this).addClass("active");
});
i am also having same problem,when i move from one tab to another tab containing Echart
it works perfectly in ubuntu and in Mac os it does not display the chart. Can anyone help me to solve this problem. I am setting width and height of the chart using external css file for responsive design.Below i attached screenshots for the problem.
put the class echart in each div chart, and execute that in your js.
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
$(".echart").each(function () {
var id = $(this).attr('_echarts_instance_');
window.echarts.getInstanceById(id).resize();
});
});
Most helpful comment
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: