SVG Pros & Cons for Javascript developers
The good, bad and ugly of scripting SVG in the browser
Author: Tim Meadowcroft -- @schmerg
Extracted & expanded from a longer Intro to Scripting SVG presentation
Presentation written with Slidy2
Hit the space bar for next slide
Introduction - Overview
SVG Tips and Gotchas for javascript developers
Slides intended for a short (10 min) talk to the #LondonJS meetup group
Extracted and expanded from a slightly longer intro to SVG http://www.mysparebrain.com/svgjs
Hope to cover
Brief SVG history and overview
Some of the things it offers and what these mean
Examples of basic DOM and scripting
Some perhaps-not-too-obvious features for the scripter (good, bad, ugly)
Not intending to cover
Use for static images
Use for non-scripted animation
How specific tags work (esp. filters, gradients, text kerning, fonts)
My technology platform is better than yours
Eye candy demos and generally trading on the hard work of others
Quick history - Standards
What are all these versions, what should I target
PGML and VML (the first vector standard, suggested to W3C 1998 but then stopped, has become more buggy over time)
Adobe started SVG with their browser plugin (but then bought Flash from Macromedia)
First drafted 1999
W3C 1.0 recommendation 2001
Versions and revisions
1.0 - first spec
1.1 - re-structuring of 1.0 into modular components, no significant changes
SVG Tiny and Basic are then subsets of 1.1 for mobile devices (phones and PDAs) but of limited scripting use
1.1 2nd Edition - errata and clarifications, released 2011
1.2 has been working draft for ages but will probably become 2.0
2.0 will include SVG Print (for multi-page handling etc) + HTML5 etc
Quick history - Browser Support
Where will this work
Desktop
FF and Opera, first by extensions, then native browser support since 2005 (FF3, Opera 8/9)
Webkit since 2006, Chrome / Safari native support
No support in IE 6,7,8 unless Chrome Frame, Adobe plugin (now discontinued), Batik (Java) etc
IE9 managed to get 'full' support from a standing start in 12 months
IE9 release is very good (and fast) but no foreignObject, and not on XP
Libraries like SVGWeb provide seamless support in IE via VML (or sometimes Flash but marshalling painful)
Mobile / Tablet
iOS 4+ pretty good if slow (iPad2 fine, new iPad - anyone got one to test?)
Android browser had no support for SVG until Honeycomb (3.0)
Chrome for Android is available in beta
Only on Android 4 (ICS) so far (maybe for 2.3 as beta progresses)
After 10 years, OK on "modern" desktops (meaning not IE 6,7,8)
Mobile limited to iOS 4+, Android 4 or Chrome on Android (beta)
Basic characteristics
What does it offer me
Resolution independance (benefits both big and small scale) of vector graphics
"Pure vector" (WMF, plotters) is painful for textures/images but SVG is not "pure"
Native text as true text (but with SVG fonts if required) - Google are now indexing text within SVG
Images, including JPEG, PNG and SVG itself
Gradients, fills, filters including image based items
Declarative not procedural form, including largely arbitrary nesting
c.f. declarative advantages of functional vs procedural languages w.r.t. composition
Compound structures via nesting, re-use by id and href
Sprites, compound widgets and nested groupings of items
Further (non-nested) groupings by id/class
Native support within the browser
DOM integration including CSS
Full set of pseudo-classes (:hover etc)
Cursor control by attribute/CSS and mandatory support for custom cursors (PNG with transparency)
Many CSS3 features are actually just formalising the application to HTML elements of SVG style features
No need for specialist DevTools Inspector, IDE or other tooling
Fully integrated DOM for raster & vector graphics including text
Static (Declarative) Features
Intro to supported concepts and some idea of depth of functionality
Paths : moveto; lineto; curves; close; with ability to define lengths in user-units
Text : including paths, string and character rotations, fonts, alignment, kerning, stroke and fill etc
Shapes : line, polyline, rect, circle, ellipse, polygon, image (includes rounded rect, line width, dotted lines)
Painting : Fills (solid/gradient/pattern) including opacity, and markers such as arrowheads
Colours : fill/stroke including transparency, native attributes and full CSS support
Transformations : Clipping, masking, compositing and chainable transformations (scaling, translate, skew, rotate, arbitrary matrix)
Filters : Effects including blur, lighting, turbulence, blend, colour matrix
eg a monochrome filter and blurring over what's underneath (including HTML5 video)
Animation : <animate> tag specifies time-based transitions from start to
end values for parent's properties
Control over durations, stop points, easings, repetition
<animateMotion>, <animateColor>, <animateTransform> for complex values
You can achieve a lot before you need to start scripting
Declarative building blocks
Constructs for composition within SVG
<svg> defines an SVG fragment
Inline embedding of SVG within SVG defines a new viewport (with optional clipping)
A bit like position: relative and forcing every child position: absolute
<image> refers to the contents of a complete file: PNG, JPEG or SVG
<g> defines a group (including arbitrary nesting) but not a viewport
Handy for redraw order (layers) and CSS rules as well as group transformations
<defs> defines certain types of object for later use
eg define a linear gradient to be invoked later
<symbol> defines a template which is then invoked (if needed) with <use>
<use> instantiates a <symbol> template
But <use> can also quote other graphical elements including <g> and <svg>
Deep clones the element but with new parentage (eg CSS selector)
But maintains the attachment (ie not a snapshot)
Build composable structures that can be manipulated as a single item
Quick examples #1
Basic composition: shapes and text
<svg version="1.1" width='700px' height='250px'
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="1" y="1" width="699" height="249" style="fill: #eeffee; stroke: blue;" />
<g id="textBox" style='cursor: pointer;'>
<circle id='textCirc' cx='100' cy='100' r='75px' fill='yellow' opacity='0.5'
onclick='document.getElementById("textCirc").setAttribute("fill", "orange") '/>
<text x='100px' y='100px' style='fill: blue; font-weight: bold; font-size:20px;'>
<tspan>Text on top</tspan>
</text>
</g>
<g id="textBox2">
<text x='450px' y='50px' style='fill: blue; font-weight: bold; font-size:20px;'>
<tspan>Text under transparency</tspan>
</text>
<rect x='445px' y='25px' width='150px' height='50px' style='opacity: 0.5;' fill='yellow'/>
</g>
<use x='400' y='-25' xlink:href='#textBox' transform="rotate(20), scale(0.75,0.75)"/>
</svg>
Text on top
Text under transparency
Quick examples #2
Text on a path from http://www.w3.org/TR/SVG/text.html
<?xml version="1.0" standalone="no"?>
<svg width="15cm" height="4.5cm" viewBox="0 0 1000 250" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="MyPath"
d="M 100 200
C 200 100 300 0 400 100
C 500 200 600 300 700 200
C 800 100 900 100 900 100" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5" fill="blue" >
<textPath xlink:href="#MyPath">We go up, then we go down, then up again</textPath>
</text>
<rect x="1" y="1" width="998" height="298" fill="none" stroke="blue" stroke-width="2" />
</svg>
Example toap01 - simple text on a path
We go up, then we go down, then up again
Quick examples #3
Gradients from http://www.w3.org/TR/SVG/pservers.html
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1" xmlns="http://www.w3.org/2000/svg">
<desc>Example lingrad01 - fill a rectangle using a linear gradient paint server</desc>
<defs>
<linearGradient id="MyGradient">
<stop offset="5%" stop-color="#F60" />
<stop offset="50%" stop-color="#FFF" />
<stop offset="95%" stop-color="#FF6" />
</linearGradient>
<filter xmlns="http://www.w3.org/2000/svg" id="desaturate">
<feColorMatrix type='saturate' values='0.4' />
</filter>
</defs>
<rect fill="none" stroke="blue" x="1" y="1" width="798" height="398"/>
<!-- The rectangle is filled using a linear gradient paint server -->
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="100" y="50" width="600" height="100"/>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
filter="url(#desaturate)"
x="100" y="200" width="600" height="100"/>
</svg>
Example lingrad01 - fill a rectangle using a
linear gradient paint server
Scripting the DOM
Changing the document
Creation needs to be done by the correct DOM constructors or createElementNS() - no .innerHTML shortcuts
XML pedantry (namespaces)
Throws off javascript libraries that wrap HTML DOM elements
Essentially the same but beware HTML DOM assumptions
Comparison to Canvas
What does SVG do for you compared to Canvas
SVG gives you "for free" much of what you have to code yourself in Canvas
Features written in browser-specific but generalised native code rather than slower javascript
Can integrate with the rest of your DOM work (ie works like you modify the HTML DOM)
You may end up with a lot of DOM compared to what you're doing
What you get
Richer scriptable primitives (filters, gradients, transforms, fragments etc) with CSS integration
Browser events (including touch) per item & hit testing of visuals (stroke and fill)
Redraw loop including "dirty" calculations and clipping logic
Serialisable form at any point and further round-tripping
Composable mutable documents: eg generate SVG as output from gnuplot,
enhance
on server and/or client
Text support (now in Canvas but richer in SVG if needed )
What you lose
Full control of redraw scope and timing (eg memoising specific layers)
True single shot cost of complex one-off rendering (backgrounds etc)
Insight into memory use, timing and speed of operations (GPU optimisations) etc
Pixel level accuracy, introspection & tweaking
Fixed-price all-you-can-eat is expensive if you're just snacking
Even free pizza is useless unless you like the pizza on offer
Techniques
Some tricks of doing basic stuff in Canvas and SVG
Mouse hit testing
SVG: Use builtin event routing with pointer-events to get/avoid hits on border and fill
Canvas: Make a 2nd canvas, encode IDs as colours, then read the pixels from this hidden canvas
Canvas technique also allows arbitrary hit testing, SVG relies on initiation with events
Fuzzy hit testing
SVG: Use invisible backing items with opacity='0' pointer-events='all'
Canvas: As above but draw them bigger on the hidden canvas
Layering and bring-to-front
SVG: Implicit DOM ordering, use <g> groups & appendChild to move an item to the end of its parent
Canvas: Change your redraw logic order, build a scene graph
SVG: Use CSS tricks
control surface sub-widgets with 'display:none' but a CSS hover rule on the parent to make them visible
tweak styles per agent/mode by adding classes to body or html tag
Don't be afraid to overlay HTML with absolute positioning
Rich tooltips with markup, hover-cards with HTML controls, in-place edit etc
Fighting the SVG DOM / redraw-loop / events? » Canvas
Writing Canvas scene graphs / hit detection / sprite libraries? » SVG
Good bits
What features make life easy
Composition of compound elements (defs; symbol and use; groups; image; svg fragments)
Built in animation (if that's what you need)
CSS3 including "CSS animation" (hover effects, transitions)
Selectors can include the entire DOM parent chain
HTML5 integration (eg drag-drop abilities on individual shapes)
Implicit z-layer based on DOM order (no explicit control)
Rich set of primitives
Viewport defining fragments with svg tag
Arbitrary chainable transformations
Interaction support with items / sprites
Control over mouse cursor and pointer events per structure
Working group for Canvas working on Hit Regions & more
Inherent support for beziers, gradients, filters, markers, linestyles etc
Memory use seems quite good (anecdotal)
Static performance speed is excellent
Dynamic performance is good for some cases
Bad bits or missing bits
What should I be careful of
<symbol> and <use> too concrete (no parameterisation)
Control over "ghost" tree for <use> not widely supported
Keyboard and focus support (not an InputElement - focus determined by selecting <text>)
Performance as number of DOM changes increases (but improving)
No 'export to PNG' or similar (cf toDataURL() of canvas)
No image introspection (getPixel()) so you can't examine clipping/collision results
<image> doesn't have the naturalWidth / naturalHeight properties of <img>
Not as "new" as Canvas and so not so trendy (HTML5 buzz )
Terminology annoyances especially with CSS muscle memory
<image> not <img>
stroke & fill not color & background-color
Positioning coordinates and sizes by attributes, not styles
Position containership done by tagname, not style
Units must be specified for lengths etc
Hard/ugly bits
What will be frustrating
Values can be awkward (eg need for expressing units on lengths, esp in CSS)
Built in animation makes scripting wordy (".baseVal.value" etc) event if you don't use it
Embedding in HTML had a history of being hit-and-miss (but much better with HTML5)
Text support superb except all markup has to be done by hand (and remember, no .innerHTML shortcut)
Patchy support for foreignObject (HTML in SVG) extensibility
Limited introspection, and getBBox() doesn't return valid results until after items are rendered and visible
Browser bugs (eg text kerning , repaint logic )
suspendRedraw() and resumeRedraw() are no-ops in most (all?) browsers
Native support within Javascript libraries/frameworks lacking, & SVG libraries tend to be specialised
Complexity: when you're mixing declarative models, viewports, transformation chains, animation,
scripting, CSS cascades, shims for your DOM wrappers etc etc, then pinning down what's wrong
can be hard (Chrome helps - DOM breakpoints etc)
Flash's advantage with browser limitations
Keyboard and mouse control (different browsers own different resources, certain keys, mouse buttons)
Clipboard and local file support
Camera and microphone access
Libraries / wrappers
Making life easier
svgweb, raphaeljs, dojo, mootools, and more...
offer support for IE via VML (and/or Flash emulation of SVG)
bugfixes per platform
abstract some of the API details
higher level functionality
specialist graphing (bar charts, node graphs etc) libraries
processing.js is a js port of a visualisation DSL that uses SVG
d3 for data driven tranformations of data to both HTML and SVG
Personal Recommendations
Some basic guidance
Use SVG for:
Complex static images
Transforms (pan, rotate, zoom, filters) of individual items and overall pictures
Complex sprites with sub-region behaviours
UI mouse interaction with rich shapes, nesting rules, transformations
CSS and DOM integration of visuals
Use Canvas for:
Lots of simple animated objects
Pixel level drawing (heatmaps, mouse trails)
Limited UI interaction with individual items
Complex compositing (multiple canvas tags to build multiple images)
Export as PNG
Hybrids
Possibilities of hybrid solutions?
Best of all worlds, or increased complexity?
SVG / HTML hybrid
SVG with HTML overlays for rich tooltips, hover cards, in-place edits
SVG over HTML for transformations & filters (patchy.. coming soon?)
Applying SVG effects to HTML via CSS styles
SVG / Canvas hybrids
Canvas to make fixed PNGs to speed up/simplify SVG
Canvas within SVG using <foreignObject> or inline with data://
c.f. owner-draw controls
References
Forget the reference tomes, where's the meat
Standards at W3C
SVG "support groups" are still active but seem largely frozen in time
SVG Open conference 2009/2010 papers http://svgopen.org
http://www.borismus.com/canvas-vs-svg-performance/
http://people.mozilla.com/~vladimir/xtech2006/
http://skillsmatter.com/podcast/ajax-ria/native-vector-graphics
event loops: http://lazutkin.com/blog/2008/mar/23/javascript-edp-and-0ms-timeouts/
svg vs canvas in practice: https://www.svgopen.org/2009/papers/54-SVG_vs_Canvas_on_Trivial_Drawing_Application/