
Missing drawing API: Canvas vs SVG paradox - kodisha
http://bajcic.com/blog/82/missing-drawing-api
======
gruseom
_If you want to draw a lot of data, you have to use canvas. If you want to
have vector graphics, you have to use SVG. What are you supposed to do when
you need both? Good luck to you my friend_

We solved this problem for our domain by using SVG but bypassing the SVG DOM.
Instead of making API calls to build up vector elements, we string together a
gigantic blob of SVG markup as text and then splat it into the DOM in one go
using innerHTML. This works surprisingly well—it's amazing how much
computation you can cram in there without noticing any lag. We rebuild pretty
much the entire UI on every mouse move and scroll.

At the time we came up with this trick, there was one big drawback: you
couldn't put SVG elements inside HTML elements unless your doctype was XHTML.
I believe that has changed with HTML5, but haven't ported that code yet. Can
anyone add info here?

I have no idea how close this comes to Web/OpenGL; probably not very close,
but it was a way out of the dilemma for us.

Edit: It used to puzzle me why this was so fast, but it seems obvious now. JS
engines have optimized string concatentation, and the rendering of all that
markup is happening on the C++ side, so both things that have to happen here
are relatively quick. What's slow is the trip across the Grand Canyon from JS
to the rendering engine, and this technique only does that once. Essentially,
you're batching up all your API calls, and that saves you so much that the
fact that you're using a horrifically inefficient text protocol to do it
doesn't matter.

~~~
spellboots
You can use document fragments for this and get a similar performance boost
without resorting to string concatenation.

~~~
gruseom
Do you mean SVG document fragments? Can you explain in more detail or point to
an example?

~~~
spellboots
Here is an introduction. They are not SVG specific but you can build SVG
elements in a document fragment, which is a lot faster than appending to the
DOM, then append the fragment to the DOM all in one go.

See [http://ejohn.org/blog/dom-documentfragments/](http://ejohn.org/blog/dom-
documentfragments/) or google for an introduction.

Building strings and using innerHTML is a very ugly way to get performance,
you should definitely try to using the document fragment approach as it has
similar performance characteristics.

~~~
gruseom
So these are regular document fragments? I vaguely remember that we tried that
and it didn't work nearly as well, but it's been a while.

 _Building strings and using innerHTML is a very ugly_

Ah. Then you'll be dismayed to hear we use tables for layout as well :)

------
modeless
Canvas is a vector drawing API. Scaling a drawing to retina resolution or 300
DPI for printing is trivial.

Ultimately if you want to draw truly giant giant data sets, you need WebGL.
What's missing isn't a new browser drawing API, but a good WebGL charting
library.

~~~
juriga
Two.js[1] has a WebGL renderer and abstractions for basic vector graphics and
polygons. I haven't had the chance to use it in a project yet but it seems
promising. Two.js could even be used as a basis for a WebGL charting library
(thus providing another layer of abstraction).

