Updated June, 4th 2013 following the SVG F2F meeting
I’ve been advocating for a while now for SVG to be treated as a first class citizen on the Web. One aspect where it’s still not the case, in my opinion, is in the handling of animated SVG. To me, it should be possible to view and stream animated graphics in the same way as a video, ie. you should be able to write:
<video controls width="640" height="480"> <source src="myAnimatedFile.svg" type='image/svg+xml' /> </video>
and be able to play, pause, seek in the SVG content just like you would in a video. So, I’ve started tweaking a JavaScript HTML 5 video player for that. I’ve used Video.js. The result is demonstrated below and the code on GitHub. It is still ongoing work but you should already be able to select a cartoon, play it, pause it, seek while playing or while paused. This post discusses below the results and problems I had.
Referencing SVG animations with the <video> element
Unfortunately, SVG content in the video element is not (yet?) supported natively by current browsers. The modification I made to Video.js actually reads the video tag and replaces it with a different element depending on some options.
Replacing the <video> element
Referencing SVG animations
My first idea was to replace, at rendering time, the video element with a suitable element where I could reference the SVG content, control its rendering (position, size, aspect ratio, fullscreen…) and access the SVG root element to control the playback (pause, play …). Ideally, it should be possible to reference the SVG animation coming from a different page, from a different origin (just like a video is referenced from an embedding page without restrictions). The <svg> element does not contain an src attribute for that, and the other referencing HTML/SVG elements all have problems, as detailed below:
- <iframe>: with frame.contentDocument it is possible to access the SVG root element and call the appropriate methods for playback control. However, this is not possible when the frame comes from a different origin.
- <object>. The problem is similar to the <iframe> case. Even specifying the typemustmatch attribute, Chrome doesn’t let me access the content of the remote SVG document from the referencing document (in my tests, a local file).
- <embed>, <img> or <foreignObject>. It is not possible to access the SVG root element of the referenced document.
In my modified Video.js player, I’ve used the iframe option as the default strategy.
Embedding SVG animations
A second idea was to try to replace the <video> element with the content of the SVG document. I tried using XHR to download the document. This would have the advantage that I would be able to control the download of the SVG, downloading only what is needed when seeking into the future of a large SVG cartoon. The idea was to monitor the SVG download with XHR progress events and triggering video-like progress events. I’ve also implemented that in the modified Video.js player, it is used when the ‘svgEmbed’ option is specified.
<video controls width="303" height="250" data-setup='{ "svgEmbed": true }'> <source src="cartoon.svg" type='image/svg+xml' /> </video>
This works quite well, but this approach still has a few problems. Unfortunately, XHR has the same origin restrictions as iframes. Then, the download algorithm is currently limited: the SVG file is downloaded as a whole, not chunked, so seeking into the file while the download is not finished is not yet possible. I plan on improving that in the future as I see more potential benefits.
Controlling SVG animations like a video
Animated SVG content can be controlled very similarly to a video. SVG defines different APIs for that: to get and set the current time in the document (allowing seek), to play/pause the animations… In the modified Video.js player, I use these APIs. They work quite well, except for some small details. For instance, when you pause a video and ask for the current time in a video (while paused), you will get the same time value. For SVG, you can pause the animations. That doesn’t pause the document timeline, so getCurrentTime will return a different value, as time flows.
Update: Apparently, this is a bug in Chrome. Should work in Firefox.
The other problem is that SVG does not define an API to change the playback speed. Finally, I had to extend the content to define a ‘duration’ attribute on the root SVG element.
Update: Should be fixed when SVG references Web Animations.
Next steps
In the future, I plan on testing SVG content as text tracks, ie. being able to write:
<video controls width="640" height="480"> <source src="file.mp4" type='video/mp4' /> <track src="annotations.svg" kind="captions"> </video>
and on rendering SVG streams.
I think this is an excellent idea. I might use this in my own research project.