schlebe
schlebe

Reputation: 3716

Using chartjs, how to define relative width and height of canvas?

Using Chart.js version 4.2.0, I try to display a chart on a maximized window on Windows 11 where height of chart is 100% of screen's height and width of chart is 80% of screen's width.

I tried with following code

<body>
    <div height="100%" width="80%">
        <canvas id="canvas">

But this simple attributes don't do the job.

Finally, I have found this solution

<body>
    <div>
        <canvas id="canvas">
        </canvas>
    </div>

, options:
    { responsive: true
    , maintainAspectRatio: true
    , aspectRatio: 1.65

var ctx = document.getElementById("canvas").getContext("2d");
var myChart = new Chart(ctx, config);
myChart.canvas.parentNode.style.width = '80%';

This works correctly but is a little tricky because width (not height) is set dynamically in Javascript code and aspectRatio must be manually fixed in options.

Is there a simple solution to define width to 80% of screen and height to 100% of screen ?

My current screen size are 1920x1080.

What I obtain is

enter image description here

When I suppress aspectRatio in options, I obtains following chart

enter image description here

Upvotes: 2

Views: 1156

Answers (2)

Je Je
Je Je

Reputation: 562

This answer was the first hit I got from google after I upgraded chartjs from v3.9 to 4.4, so i thought I would add an example with CSS in case that helps someone too.

in css:

.chart-container {
    position: relative;
    height: 100vh;
    width: 80%;
} 

Add the chartjs canvas within a specific div using "chart-container" class which CSS properties are defined in your css file.

<div class="chart-container">
     <canvas id="chart_id"></canvas>
</div>

in your Chartjs options new Chart, make sure you add "maintainAspectRatio: false" (doc) as its default value is true (doc). Doc extract: "Note that in order for the above code to correctly resize the chart height, the maintainAspectRatio option must also be set to false."

...=new Chart(canvas_id,
{
    type:'line',
    data:{},
    options: {
            responsive: true,
            maintainAspectRatio: false,
            }
}
);

I added a feeddle using previous code: here

Note that since v4 of Chartjs I need to use the "umd" version of the CDN (chart.umd.min.js), for instance:

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js" integrity="sha512-CQBWl4fJHWbryGE+Pc7UAxWMUMNMWzWxF4SQo9CgkJIN1kx6djDQZjh3Y8SZ1d+6I+1zze6Z7kHXO7q3UyZAWw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Upvotes: 0

kikon
kikon

Reputation: 8665

It seems that the standard way for a chart.js plot to fill a certain area with a size set in css, is to do these:

  • include the canvas in a div that doesn't contain anything else

  • set the size in the style of the div, not the canvas (that is already done in your code)

  • have at least one size in absolute units, (that is not both in %) - in your case

      <div style="height:100vh; width:80vw">
          <canvas id="myChart"></canvas>
      </div>
    

    See also this comment from the docs.

  • set chart options maintainAspectRatio: false and responsive: true - the latter for the chart to be redrawn when you resize the window.

Here's a code snippet doing these, including a plugin I wrote that displays the current sizes of the canvas, div and window

const plugin = {
    id: 'canvasSizeMonitor',
    currentWidth: 0,
    currentHeight: 0,
    resizing: false,
    
    displaySizes(chart){
        const canvas = chart.canvas,
            div = canvas.parentElement;
        document.querySelector('#sizes').innerText+=
            `div: ${div.offsetWidth}x${div.offsetHeight}\n`+
            `canvas: ${canvas.offsetWidth}x${canvas.offsetHeight}\n`+
            `window:${window.innerWidth}x${window.innerHeight}\n`+
            `0.8 * ${window.innerWidth} = ${Math.round(0.8*window.innerWidth)}\n`+
            '---------\n'//`aspRatio: ${chart.options.aspectRatio.toFixed(3).replace(/[.]?0*$/, '')}\n\n`;
    },
    
    afterRender(chart){
        if(!plugin.resizing &&
            (chart.canvas.offsetWidth !== plugin.currentWidth ||
                chart.canvas.offsetHeight !== plugin.currentHeight)){
            plugin.resizing = true;
            setTimeout(
                function(){
                    plugin.resizing = false;
                    plugin.currentWidth = chart.canvas.offsetWidth;
                    plugin.currentHeight = chart.canvas.offsetHeight;
                    plugin.displaySizes(chart);
                }, 500
            )
        }
    }
};


chart = new Chart(document.getElementById("myChart"), {
    type: 'line',
    data: {
        datasets: Array.from({length: 8}, (_, i)=>({
            label: `k = ${i+1}`,
            data: Array.from({length: 100}, (_, j)=>({
                x: j/50, y: Math.exp(-j/10)*Math.cos((i+1)*j*Math.PI/100)
            }))
        }))
    },
    options: {
        parsing: {
            xAxisKey: 'x',
            yAxisKey: 'y'
        },
        pointStyle: false,
        borderWidth: 1,
        
        responsive: true,
        maintainAspectRatio: false,
        //aspectRatio: 1,
        scales: {
            x: {
                type: 'linear',
                grid: {
                    drawOnChartArea: true,
                    lineWidth: 1
                },
                border:{
                    color: '#000',
                },
                ticks: {
                    display: true,
                    color: '#000',
                    padding: 10
                },
                title: {
                    display: true,
                    text: 'x',
                    align: 'end'
                }
            },
            y: {
                type: 'linear',
                ticks: {
                    padding: 10,
                    color: '#000',
                },
                grid: {
                    drawOnChartArea: true,
                    lineWidth: 1
                },
                border:{
                    color: '#000',
                },
                title: {
                    display: true,
                    text: 'f[k](x)',
                    align: 'end'
                }
            }
        },
        plugins:{
            legend:{
                position: 'right'
            }
        },
        animation: {duration: 0}
    },
    plugins: [plugin]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.1.2/chart.umd.js"
        integrity="sha512-t41WshQCxr9T3SWH3DBZoDnAT9gfVLtQS+NKO60fdAwScoB37rXtdxT/oKe986G0BFnP4mtGzXxuYpHrMoMJLA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<body style="margin: 0">

<pre id="sizes" style="position: absolute; top: 0; right: 10px; text-align: right;background-color:rgba(255, 200, 100,0.4)"></pre>

<div style="height:100vh; width:80vw; padding:0; margin: 0; background: red">
<canvas style="background: #ddd" id="myChart"></canvas>
</div>

</body>

Upvotes: 2

Related Questions