[javascript] HTML5 Canvas vs. SVG vs. div

What is the best approach for creating elements on the fly and being able to move them around? For example, let's say I want to create a rectangle, circle and polygon and then select those objects and move them around.

I understand that HTML5 provides three elements that can make this possible: svg, canvas and div. For what I want to do, which one of those elements will provide the best performance?

To compare these approaches, I was thinking of creating three visually identical web pages that each have a header, footer, widget and text content in them. The widget in the first page would be created entirely with the canvas element, the second entirely with the svg element, and the third with the plain div element, HTML and CSS.

This question is related to javascript html svg html5-canvas

The answer is


Just my 2 cents regarding the divs option.

Famous/Infamous and SamsaraJS (and possibly others) use absolutely positioned non-nested divs (with non-trivial HTML/CSS content), combined with matrix2d/matrix3d for positioning and 2D/3D transformations, and achieve a stable 60FPS on moderate mobile hardware, so I'd argue against divs being a slow option.

There are plenty of screen recordings on Youtube and elsewhere, of high-performance 2D/3D stuff running in the browser with everything being an DOM element which you can Inspect Element on, at 60FPS (mixed with WebGL for certain effects, but not for the main part of the rendering).


While there is still some truth to most of the answers above, I think they deserve an update:

Over the years the performance of SVG has improved a lot and now there is hardware-accelerated CSS transitions and animations for SVG that do not depend on JavaScript performance at all. Of course JavaScript performance has improved, too and with it the performance of Canvas, but not as much as SVG got improved. Also there is a "new kid" on the block that is available in almost all browsers today and that is WebGL. To use the same words that Simon used above: It beats both Canvas and SVG hands down. This doesn't mean it should be the go-to technology, though, since it's a beast to work with and it is only faster in very specific use-cases.

IMHO for most use-cases today, SVG gives the best performance/usability ratio. Visualizations need to be really complex (with respect to number of elements) and really simple at the same time (per element) so that Canvas and even more so WebGL really shine.

In this answer to a similar question I am providing more details, why I think that the combination of all three technologies sometimes is the best option you have.


To add to this, I've been doing a diagram application, and initially started out with canvas. The diagram consists of many nodes, and they can get quite big. The user can drag elements in the diagram around.

What I found was that on my Mac, for very large images, SVG is superior. I have a MacBook Pro 2013 13" Retina, and it runs the fiddle below quite well. The image is 6000x6000 pixels, and has 1000 objects. A similar construction in canvas was impossible to animate for me when the user was dragging objects around in the diagram.

On modern displays you also have to account for different resolutions, and here SVG gives you all of this for free.

Fiddle: http://jsfiddle.net/knutsi/PUcr8/16/

Fullscreen: http://jsfiddle.net/knutsi/PUcr8/16/embedded/result/

var wiggle_factor = 0.0;
nodes = [];

// create svg:
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('style', 'border: 1px solid black');
svg.setAttribute('width', '6000');
svg.setAttribute('height', '6000');

svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink",
    "http://www.w3.org/1999/xlink");

document.body.appendChild(svg);


function makeNode(wiggle) {
    var node = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var node_x = (Math.random() * 6000);
    var node_y = (Math.random() * 6000);
    node.setAttribute("transform", "translate(" + node_x + ", " + node_y +")");

    // circle:
    var circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    circ.setAttribute( "id","cir")
    circ.setAttribute( "cx", 0 + "px")
    circ.setAttribute( "cy", 0 + "px")
    circ.setAttribute( "r","100px");
    circ.setAttribute('fill', 'red');
    circ.setAttribute('pointer-events', 'inherit')

    // text:
    var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.textContent = "This is a test! ÅÆØ";

    node.appendChild(circ);
    node.appendChild(text);

    node.x = node_x;
    node.y = node_y;

    if(wiggle)
        nodes.push(node)
    return node;
}

// populate with 1000 nodes:
for(var i = 0; i < 1000; i++) {
    var node = makeNode(true);
    svg.appendChild(node);
}

// make one mapped to mouse:
var bnode = makeNode(false);
svg.appendChild(bnode);

