Difference Between Svg and HTML5 Canvas

What is the difference between SVG and HTML5 Canvas?

See Wikipedia: http://en.wikipedia.org/wiki/Canvas_element

SVG is an earlier standard for drawing
shapes in browsers. However, SVG is at
a fundamentally higher level because
each drawn shape is remembered as an
object in a scene graph or DOM, which
is subsequently rendered to a bit map.
This means that if attributes of an
SVG object are changed, the browser
can automatically re-render the scene.

In the example above, once the
rectangle is drawn, the fact that it
was drawn is forgotten by the system.
If its position were to be changed,
the entire scene would need to be
redrawn, including any objects that
might have been covered by the
rectangle. But in the equivalent SVG
case, one could simply change the
position attributes of the rectangle
and the browser would determine how to
repaint it. It is also possible to
paint a canvas in layers and then
recreate specific layers.

SVG images are represented in XML, and
complex scenes can be created and
maintained with XML editing tools.

The SVG scene graph enables event
handlers to be associated with
objects, so a rectangle may respond to
an onClick event. To get the same
functionality with canvas, one must
manually match the coordinates of the
mouse click with the coordinates of
the drawn rectangle to determine
whether it was clicked.

Conceptually, canvas is a lower level
protocol upon which SVG might be
built.[citation needed] However, this
is not (normally) the case—they are
independent standards. The situation
is complicated because there are scene
graph libraries for Canvas, and SVG
has some bit map manipulation
functionality.

UPDATE:
I use SVG because of its markup language abilities - it can be processed by XSLT and can hold other markup in its nodes. Similarly I can hold SVG in my markup (chemistry). This allows me to manipulate SVG attributes (e.g. rendering) by combinations of markup. This may be possible in Canvas but I suspect that it's a lot harder.

HTML5 Canvas vs. SVG vs. div

The short answer:

SVG would be easier for you, since selection and moving it around is already built in. SVG objects are DOM objects, so they have "click" handlers, etc.

DIVs are okay but clunky and have awful performance loading at large numbers.

Canvas has the best performance hands-down, but you have to implement all concepts of managed state (object selection, etc) yourself, or use a library.


The long answer:

HTML5 Canvas is simply a drawing surface for a bit-map. You set up to draw (Say with a color and line thickness), draw that thing, and then the Canvas has no knowledge of that thing: It doesn't know where it is or what it is that you've just drawn, it's just pixels. If you want to draw rectangles and have them move around or be selectable then you have to code all of that from scratch, including the code to remember that you drew them.

SVG on the other hand must maintain references to each object that it renders. Every SVG/VML element you create is a real element in the DOM. By default this allows you to keep much better track of the elements you create and makes dealing with things like mouse events easier by default, but it slows down significantly when there are a large number of objects

Those SVG DOM references mean that some of the footwork of dealing with the things you draw is done for you. And SVG is faster when rendering really large objects, but slower when rendering many objects.

A game would probably be faster in Canvas. A huge map program would probably be faster in SVG. If you do want to use Canvas, I have some tutorials on getting movable objects up and running here.

Canvas would be better for faster things and heavy bitmap manipulation (like animation), but will take more code if you want lots of interactivity.

I've run a bunch of numbers on HTML DIV-made drawing versus Canvas-made drawing. I could make a huge post about the benefits of each, but I will give some of the relevant results of my tests to consider for your specific application:

I made Canvas and HTML DIV test pages, both had movable "nodes." Canvas nodes were objects I created and kept track of in Javascript. HTML nodes were movable Divs.

I added 100,000 nodes to each of my two tests. They performed quite differently:

The HTML test tab took forever to load (timed at slightly under 5 minutes, chrome asked to kill the page the first time). Chrome's task manager says that tab is taking up 168MB. It takes up 12-13% CPU time when I am looking at it, 0% when I am not looking.