[1] [http://jonobr1.github.io/two.js/](http://jonobr1.github.io/two.js/)

~~~
kodisha
Thanks, that sounds really promising, will give it a try!

------
mistercow
I don't understand why the author didn't just do his canvas drawing in a
resolution independent (or quasi-independent) way. Just choose a unit relative
to the size of the canvas, and do everything in those units, transforming your
coordinates to fit the width of the canvas element, which is resized to fit
the device.

------
spicyj
Sounds like you need a library like ART, which is described as a "Retained
mode vector drawing API designed for multiple output modes".

[https://github.com/sebmarkbage/art](https://github.com/sebmarkbage/art)

Essentially, you write your drawing code once and it can render to Canvas,
SVG, or VML depending on what you need. It doesn't yet have great
documentation or a ton of examples, but it's in use at Facebook in their ads
management and the page insights interface.

There's even bindings to Facebook's React
([http://facebook.github.io/react/](http://facebook.github.io/react/)) drawing
library which is a declarative library for building efficient, reusable view
components: [https://github.com/facebook/react-
art](https://github.com/facebook/react-art). I haven't had a chance to play
around too much yet but it looks very promising.

------
bsimpson
Retina canvas isn't that hard. Set the width and height attributes of your
canvas to be their CSS dimensions * devicePixelRatio, and scale all your
drawing calls by devicePixelRatio.

I agree that it's annoying that you have to think about it, but since it's a
low-level drawing API, I understand why it's done that way.

------
teleclimber
One thing to note with respect to SVG and Canvas is that these APIs are not
nearly as optimized in browsers as HTML is.

Since the web is predominantly HTML, Chrome and other browser devs have
focused all their efforts on optimizing it (and JS).

SVG and Canvas rendering has not gotten that kind of attention. However it
sounds like they are working on it now.

The upshot is that even if it doesn't seem like it would work today doesn't
mean it's dead in the water and we need yet another drawing API. Give it time.

It also means -- and I know this sounds crazy -- that you could try drawing
your dots with absolutely positioned 1px by 1px DIVs. I know this sounds
absurd but I once worked on a scrolling + scaling timeline widget that
performed 10x better when implemented with absolutely positioned HTML DIVs
than in SVG.

(And like gruesom noted, it is probably best to blast all your DIVs the DOM in
one shot.)

~~~
seszett
I've done this too (on [http://ssz.fr/ker/](http://ssz.fr/ker/) for example)
and I've noticed if indeed, HTML DOM was slightly faster than SVG up to a
couple Firefox versions ago, I have found it to be consistently slower on
Chromium, and about the same in the latest Firefox versions.

And 40k elements is a no way with any method other than canvas on Firefox,
though it can sometimes stay somewhat usable with SVG on Chromium.

~~~
teleclimber
Interesting. I should point out my experience with this is from about 18
months ago (Spring 2012).

------
daemonk
I am a bioinformatician interested in visualizations too. I totally understand
your situation wanting to use D3 but can't because of the amount of bio data.

I've been trying to develop a toy genome browser as a pet project while
procrastinating on writing my thesis. I faced a similar problem when rendering
a genome feature density plot and found mouse interactions with it was
painfully slow. I solved it by rendering the svg with d3 and then use canvg.js
to convert the svg into canvas. You can see the toy example here:
[http://www.nextgenetics.net/tools/browser/browser.html](http://www.nextgenetics.net/tools/browser/browser.html)

This prototype shows all genes from human chromosome 1. You can use WASD to
scroll and Q/E to zoom in and out. The white density plot on the bottom is d3
made and converted into canvas with canvg. All svg are rendered with d3 using
an element pooling system.

------
MrMike
While I don't have a solution, I'm facing very similar challenges.

~~~
kodisha
Ah, good to know there area others out there :)

I really liked the object model of paper.js, but the very same layers/object
model led to some performance issues ol large data sets. So im stuck with
custom canvas implementation with no vector/high res export solution.

------
theoa
Access to WebGL really helps.

Have a look at this fiddle:

[http://jsfiddle.net/theo/9narA/](http://jsfiddle.net/theo/9narA/)

25,000 3D cubes - with the required 8 vertices and 6 faces - each gently
rotating around its X-axis in real time. Use your pointing device to pan, zoom
and rotate the display.

Built with the Three.js library. Requires fast machine with good GPU and
browser that supports WebGL.

------
cheeaun
This reminds me of [http://famo.us/](http://famo.us/)

~~~
gruseom
What do they do? (I don't want to sign up to find out.)

~~~
camus
Nothing it is just vaporware. they put a demo out with some music there
promising the next generation html5 framework , but it was only to get
funding. This is pure Scamware.

What is funny is the author of Three.js did exactly the same demo ( without
the cheesy music ) with his framework, the difference is he has an real
framework used by thousand of developpers and he did not need 2 million dollar
funding to create it.

------
moocowduckquack
Take the output of d3 before it is drawn as svg and use it to draw to the
canvas instead.

------
smrtinsert
24.00? I would argue for a sample of the data and not the complete dataset.

~~~
gcr
I think that's a typo for 24.000, which is how UK people render "Twenty-four
thousand"

~~~
aardvark179
No, it's how some European countries write 24,000. The UK (like the US) uses .
as the radix point and , for digit grouping.