document.body.onmousemove=function(event){
    bnode.setAttribute("transform","translate(" +
        (event.clientX + window.pageXOffset) + ", " +
        (event.clientY + window.pageYOffset) +")");
};

setInterval(function() {
    wiggle_factor += 1/60;
    nodes.forEach(function(node) {

        node.setAttribute("transform", "translate(" 
                          + (Math.sin(wiggle_factor) * 200 + node.x) 
                          + ", " 
                          + (Math.sin(wiggle_factor) * 200 + node.y) 
                          + ")");        
    })
},1000/60);

Knowing the differences between SVG and Canvas would be helpful in selecting the right one.

Canvas

SVG

  • Resolution independent
  • Support for event handlers
  • Best suited for applications with large rendering areas (Google Maps)
  • Slow rendering if complex (anything that uses the DOM a lot will be slow)
  • Not suited for game application

While googling I find a good explanation about usage and compression of SVG and Canvas at http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Hope it helps:

  • SVG, like HTML, uses retained rendering: When we want to draw a rectangle on the screen, we declaratively use a element in our DOM. The browser will then draw a rectangle, but it will also create an in-memory SVGRectElement object that represents the rectangle. This object is something that sticks around for us to manipulate – it is retained. We can assign different positions and sizes to it over time. We can also attach event listeners to make it interactive.
  • Canvas uses immediate rendering: When we draw a rectangle, the browser immediately renders a rectangle on the screen, but there is never going to be any "rectangle object" that represents it. There's just a bunch of pixels in the canvas buffer. We can't move the rectangle. We can only draw another rectangle. We can't respond to clicks or other events on the rectangle. We can only respond to events on the whole canvas.

So canvas is a more low-level, restrictive API than SVG. But there's a flipside to that, which is that with canvas you can do more with the same amount of resources. Because the browser does not have to create and maintain the in-memory object graph of all the things we have drawn, it needs less memory and computation resources to draw the same visual scene. If you have a very large and complex visualization to draw, Canvas may be your ticket.


I agree with Simon Sarris's conclusions:

I have compared some visualization in Protovis (SVG) to Processingjs (Canvas) which display > 2000 points and processingjs is much faster than protovis.

Handling events with SVG is of course much easer because you can attach them to the objects. In Canvas you have to do it manually (check mouse position, etc) but for simple interaction it shouldn't be hard.

There is also the dojo.gfx library of the dojo toolkit. It provides an abstraction layer and you can specify the renderer (SVG, Canvas, Silverlight). That might be also an viable choice although I don't know how much overhead the additional abstraction layer adds but it makes it easy to code interactions and animations and is renderer-agnostic.

Here are some interesting benchmarks:


For your purposes, I recommend using SVG, since you get DOM events, like mouse handling, including drag and drop, included, you don't have to implement your own redraw, and you don't have to keep track of the state of your objects. Use Canvas when you have to do bitmap image manipulation and use a regular div when you want to manipulate stuff created in HTML. As to performance, you'll find that modern browsers are now accelerating all three, but that canvas has received the most attention so far. On the other hand, how well you write your javascript is critical to getting the most performance with canvas, so I'd still recommend using SVG.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to svg

How to extract svg as file from web page How to display svg icons(.svg files) in UI using React Component? Why don’t my SVG images scale using the CSS "width" property? How to show SVG file on React Native? Easiest way to use SVG in Android? IE11 meta element Breaks SVG img src SVG changing the styles with CSS How to use SVG markers in Google Maps API v3 Embedding SVG into ReactJS How to change the color of an svg element?

Examples related to html5-canvas

Scaling an image to fit on canvas Tainted canvases may not be exported How to fix getImageData() error The canvas has been tainted by cross-origin data? JS Client-Side Exif Orientation: Rotate and Mirror JPEG Images Resize image with javascript canvas (smoothly) How to show a running progress bar while page is loading HTML5 Canvas Resize (Downscale) Image High Quality? HTML5 Canvas Rotate Image Real mouse position in canvas Changing three.js background to transparent or other color