Chart.js: Initializing Chart.js multiple times over same canvas changes its size for some devices

Created on 15 Apr 2014  Â·  14Comments  Â·  Source: chartjs/Chart.js

    //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
    if (window.devicePixelRatio) {
        context.canvas.style.width = width + "px";
        context.canvas.style.height = height + "px";
        context.canvas.height = height * window.devicePixelRatio;
        context.canvas.width = width * window.devicePixelRatio;
        context.scale(window.devicePixelRatio, window.devicePixelRatio);
    }

When devicePixelRation != 1 doing

ctx = canvas.getContext("2d")
new Chart(ctx).drawSomething
//then later drawing another chart on the same canvas with
new Chart(ctx).drawSomething
//
//then later another one
new Chart(ctx).drawSomething

keeps changing (getting smaller or bigger depending on devicePixelRatio) the chart size.

This can be easily reproduced if you zoom-in or zoom-out in firefox, refresh (verify that window.devicePixelRatio is not 1) and keep doing the mentioned procedure (creting new charts on the same canvas). The charts are getting smaller or bigger with every Chart initialization.

My workaround for now is to reset width/height again to initial values before creating chart again:

ctx = canvas.getContext("2d")
new Chart(ctx).drawSomething

//then later drawing another chart on the same canvas with
canvas.width = 400
canvas.height = 400
ctx = canvas.getContext("2d")
new Chart(ctx).drawSomething

Most helpful comment

I had the same distressing hover effect using one canvas for changing charts. For me the following was the solution. I found it @ http://stackoverflow.com/questions/24815851/how-do-clear-a-chart-from-a-canvas-so-that-hover-events-cannot-be-triggered - Answer from xchiltonx (modified):

// initialising variable for charts
var myChart = null;
//setting options
var options = {
    datasetFill : false,
    };

// funciton executed on clicking button "10"
function twenty() {
$.getJSON( "ltwen", function(data) {
var my_data = data;
var ctx = document.getElementById("myChart").getContext("2d");
// --> this is the key to solution - no hover effects of old charts anymore
if(myChart != null){
        myChart.destroy();
    }
myChart = new Chart(ctx).Line(my_data, options);
});
}

// funciton executed on pressing button "20"
function ten() {
$.getJSON( "lten", function(data) {
var my_data = data;
var ctx = document.getElementById("myChart").getContext("2d");
// --> this is the key to solution - no hover effects of old charts anymore
if(myChart != null){
        myChart.destroy();
    }
myChart = new Chart(ctx).Line(my_data, options);
});
}

I tried something with typeof myChart != 'undefined' - but it didnt work out. I hope it will work for you aswell.

All 14 comments

I can reproduce this issue as well.

I think I have an issue that is linked to this one. I am using chartjs to display data from a sql query. Every time uses change the query input, I create a new chart "var barChart = new Chart(ctx).Bar(data,..." , This works until the chart is scrolled over, when seemingly randomly, the canvas will revert back and forth between previously created charts. I'm still searching for the root cause, but I believe all chart instances are being added to the context and maybe a tooltip tool is switching between the instances ... Will reply if I figure it out.

Solution for me:
keep a reference to the chart create "barChart" and before rebuilding it with "new Chart(ctx).Bar(data,..." , destroy the previous instance with "barChart.destroy();"

Yep - you should call .destroy() on your chart instance before re-using the canvas, this will also remove all the event bindings and clean up references to the chart.

Also, if it's the same chart but with updated data, you could check out updating the data on the chart rather than reinitialising it instead?

@nnnick I have this issue as well with Meteor even using destroy. IMO we shouldn't have to call destroy when updating chart data. The API should support a clearData setData API that performs a full update on the internal segments object.

Hi @nnnick . Just to confirm. I've tried the workaround above i.e.

canvas.width = 400
canvas.height = 400
chart.destroy()
chart.create()

Still an issue. Chart canvas size multiples x 2 each create().

Can confirm that I'm seeing this issue as well, neither destroying nor the posted workaround seem to help.
Were there any changes recently related to this that could have revived this issue?

Same happened to me. I had charts inside tables. At first, it seemed like there was a conflict with Bootstrap, then I found out a simple canvas {width: 100%;} fixed it.

_Later edit:_ I also notice I had a barChart.destroy(); in my chart building loop:

var barChart = new Chart(charts[i]).Line(chartData[i], chartOptions);
barChart.destroy();

I had the same distressing hover effect using one canvas for changing charts. For me the following was the solution. I found it @ http://stackoverflow.com/questions/24815851/how-do-clear-a-chart-from-a-canvas-so-that-hover-events-cannot-be-triggered - Answer from xchiltonx (modified):

// initialising variable for charts
var myChart = null;
//setting options
var options = {
    datasetFill : false,
    };

// funciton executed on clicking button "10"
function twenty() {
$.getJSON( "ltwen", function(data) {
var my_data = data;
var ctx = document.getElementById("myChart").getContext("2d");
// --> this is the key to solution - no hover effects of old charts anymore
if(myChart != null){
        myChart.destroy();
    }
myChart = new Chart(ctx).Line(my_data, options);
});
}

// funciton executed on pressing button "20"
function ten() {
$.getJSON( "lten", function(data) {
var my_data = data;
var ctx = document.getElementById("myChart").getContext("2d");
// --> this is the key to solution - no hover effects of old charts anymore
if(myChart != null){
        myChart.destroy();
    }
myChart = new Chart(ctx).Line(my_data, options);
});
}

I tried something with typeof myChart != 'undefined' - but it didnt work out. I hope it will work for you aswell.

Initializing the chart variable to null (greldinard's solution) worked for me. My doughnut chart doubled in size on each button press.

@greldinard thx a lot!!!

You can use update() for v2.x

var chart_ctx = document.getElementById("chart").getContext("2d");

var chart = new Chart(chart_ctx, {
    type: "pie",
    data: {}
    options: {}
}

$.ajax({
    ...
}).done(function (response) {
    chart.data = response;
    chart.update();
});

@mtvbrianking not working

@nukec I have it working, if you can't get it to work for you; let me know, I do for you a fiddle.

Was this page helpful?
0 / 5 - 0 ratings