4

I made a speedtest to compare Snap.svg (SVG) to FabricJS (CANVAS): http://jsbin.com/tadec/7 function dummy().

In Chrome SVG renders in 120 ms, while CANVAS renders in 1100 ms. SVG is 9x faster than CANVAS.

Fabricjs.com page says in this example that Raphael takes 225 ms and Fabric takes 97 ms (parsing: 80, rendering: 17).

I have had an impression (after reading fabricjs.com and paperjs.org) that FabricJS and more generally Canvas is faster than SVG.

My speed test claims that SVG is significantly faster than Canvas (at least Snap.svg seems to be significantly faster than FabricJS).

Why FabricJS is so slow in my test? Have I made some mistake in comparison, because I'm surprised that SVG seems to be faster than Canvas in my speed test.

EDIT: My question is two-parted: Why rendering speed is so much slower in FabricJS and why dragging speed as well?

Timo Kähkönen
  • 11,962
  • 9
  • 71
  • 112

1 Answers1

8

Your benchmark is broken in my opinion, because beside measuring drawing to canvas you are measuring parsing of a huge string containing a path, over and over again. Separate this code out of the loop and you should get more reliable results.

Measurements that are provided for canvas libraries are provided for drawing, not for parsing or other pre-processing work. If you use canvas like you use SVG, then yes, it will be slower. It is not intended to be used like SVG. FabricJS provides a way to do that, but it is not optimal. One solution would be to parse path once, and then use same path over and over instead of parsing it every time.

Also, measurements are given probably for drawing a canvas, not for interaction with parts. As you say in comments, rendering may be improved, but why does dragging a shape take so much longer? Because:

  1. maybe path is being reparsed on each redraw (not sure how FabricJS works)
  2. because SVG can redraw only certain parts of image that you are moving, and canvas is usually redrawn completely. Why? Because you can't "erase" part of canvas where a shape used to be. So entire canvas is erased, and new positions are redrawn.

Why do then people say canvas is faster than SVG for such scenarios? Because it is if you use it properly. It will be more work, but it will work much faster.

  1. Don't use SVG paths for drawing shapes, or use simple paths and cache them
  2. Cache shapes which you use often into off-screen (hidden canvas) and then copy from that canvas onto visible canvas when needed
  3. If you have multiple independant layers of an image (for example 3 layers in a game, if you have background sky which is moving, background mountains which are moving slower and a character), use multiple canvases. Put canvases one over another, draw sky on the bottom canvas, draw mountains on second canvas and draw character on top canvas. That way, when character on top canvas moves, you don't have to redraw entire background.

I hope my answer is useful for you :)

Nikola Radosavljević
  • 6,871
  • 32
  • 44
  • How? Could you provide the fix? – Timo Kähkönen Feb 14 '14 at 23:47
  • My question is two parted: Separating string parsing could make "rendering" time better, but did you try to drag a shape over other shapes? It is significantly slower in FabricJS. And I have no idea yet, why it is so slow. – Timo Kähkönen Feb 14 '14 at 23:51
  • Why parsing should be separated? If all shapes were different, then parsing has to be taken into account. I didn't find soon so much different shapes. – Timo Kähkönen Feb 14 '14 at 23:59
  • Thanks. I a bit wonder this: "Because: of path parsing". Does FabricJS really parse string when something is dragged? – Timo Kähkönen Feb 15 '14 at 00:15
  • This was only an assumption. I don't know that it does. Second point does stand. In SVG for each shape/path there is a DOM object. In canvas, there is no notion of path or shape. You can't influence single shape isolated. – Nikola Radosavljević Feb 15 '14 at 00:24
  • +1. Second point is in fact very clever and every Canvas librarian should read it thoroughly. If FabricJS would make such optimization, it would be faster. Why draw entire scene, when there is nothing changed? – Timo Kähkönen Feb 15 '14 at 00:28
  • Side note: this was my common sense based on my experience with canvas, not with FabricJS. But look at http://fabricjs.com/svg-caching/ example with SVG caching. Try element interaction, and then click `Cache shapes` button and try again. If my answer was useful, feel free to accept it :) – Nikola Radosavljević Feb 15 '14 at 00:34
  • It is useful so I put +1, but I'd like to wait a bit more the acception, if there comes better answers. Just a joke :) – Timo Kähkönen Feb 15 '14 at 00:37