Joshua's Docs - HTML Canvas Notes and Tricks


What & Link Type
MDN - Canvas APIs
    - Element: HTMLCanvasElement
Jenkov: HTML Canvas Tutorials Guide

Common Tasks

Clear the Canvas

const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);

Inserting an SVG Onto the Canvas

The easiest way is to use the context.drawImage() method:

<canvas id="canvas"></canvas>
<img id="svgAsImg" src="./file.svg" />

const context = canvas.getContext('2d');
const image = document.getElementById('svgAsImg');
const renderImage = () => {
	context.drawImage(image, 0, 0, image.width, image.height);
if (image.complete) {
} else {
	image.addEventListener('load', renderImage);

But, to use this you first need to get the SVG as an img element (the svgAsImg).

How to Import an Existing SVG Element

If you have the SVG as an existing <svg> element in the DOM, you can use this approach to convert it to an image element.

<svg id="mySvg">...</svg>
const context = canvas.getContext('2d');
const svgElem = document.getElementById('mySvg');

// Construct Data URI
const svgDataUri = URL.createObjectURL(new Blob([svgElem.outerHTML], {type: 'image/svg+xml'}));
const image = document.createElement('img');
image.addEventListener('load', () => {
	context.drawImage(image, 0, 0, image.width, image.height);
// Trigger load
image.src = svgDataUri;
Pre-Formatting as Data-URIs Powered Images

If you already have the full SVG as a string, but for some reason can't save and import it as a file, you can pre-make your <img> tags, with <img src='data:image/svg+xml;utf8,<svg ... > ... </svg>'>. You just need to encode the data first though. You can use an online tool, like this one, or do it all in JS:

const svgStr = `<svg xmlns="" width="800" height="600"><defs/><path fill="#fff" d="M-1-1h802v602H-1z"/><g><circle cx="401" cy="292.6" r="250.5" fill="#fff" stroke="#000" stroke-width="1.5"/><path fill="#fff" fill-opacity="null" stroke="#000" stroke-opacity="null" stroke-width="1.5" d="M254 171h108v58H254zM411 169h145v67H411zM365 289h35v37h-35zM256 391h174v87H256z"/><path fill="none" stroke="#000" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="1.5" d="M302 108l48 44M474 95l-57 54M270 390l35 38M324 392l-21 35M338 392l16 31M381 391l-25 31M309 478l21-30M349 477l-16-27M372 477l10-28M408 477l-25-28"/></g></svg>`;

const img = document.createElement('img');
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(svgStr)}`;

// You can use `img` without appending, or go ahead and append to show in browser

You can also use a library dedicated to this (with more bells and whistles, plus fixes some security issues): canvg.

Insert another canvas into your canvas

The context.drawImage() method actually accepts HTMLCanvasElement as the image to insert! Meaning that you can totally just insert the contents of one canvas element into another!

📄 -> MDN Doc on drawImage()

Troubleshooting / Common Issues

  • Changes to context.font are being ignored / overwritten

    • Canvas will reset the font to default if the dimensions of the canvas are altered (S/O)
  • context.drawImage() works for inserting an SVG in Chrome, but not in Firefox!

    • There is a known bug / quirk with FF: you must provide explicit dimensions within SVG strings

      • For example, if all your SVG has for dimensions is viewBox="0.0 0.0 440.0 50.0", you also need to add width="440" height="50" for it to work with insertion in FF. The values also cannot be percentages.
  • Canvas is drawing everything in the wrong spot, things are appearing warped, circles / arcs are showing up as ovals, etc.

    • If you are trying to make the canvas responsive with CSS (for example, so it fills the screen, as a background), make sure you are also updating the width and height properties of the <canvas> element

      • This is important, because canvas operations use the fixed dimensions of the canvas element as reference points; not the rendered / computed dimensions
    • To dynamically update the canvas, you could use a resize listener:

      const canvasElement = document.querySelector('canvas');
      window.addEventListener('resize', () => {
      	const dimensions = canvasElement.getBoundingClientRect();
      	canvasElement.width = dimensions.width;
      	canvasElement.height = dimensions.height;
  • Canvas is not completely filling shapes / slicing off parts of shape when using .fill()

    • If you using .fill() after drawing lines, make sure that you are calling .moveTo() to set the first point of the path before you do anything like .arc().
Markdown Source Last Updated:
Sat Mar 27 2021 00:36:30 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Fri Nov 13 2020 18:17:28 GMT+0000 (Coordinated Universal Time)
© 2021 Joshua Tzucker, Built with Gatsby