How to Resize HTML Canvas Element

Resize HTML5 canvas to fit window

I believe I have found an elegant solution to this:

JavaScript

/* important! for alignment, you should make things
* relative to the canvas' current width/height.
*/
function draw() {
var ctx = (a canvas context);
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
//...drawing code...
}

CSS

html, body {
width: 100%;
height: 100%;
margin: 0;
}

Hasn't had any large negative performance impact for me, so far.

How to resize the canvas using JavaScript?

The following jsfiddle demonstrates how to resize the canvas. https://jsfiddle.net/intrinsica/msj0cwx3/

(function() {  var canvas = document.getElementById('canvas'),      context = canvas.getContext('2d');
// Event handler to resize the canvas when the document view is changed window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight;
// Redraw everything after resizing the window drawStuff(); } resizeCanvas();
function drawStuff() { // Do drawing here context.strokeRect(10,10, 230,100); context.font = '16px serif'; context.fillText('The canvas is the blue', 30, 30); context.fillText('background color seen here.', 30, 50); context.fillText('It will resize if the window', 30, 70); context.fillText('size is adjusted.', 30, 90); }})();
* { margin:0; padding:0; } /* to remove the top and left whitespace */
html, body { width:100%; height:100%; } /* just to be sure these are full screen*/
canvas { background: #77f; /* to show the canvas bounds */ display:block; /* to remove the scrollbars */}
<canvas id="canvas"></canvas>

Add CSS Resize Property to Canvas Element

No, CSS resize is not applicable to inline elements. <canvas>, just like <img> is an inline element. Thus, you cannot use this property on canvases. See MDN Note

Note that you could wrap you canvas inside a resizeable block container and make your canvas to display at 100%, but remember this is just for display. This will stretch the actual pixel content of your canvas image.

const ctx = canvas.getContext('2d');ctx.arc(25,25,25,0,Math.PI*2);ctx.fill();
.resize-me {  display: inline-block;  border: 1px solid;  resize: both;  width: 50px;  height: 50px;  overflow: hidden;}canvas {  width: 100%;  height: 100%;  pointer-events: none; /* Chrome needs this oO */}
<div class="resize-me">  <canvas id="canvas" width="50" height="50"></canvas></div>

Resizing a canvas element via dragging the edges

  1. Put your fabric.js canvas in a wrapper div.
  2. Make the wrapper resizable. Here I'm using CSS resize. It only adds a bottom-left corner as a resize control but it's good enough for the sake of the demo. To have all the edges as controls you can try something like this.
  3. Detect the wrapper's size change. Ideally, you would use something like ResizeObserver. However, since browser support is still about 80% at the time of posting this, you might feel the need to use a polyfill or write something specific to your case. A simple setInterval with size check might prove to be sufficient.
  4. When the wrapper's size changes, set new fabric.js canvas dimensions via setWidth() and setHeight().

const canvas = new fabric.Canvas('c')

canvas.add(new fabric.Rect({
width: 100,
height: 100,
fill: 'red',
left: 100,
top: 50,
}))

const canvasWrapper = document.getElementById('wrapper')
// initial dimensions
canvasWrapper.style.width = '300px'
canvasWrapper.style.height = '150px'

let width
let height
setInterval(() => {
const newWidth = canvasWrapper.clientWidth
const newHeight = canvasWrapper.clientHeight
if (newWidth !== width || newHeight !== height) {
width = newWidth
height = newHeight
canvas.setWidth(newWidth)
canvas.setHeight(newHeight)
}
}, 100)
#wrapper {
border: solid 1px black;
resize: both;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
<div id="wrapper">
<canvas id="c"></canvas>
</div>

Resize canvas element when parent changes its width/height

The problem is that there is not (yet) a good way to do this. Instinctively you would look for a resize event on an element. But that can only be applied to the window as explained here on MDN.

After doing some research and looking at other threads I found a couple of options for you to consider.

Continuous loop

Draw the image in a recursive function which will also check the imgDiv's width and height every time it draws itself.

CSS:

canvas {
width: 100%;
height: 100%;
}

JS:

function draw(ctx, imgDiv, img) {
ctx.canvas.width = imgDiv.offsetWidth;
ctx.canvas.height = imgDiv.offsetheight;
ctx.drawImage(img, 0, 0);
requestAnimationFrame(() => {
draw(ctx, imgDiv, img);
});
}

img.onload = function() {
draw(ctx, imgDiv, img);
};

This option has the benefit of checking all the time it can, but I image it can be quite heavy in terms of performance. requestAnimationFrame does improve performance by firing the function only when it is allowed in the speed of the framerate. So about 60 times per second on average.

ResizeObserver (Warning: experimental technology)

This is one I have not seen anywhere yet. The ResizeObserver is new and is in the family of the IntersectionObserver, PerformanceObserver and MutationObserver. Like the name suggests it observers changes in elements that are resized and fires a callback when it detects a change.

It works like this:

const observer = new ResizeObserver(entries => {
entries.forEach(entry => {
// Update the canvas dimensions.
});
});

// Observer the image-div when it resizes.
observer.observe(imgDiv);

Since it is experimental I wouldn't recommend using it, although it would perfectly fit your scenario. More on browser support for this API her on Caniuse and an article on how to use it from Alligator.io.

Use the resize event on window

This would only capture the scenario of changing the width of the window or document. And in case of your sidebar opening and closing it would need some extra tinkering.

window.addEventListener('resize', (event) => {
requestAnimationFrame(() => {
// Update the canvas dimensions.
});
});

Using requestAnimationFrame here is recommended since the resize event will be called on every pixel and can slow down performance.

Edit:

It seems that Artyomska solved the problem already. And although the issue is resolved I still want to share my research in case a future query may stumble on this thread.

Resizing a HTML canvas blanks its contents

You need to either resize the canvas with CSS or redraw the canvas after you resize it.

If you want to save the content of the canvas and redraw it, I can think of a few options:

  1. Use context.getImageData to grab the whole canvas, resize the canvas, then use context.putImageData to redraw it at the new scale.
  2. Create an Image object, setting the source to the result of canvas.toDataUrl(), resize the canvas, then draw the image at the new scale.
  3. call context.setScale(xscale, yscale) and call whatever function you used to draw the canvas originally. Assuming you set up xscale and yscale correctly, it will automatically scale everything to the new size.
  4. Create a new canvas with the updated size and call context.drawImage(oldCanvas, ...) to copy the old canvas onto the new one. Then you would switch out the old canvas with the new one.

The first two options won't work if you have drawn an image from a different domain to the canvas at any time, and aren't supported by older implementations.

In my opinion, option 3 (redrawing the image at the new scale) is the best if it's possible. It's the only option that will keep your lines completely smooth and sharp, and it will always work (assuming you still have all the information to generate the image).

Resize div containing a canvas

You could add a CSS width of 100% to the canvas element.

While resizing a canvas via CSS is usually not a good practice as it stretches / shrinks the "image inside the canvas", if it's in sync with the canvas width & height properties there's nothing wrong with it.

You can solve that inline:

<div class="canvas-wrapper">
<canvas height="30px" style="width: 100%;"></canvas>
</div>

Or use whatever CSS selection method you prefer instead.

Dynamic resize Canvas; keep image on position

You want to set the width and height attributes of the canvas element, not the css width and height which only stretch the canvas, which defaults to 300x150 width/height. You can dynamically size the canvas element with JavaScript.

Here is a working example.

//get the elementsconst canvas = document.getElementById("canvas");const myDiv = document.getElementById("my-div");
//set the width and height attributes to the div width and heightfunction resize(){ canvas.width = myDiv.clientWidth; canvas.height = myDiv.clientHeight;}//on page resize, call resize()window.addEventListener("resize", resize, false);
//call resize() initially to set the canvas size correctlyresize();
//you can call resize() when your div changes size, dynamically resizing the canvas to the div
div {  width: 50vw;  height: 50vh;  background-color: lightblue;}canvas {  background-color: rgba(255,0,0,0.5);}
<div id="my-div">  <canvas id="canvas"></canvas></div>


Related Topics



Leave a reply



Submit