While SVG might be easier to handle, Canvas has advantages when it comes to showing and animating more elements:
- SVG allows you to draw roughly 10,000 elements and animate 1,000 or so elements. With Canvas you can animate around 10,000 points. Why? First of all, Canvas is lower level and has fewer abstraction layers to keep and manage in memory. Secondly, browsers (like most monitors) mostly support a frame rate of 60 frames per second, meaning the screen is updated 60 times per second. This leaves 1000 / 60 = 16.67 milliseconds to finish all necessary rendering and housekeeping activities. As human brains are fooled into perceiving fluid animation at a mere 16 frames per second, the maximum time for rendering a frame is 1000 / 16 = 62.5 milliseconds — but you should strive for a shorter time. For SVG these activities include DOM parsing, render tree production, layout and screen painting, to name the most important. The path between Canvas changes and image is shorter. The browser turns the context instructions into an array of pixel values before painting it to the canvas.
- If you need more elements to render or animate, accessing the alternative WebGL context is as easy as defining canvas.getContext(‘webgl'). WebGL allows you to animate 100k elements and more. While WebGL code is close to GPU programming and hence not for the faint-hearted, abstraction libraries like Three.js, Pixi.js, or regl make it more accessible.
Check out Peter Beshai's excellent tutorial on animating 100,000 points with WebGl and regl at https://peterbeshai.com/beautifully-animate-points-with-webgl-and-regl.html.
- Canvas is a rasterized graphics system. This just means the image consists of a raster (we could also say a matrix) of pixels. As a result, scaling can lead to blur, but in turn it's simple to download your canvas as an image. A further problem are high Dots Per Inch (DPI) or retina screens, that can make Canvas blur. You can use the following setup to support retina displays on Canvas:
var devicePixelRatio = window.devicePixelRatio || 1
var canvas = d3.select(‘body').append(‘canvas')
.attr(‘width', width * devicePixelRatio)
.attr(‘height', height * devicePixelRatio)
.style(‘width', width + ‘px')
.style(‘height', height + ‘px');
var context = canvas.getContext(‘2d');
context.scale(devicePixelRatio, devicePixelRatio);
Considering this, it seems a wise choice to stick to SVG for as long as possible and pull Canvas out of the hat when many elements need to be drawn or moved around. You might want to keep things simple until they can't be. One not-so-simple case could be the animation of a great many points. Let's look at an example that demonstrates the performance benefits Canvas has by building an element-heavy, animated application first with SVG and then with Canvas.