[html] Chart.js canvas resize

In (Android WebView HTML5 canvas error) i posted a question regarding plotting graphs using Graph.js library. The problem i have now is that if i call the function to plot the graph multiple times, the canvas resizes every time. Each time the graph is redrawn to the same canvas, its size also changes. I also tried setting the size of the canvas but without success.

What could be the reason? Why does the canvas resize every time?

This question is related to html canvas chart.js

The answer is


If anyone is having problems, I found a solution that doesn't involve sacrificing responsiveness etc.

Simply wrap your canvas in a div container (no styling) and reset the contents of the div to an empty canvas with ID before calling the Chart constructor.

Example:

HTML:

<div id="chartContainer">
    <canvas id="myChart"></canvas>
</div>

JS:

$("#chartContainer").html('<canvas id="myChart"></canvas>');
//call new Chart() as usual

I had to use a combination of multiple answers here with some minor tweaks.

First, it is necessary that you wrap the canvas element within a block-level container. I say to you, do not let the canvas element have any siblings; let it be a lonely child, for it is stubborn and spoiled. (The wrapper may not need any sizing restrictions placed on it, but for safety it may be good to have a max-height applied to it.)

After assuring that the previous conditions are met, when initiating the chart, make sure the following options are used:

var options = { 
    "responsive": true,
    "maintainAspectRatio": false
}

If you want to adjust the height of the chart, do so at the canvas element level.

<canvas height="500"></canvas>

Do not try to deal with the child in any other manner. This should result in a satisfyingly, properly laid-out chart, one that stays in its crib peacefully.


What's happening is Chart.js multiplies the size of the canvas when it is called then attempts to scale it back down using CSS, the purpose being to provide higher resolution graphs for high-dpi devices.

The problem is it doesn't realize it has already done this, so when called successive times, it multiplies the already (doubled or whatever) size AGAIN until things start to break. (What's actually happening is it is checking whether it should add more pixels to the canvas by changing the DOM attribute for width and height, if it should, multiplying it by some factor, usually 2, then changing that, and then changing the css style attribute to maintain the same size on the page.)

For example, when you run it once and your canvas width and height are set to 300, it sets them to 600, then changes the style attribute to 300... but if you run it again, it sees that the DOM width and height are 600 (check the other answer to this question to see why) and then sets it to 1200 and the css width and height to 600.

Not the most elegant solution, but I solved this problem while maintaining the enhanced resolution for retina devices by simply setting the width and height of the canvas manually before each successive call to Chart.js

var ctx = document.getElementById("canvas").getContext("2d");
ctx.canvas.width = 300;
ctx.canvas.height = 300;
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);

I had the same kind of scaling issue's using Angular CLI. Was able to get it working by removing this line from the index.html:

<script src="node_modules/chart.js/dist/Chart.bundle.min.js"></script>

and then in the angular-cli.json file, in the scripts section, using this:

"scripts": ["../node_modules/chart.js/dist/Chart.bundle.min.js"]

Source: mikebarr58


This works for me:

<body>
    <form>
        [...]
        <div style="position:absolute; top:60px; left:10px; width:500px; height:500px;">
            <canvas id="cv_values"></canvas>

            <script type="text/javascript">
                var indicatedValueData = {
                    labels: ["1", "2", "3"],
                    datasets: [
                        {
                            [...]
                        };

                var cv_values = document.getElementById("cv_values").getContext("2d");
                var myChart = new Chart(cv_values, { type: "line", data: indicatedValueData });
            </script>
        </div>
    </form>
</body>

The essential fact is that we have to set the size of the canvas in the div-tag.


I had a similar problem and found your answer.. I eventually came to a solution.

It looks like the source of Chart.js has the following(presumably because it is not supposed to re-render and entirely different graph in the same canvas):

    //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);
}

This is fine if it is called once, but when you redraw multiple times you end up changing the size of the canvas DOM element multiple times causing re-size.

Hope that helps!


In IOS and Android the browser hides the toolbar when you are scrolling, thereby changing the size of the window which inturn lead chartjs to resize the graph. The solution is to maintain the aspect ratio.

var options = { 
    responsive: true,
    maintainAspectRatio: true
}

This should solve your problem.


I tried to Resize Canvas using jQuery but it din't work well. I think CSS3 is the best option you can try on, if you want on hover zooming at certain level.

Following hover option from other codepan link:

.style_prevu_kit:hover{
    z-index: 2;
    -webkit-transition: all 200ms ease-in;
    -webkit-transform: scale(1.5);
    -ms-transition: all 200ms ease-in;
    -ms-transform: scale(1.5);   
    -moz-transition: all 200ms ease-in;
    -moz-transform: scale(1.5);
    transition: all 200ms ease-in;
    transform: scale(1.5);
}

Follow my codepan link:

https://codepen.io/hitman0775/pen/XZZzqN


Add div and it will solve the problem

<div style="position:absolute; top:50px; left:10px; width:500px; height:500px;"></div>

As jcmiller11 suggested, setting the width and height helps. A slightly nicer solution is to retrieve the width and height of the canvas before drawing the chart. Then using those numbers for setting the chart on each subsequent re-draw of the chart. This makes sure there are no constants in the javascript code.

ctx.canvas.originalwidth = ctx.canvas.width;
ctx.canvas.originalheight = ctx.canvas.height;

function drawchart() {
    ctx.canvas.width = ctx.canvas.originalwidth;
    ctx.canvas.height = ctx.canvas.originalheight;

    var chartctx = new Chart(ctx);
    myNewBarChart = chartctx.Bar(data, chartSettings); 
}

 let canvasBox = ReactDOM.findDOMNode(this.refs.canvasBox);
 let width = canvasBox.clientWidth;
 let height = canvasBox.clientHeight;
 let charts = ReactDOM.findDOMNode(this.refs.charts);
 let ctx = charts.getContext('2d');
 ctx.canvas.width = width;
 ctx.canvas.height = height;
 this.myChart = new Chart(ctx);

I was having the same problem. I was able to solve it by setting option:

_x000D_
_x000D_
responsive: false,_x000D_
maintainAspectRatio: true,_x000D_
showScale: false,
_x000D_
_x000D_
_x000D_

And in css, set the width of the container div the same as the canvas:

_x000D_
_x000D_
    #canvasContainer { _x000D_
      width: 300px;_x000D_
    }_x000D_
    _x000D_
    canvas {_x000D_
      width: 300px;_x000D_
    }
_x000D_
_x000D_
_x000D_


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to canvas

How to make canvas responsive How to fill the whole canvas with specific color? Use HTML5 to resize an image before upload Convert canvas to PDF Scaling an image to fit on canvas Split string in JavaScript and detect line break Get distance between two points in canvas canvas.toDataURL() SecurityError Converting Chart.js canvas chart to image using .toDataUrl() results in blank image Chart.js canvas resize

Examples related to chart.js

Set height of chart in Chart.js how to set start value as "0" in chartjs? Setting width and height Chart.js v2 hide dataset labels How to format x-axis time scale values in Chart.js v2 How to set ChartJS Y axis title? how to display data values on Chart.js How to set max and min value for Y axis JavaScript Chart.js - Custom data formatting to display on tooltip In Chart.js set chart title, name of x axis and y axis?