Resizing a canvas can be tricky if we don't know a few rules that might not be easily guessed:
Changing the width or height property of a canvas in JavaScript erases its content and resets its context,
Using percentages (%) in the CSS width and height properties of a canvas does not change its number of pixels/resolution. Instead, it scales the existing pixels without erasing the content, giving a blurry effect when a canvas becomes larger, for example.
Before looking at how best to handle canvas resizing, let's see some examples below:
Code:
<script>
...
function resizeCanvas() {
canvas.width = 300;
}
</script>
...
<button onclick="resizeCanvas();">
Click this button to resize the canvas and erase it!
</button>
This time we are using a similar example as above, but we removed the button for resizing it, and we set the size of the canvas to 100x100 pixels. Instead of drawing inside, we draw two lines that join the diagonals.
Then, we added this CSS rule:
It's the same example as before, just adding this CSS code:
<style>
#myCanvas {
border: 1px solid black;
width:100%
}
</style>
And the result shows clearly that the resolution is still the same, only the pixels are bigger!
This is the trick to create a really responsive canvas:
Embed it in a <div> or in any parent container,
Use CSS with percentages on the width and the height CSS properties of the parent,
Use a resize listener on the parent of the canvas,
Change the width and height properties of the canvas from the JavaScript resize listener function (content will be erased),
Redraw the content, scaled accordingly to the size of the parent.
Yep, this is not a straightforward process...
HTML code:
<div id="parentDiv">
<canvas id="myCanvas" width="100" height="100" ></canvas>
</div>
CSS code:
<style>
#parentDiv {
width:100%;
height:50%;
margin-right: 10px;
border: 1px solid red;
}
canvas {
border: 2px solid black;
}
</style>
JavaScript code for the resize event listener:
function init() {
...
// IMPORTANT: there is NO WAY to listen to a DIV's resize
// listen to the window instead.
window.addEventListener('resize',
resizeCanvasAccordingToParentSize, false);
...
}
function resizeCanvasAccordingToParentSize() {
// adjust canvas size, take parent's size, this erases content
canvas.width = divcanvas.clientWidth;
canvas.height = divcanvas.clientHeight;
...
// draw something, taking into account the new canvas size
}
See the complete example that corresponds to the above code:
When the canvas is resized, its width became smaller than the monster's size. We scale down the monster (using ctx.scale!)
The code is very similar to the previous example, we just replaced drawDiagonals() by drawMonster(...), and we added a test in the drawMonster(...) function for scaling the monster if it's bigger than the canvas width (look at lines 10-16), this is a common trick:
function drawMonster(x, y, angle, headColor, eyeColor) {
// GOOD PRACTICE: SAVE CONTEXT AND RESTORE IT AT THE END
ctx.save();
// Moves the coordinate system so that the monster is drawn
// at position (x, y)
ctx.translate(x, y);
ctx.rotate(angle);
// Adjust the scale of the monster (200x200) if the canvas
// is too small
if(canvas.width < 200) {
var scaleX = canvas.width/200;
var scaleY = scaleX;
}
ctx.scale(scaleX, scaleY);
// head
ctx.fillStyle=headColor;
ctx.fillRect(0,0,200,200);
...
}