The Canvas tab loaded in one second and takes up 30MB. It also takes up 13% of CPU time all of the time, regardless of whether or not one is looking at it. (2013 edit: They've mostly fixed that)

Dragging on the HTML page is smoother, which is expected by the design, since the current setup is to redraw EVERYTHING every 30 milliseconds in the Canvas test. There are plenty of optimizations to be had for Canvas for this. (canvas invalidation being the easiest, also clipping regions, selective redrawing, etc.. just depends on how much you feel like implementing)

There is no doubt you could get Canvas to be faster at object manipulation as the divs in that simple test, and of course far faster in the load time. Drawing/loading is faster in Canvas and has far more room for optimizations, too (ie, excluding things that are off-screen is very easy).

Conclusion:

  • SVG is probably better for applications and apps with few items (less than 1000? Depends really)
  • Canvas is better for thousands of objects and careful manipulation, but a lot more code (or a library) is needed to get it off the ground.
  • HTML Divs are clunky and do not scale, making a circle is only possible with rounded corners, making complex shapes is possible but involves hundreds of tiny tiny pixel-wide divs. Madness ensues.

SVG vs HTML5 Canvas Based Charts

Projects with a large amount of data may favor canvas. SVG approaches typically create a DOM node per point (unless you make paths), which can lead to:

  1. An explosion in the size of your DOM tree

  2. Performance problems

Using a path, you can get around this problem, but then you lose interactivity.

Say you're building a stock chart. If you are talking about a chart with, say... max 5 years and end of trade data samples only, I think the answer is clearly SVG. If you're talking about looking at Walmart's historical data from day one of trading or doing full trade information per minute, you are going to have to really look carefully at SVG. Probably will have to employ fancy memory management and a fetch-on-demand approach as SVG will fall apart, particularly if you go one sample to one SVG node.

If interactivity is a requirement, SVG easily has the edge, given:

  • It is a retained mode API
  • You can use typical event handlers
  • You can add/remove nodes easily, etc.

Of course, you see that if you require full interactivity, it may go against mechanisms that allow SVG to scale, like path collapsing, so there is an inherent tension here.

There is going to be a trade-off in extremes. If size is small, the answer is SVG hands-down. If size is large and no interactivity, the answer is SVG with path drawing only or using Canvas. If size is large and interactivity is required, you have to go canvas or tricky SVG, which is complex in either case.

Some libraries out there offer both canvas and SVG renders, such as ZingChart and Dojo. Others tend to stick with just one of the two options.

html5 canvas element and svg

SVG and canvas aren't really interchangeable technologies. SVG is a type of retained mode graphics where everything is drawn from a rather abstract model (the SVG document). Canvas on the other hand is a kind of immediate mode graphics, where there is no model and the client (JavaScript) must take care of redrawing, animations etc.

Diagrams in SVG versus HTML5 Canvas

Use SVG because—as a retained-mode drawing API—you can attach event listeners directly to specific elements, and change properties of specific elements and have the page magically update. Further, as a vector-based format, it is resolution-independent.

HTML5 Canvas, by comparison, is a non-retained-mode (aka immediate-mode) drawing API; every pixel you draw is blended with all other pixels on the canvas, with no concept of the original shape. Further, as a raster-based format, you would need to do some extra work to get the drawing commands to adjust for different display sizes.

In general, you should use Canvas if and only if you need:

  1. Direct setting of pixels (e.g. blurs, sparkly effects), or
  2. Direct getting of pixels (e.g. reading a user's drawing to save as a PNG, sampling portions of the image to detect visual overlaps), or
  3. massive number of 'objects' that won't move much or track individual events (SVG can be slow to redraw with thousands of objects).

Note also that you don't have to choose only one or the other. You can draw SVG onto canvas. You can include bitmaps (images) in SVG. You can even include HTML5 Canvas in SVG via <foreignElement>. You can have a single HTML page with multiple layered canvases and SVG elements with transparent backgrounds, intermingling the output of each.

HTML5 SVG vs Canvas for big number of lines?

Generally svg is better suited for vector images, like in your example. However canvas has a lot of benefits in modern browsers such as hardware acceleration, so for drawing the lines, as long as zooming, panning ect. isn't required performance will be using canvas.

Mouse events can be a pain using canvas, since you have to manually keep track of everything, so with 5000+ points using canvas it wont be fun. The trade off however will be once the points are drawn, assuming you only draw them once the page will behave fine regardless of the number of lines, since they are all drawn to a raster image and aren't part of the DOM.

Honestly though the best way to find it is to test what you currently have using canvas.

HTML5 Canvas vs SVG/VML?

HTML5 Canvas is simply a drawing surface for a bit map. You set up a draw (Say with a color and line thickness) , draw that thing, and then the Canvas has no knowledge of that thing: It doesn't know where it is or what it is, it's just pixels. If you want to draw rectangles and have them move around or be selectable then you have to code all of that from scratch, including the code to remember that you drew them.

On the other hand, every SVG/VML element you create is a real element in the DOM. By default this allows you to keep much better track of the elements you create and makes dealing with things like mouse events easier by default.

Canvas would be better for faster things and heavy bitmap manipulation (like animation), but will take more code if you want lots of interactivity.

Difference between svg and canvas in d3.js

The differences listed in the linked question/answers speak to the general differences between svg and canvas (vector/raster, etc). However, with d3 these differences have additional implications, especially considering that a core part of d3 is data binding.

Data Binding

Perhaps the most central feature of d3 is data binding. Mike Bostock states he needed to create d3 once he joined data to elements:

The defining moment was when I got the data-join working for the first
time. It was magic. I wasn’t even sure I understood how it worked, but
it was a blast to use. I realized there could be a practical tool for
visualization that didn’t needlessly restrict the types of
visualizations you could make. link

With SVG, data binding is easy - we can assign a datum to an individual svg element and then use that datum to set its attributes/update it/etc. This is built upon the statefulness of svg - we can re-select a circle and modify it or access its properties.

With Canvas, canvas is stateless, so we can't bind data to shapes within the canvas as the canvas only comprises of pixels. As such we can't select and update elements within the canvas because the canvas doesn't have any elements to select.

Based on the above, we can see that the enter/update/exit cycle (or basic append statements) are needed for svg in idiomatic D3: we need to enter elements to see them and we style them often based on their datum. With canvas, we don't need to enter anything, same with exiting/updating. There are no elements to append in order to see, so we can draw visualizations without the enter/update/exit or the append/insert approaches used in d3 svg visualizations, if we want.

Canvas without data binding

I'll use the example bl.ock in your last question, here. Because we don't need to append elements at all (or append data to them), we use a forEach loop to draw each feature (which is counter to idiomatic D3 with SVG). Since there are no elements to update, we have to redraw each feature each tick - redrawing the entire frame (notice the clearing of the canvas each tick). Regarding the drag, d3.drag and d3.force has some functionality anticipating use with canvas, and can allow us to modify the data array directly through drag events - bypassing any need for node elements in the DOM to directly interact with the mouse (d3.force is also modifying the data array directly - but it does this in the svg example as well).

Without data binding we draw elements based on the data directly:

data.forEach(function(d) {
// drawing instructions:
context.beginPath()....
})

If the data changes, we will probably redraw the data.

Canvas with Data Binding

That said, you can implement data binding with canvas, but it requires a different approach using dummy elements. We go through the regular update/exit/enter cycle, but as we are using dummy elements, nothing is rendered. We re-render the canvas whenever we want (it may be continuously if we are using transitions), and draw things based on the dummy elements.

To make a dummy parent container we can use:

// container for dummy elements:
var faux = d3.select(document.createElement("custom"));

Then we can make selections as needed, using enter/exit/update/append/remove/transition/etc:

// treat as any other DOM elements:
var bars = faux.selectAll(".bar").data(data).enter()....

But as elements in these selections aren't rendered, we need to specify how and when to draw them. Without data binding and Canvas we drew elements based on the data directly, with data binding and Canvas we draw based on the selection/element in the faux DOM:

bars.each(function() {
var selection = d3.select(this);
context.beginPath();
context.fillRect(selection.attr("x"), selection.attr("y")...
...
})

Here we can redraw the elements whenever we exit/enter/update etc which may have some advantages. This also allows D3 transitions by redrawing continuously while transitioning properties on the faux elements.

The below example has a complete enter/exit/update cycle with transitions, demonstrating canvas with data binding:

var canvas = d3.select("body")  .append("canvas")  .attr("width", 600)  .attr("height", 200);  var context = canvas.node().getContext("2d");
var data = [1,2,3,4,5];
// container for dummy elements:var faux = d3.select(document.createElement("custom"));
// normal update exit selection with dummy elements:function update() { // modify data: manipulateData(); var selection = faux.selectAll("circle") .data(data, function(d) { return d;}); var exiting = selection.exit().size(); var exit = selection.exit() .transition() .attr("r",0) .attr("cy", 70) .attr("fill","white") .duration(1200) .remove(); var enter = selection.enter() .append("circle") .attr("cx", function(d,i) { return (i + exiting) * 20 + 20; }) .attr("cy", 50) .attr("r", 0) .attr("fill",function(d) { return ["orange","steelblue","crimson","violet","yellow"][d%5]; }); enter.transition() .attr("r", 8) .attr("cx", function(d,i) { return i * 20 + 20; }) .duration(1200); selection .transition() .attr("cx", function(d,i) { return i * 20 + 20; }) .duration(1200); }

// update every 1.3 secondssetInterval(update,1300);

// rendering function, called repeatedly:function render() { context.clearRect(0, 0, 600, 200); faux.selectAll("circle").each(function() { var sel = d3.select(this); context.beginPath(); context.arc(sel.attr("cx"),sel.attr("cy"),sel.attr("r"),0,2*Math.PI); context.fillStyle = sel.attr("fill"); context.fill(); context.stroke(); }) window.requestAnimationFrame(render) }
window.requestAnimationFrame(render)
// to manipulate data:var index = 6; // to keep track of elements.function manipulateData() { data.forEach(function(d,i) { var r = Math.random(); if (r < 0.5 && data.length > 1) { data.splice(i,1); } else { data.push(index++); } })}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


Related Topics



Leave a reply



Submit