SVG images on a HTML5 Canvas

I wrote a while back about using SVG sprites in a HTML5 Canvas game, but there’s actu­ally a bet­ter way of doing it that doesn’t involve an external JavaScript lib­rary like canvg.

Rendering SVG to a HTML5 Canvas

It’s trivi­ally easy to load up a SVG image as a JavaScript Image ele­ment and draw that to the can­vas. There’s a few ways you can do this, with the easi­est being:

var source = new Image();
source.src = 'http://example.org/myfile.svg';
source.width = '100';
source.height = '100';

This example loads the source file into a new Image ele­ment, ready to be applied to a Canvas the same as any other image.

This takes the hassle and unpre­dict­ab­il­ity out of using a third party lib­rary because it uses the nat­ive browser’s SVG cap­ab­il­it­ies, and will prob­ably be faster to boot.

There are still a few quirks when it comes to load­ing SVG images this way, in par­tic­u­lar the browser may not get the width and height right. In the example above we’ve hard-coded the dimensions.

Actually Rendering to a Canvas

To actu­ally draw a SVG image to a can­vas, it’s the same as any other Image object.

// Set up our canvas on the page before doing anything.
var myCanvas = document.createElement('canvas');
myCanvas.width = 640;
myCanvas.height = 480;
document.getElementsByTagName('body') [0].appendChild(myCanvas);
// Get drawing context for the Canvas
var myCanvasContext = myCanvas.getContext('2d');
// Load up our image.
var source = new Image();
source.src = 'http://example.org/myfile.svg';
source.width = '100';
source.height = '100';
// Render our SVG image to the canvas once it loads.
source.onload = function(){
	myCanvasContext.drawImage(source,0,0);
}

This code loads the SVG image, cre­ates an image in the <body> and renders the SVG to the Canvas ele­ment. The onload is import­ant because it makes sure the image has com­pletely loaded before try­ing to draw it.

Rendering Dynamically Created SVG

If you’re going to be dynam­ic­ally cre­at­ing or modi­fy­ing your SVGs, this tech­nique won’t work.

Any SVG ele­ments loaded as Images no longer have a DOM access­ible for you to manip­u­late, so you will need to pre-load the SVG file and manip­u­late it prior to load­ing it in an Image. You can use any num­ber of tech­niques here such as XHR which I won’t go into.

The dif­fi­cult bit is load­ing the mod­i­fied SVG string back into an Image in order to plop it down onto a can­vas. The solu­tion to this is base64 encod­ing the image and cre­at­ing a Data URI.

The fol­low­ing code will cre­ate a data URI by base64 encod­ing the SVG string:

// My SVG file as s string.
var mySVG = '<svg […]';
// Create a Data URI.
var mySrc = 'data:image/svg+xml;base64,'+window.btoa(mySVG);
// Load up our image.
var source = new Image();
source.src = mySrc;

The btoa func­tion is a nat­ive func­tion to encode a string to base64, but is not offi­cially stand­ard­ised yet. It is a part of the WHATWG liv­ing stand­ard and is sup­por­ted in all SVG/Canvas-capable browsers with the excep­tion of IE9. If you require back­wards com­pat­ib­il­ity or IE9 sup­port there are count­less base64 lib­rar­ies out there you can use instead.

Some Caveats to using SVG on a Canvas

This tech­nique is great provid­ing you don’t require sup­port for IE8, in which case you’re out of luck and should look into using a third party ren­der­ing lib­rary in con­junc­tion with a Canvas shim.

If you’re only look­ing at tar­get­ing mod­ern browsers like Android 3+ and IE9+ this tech­nique will work per­fectly and give you the power and speed of the browser’s nat­ive SVG implementation.

About

A med­dler and a tinkerer, Ash has a back­ground in web devel­op­ment and an interest in HTML5 and browser-based gaming.

6 thoughts on “SVG images on a HTML5 Canvas

  1. Pingback: Chrome SecurityError: DOM Exception 18 | getContext

  2. I wanted to put all the load of svg data on data­base like mysql or mssql. And also put the load on server for ren­der­ing the svg rather on using much of cli­ent side band­width by down­load­ing js files in cli­ents browser. How can I achieve it? Is it feasible?

  3. Sure, that’s pos­sible. You could put the SVG into a MySQL text field, or even leave it on the filesys­tem there’s probabaly not that much difference.

    You could then use some­thing like ImageMagick with PHP to render them down into PNG files to send to the cli­ent. Good luck!