[index]

Anton's Research Ramblings

HTML5 Drawing with SVG and D3

I'm involved with a new research project that wants some web-based visualisation of analytics. I have considerable experience now with JavaScript and WebGL, the 3d canvas, but I'm investigating 2d options now too. I recently looked at drawing with the 2d HTML5 canvas, which I unexpectedly found to be a raster drawing interface. It's quite easy and pleasing to use.


Playing-around with making charts with the 2d canvas interface. Pixel-exact but not automatically scalable to different resolutions.

To complement this experience I wanted to look at some vector-based web drawing tools. In the past this would have been with Flash, but I'm interested in new HTML capabilities. There's a very popular vector-based visualisation library called D3.js, and HTML is supposed to have an interface to using SVG (scalable vector graphics) built-in as well.

D3.js


It took way too long to find out how to make D3 do a simple bar plot with my own data. Custom interface knowledge required.

As soon as I looked at the introduction I immediately knew I was going to dislike D3. The entire introduction page introduces yet-another (pointless) JavaScript wrapper, similar to Node.js. There's not a single thing related to visualisation in the introduction - it's all about this custom JS interface - which frankly I don't want to allocate any brain space to learning. Okay, so skipping ahead - there's no instructions! Just a bunch of finished example visualisations to re-implement. What if I don't want to make a visualisation exactly like these? I played around with one - even finding out how to change the input data was difficult, and this was just a bunch of bars and lines. Not impressed. Here's the code to generate that simple bar plot:

I suspected just accessing the SVG directly should be easier than using this unusual abstract interface - I mean I just want to specify some lines, how hard is that? Note the custom version of the DOM being used, and the sizes must be given in pixels.

HTML5 SVG

In true w3c style, the SVG interface is a flaky, unreliable mess. It seems to be designed, really only considering that people would manually add "svg" tags directly into the HTML. This lets you do simple things like draw a circle, but is far to cumbersome for anything that you would actually want to draw. To do dynamic work we need a JS interface, for which the default SVG interface flat out does not work - it does't render anything.


A screenshot of my SVG chart. It wasn't harder to make a bar-chart manually with SVG compared to D3.js. The interface sucks, and requires pixel dimensions!

To get anything to work you have to point to a custom spec on the w3c website, and use custom versions of the DOM (document object model) functions, post-fixed with "NS". At this point it's starting to look a lot like the design of OpenGL. After some time doing trial-and-error to establish that things truly weren't working as specified, I found a reliable way to work:

Now I've created an SVG element in the page via JavaScript. Interestingly, the interface requires manual pixel sizes for things, which very much defeats the point in the "S" and "V" of "SVG". Do you really have to write custom cladding to resize everything when the SVG element is resized? Really? Follows my entire file for generating my bar char:

Interesting points to note:

I'm sorry, but no abstraction is worth using if it doesn't save you any time at all. SVG's interface is very badly designed. Once you get going with SVG you have a lot of sensible control over sizes and scales and so on. There are built-in functions for the usual lines and boxes. It's probably a good idea to compute your own canvas-relative factors to replace the pixel-exact sizes for bars and lines. In this case you could draw to any scale by refreshing the canvas when it's resized. It seems to have very nice anti-aliasing, which is a minor advantage of doing the same scaling thing with canvas 2d.

Summary

I'm not really impressed with 2d-canvas, SVG, or D3.js. None of them are great. WebGL at least uses the GPU (graphics processor unit). SVG and D3 are slow and have flaky interfaces. The manual scaling is just horrible. You can be very exact and produce sharper graphics with 2d canvas, that don't require any anti-aliasing, provided you know exactly the size of the canvas in advance. You can, of course, do 2d graphics with the 3d canvas, which would then also be hardware accelerated, and can access all sorts of interesting effects from that domain. Would I actually use these new tools? I'm not so sure - they have too many disadvantages to be good low-level APIs, and I find D3 just horrible - but I can see how it appeals to people who want to just modify a pre-built visual. C'mon people - it's not hard to manually make a sensible chart.