Joshua's Docs - HTML Canvas Notes and Tricks
Light
help

Resources

What & Link Type
MDN - Canvas APIs
    - Element: HTMLCanvasElement
Guide
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" />

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

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>
<script>
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);
	URL.revokeObjectURL(svgDataUri);
});
// Trigger load
image.src = svgDataUri;
</script>
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="http://www.w3.org/2000/svg" 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
document.body.appendChild(img);

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.
Markdown Source Last Updated:
Mon Nov 23 2020 04:26:49 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Fri Nov 13 2020 18:17:28 GMT+0000 (Coordinated Universal Time)
© 2020 Joshua Tzucker, Built with Gatsby
Feedback