Writing a Prezi clone with HTML5, SVG, and Javascript

The idea

The other day, I took it upon myself to write a browser-based Prezi-like app without using flash. Condition: It should run purely client-side.

It was also an experiment in evaluating whether the current APIs available in modern browsers are enough to handle the task. What follows is an account of what works, what doesn’t, and what could be done better.

SVG vs Canvas

When you’re building a rich graphics-intensive app like Prezi, you usually have two ways of rendering content: SVG and Canvas.

1. SVG provides a neat DOM that can be manipulated with existing DOM handling javascript libraries, such as jQuery. Canvas, on the other hand, is just a bitmap buffer. This means that you have to program your own DOM-like scene graph if you wish to use Canvas for handling presentation elements. Libraries for this already exist – most notably, fabric.js, but none are as convenient to use as a real DOM. SVG wins here.

2. Canvas is just a dumb bitmap buffer. Animating it is faster than animating SVG with Javascript, but it isn’t accessible. You can’t select text with the mouse. You can’t embed rich content. SVG wins in this regard; you can even embed YouTube videos and forms and such.

3. SVG is not implemented as completely or identically across different browsers as Canvas is. The worst offender here is, of course, IE9 (a lack of SMIL animation support, among other things). Text rendering looks noticeably different in every browser. This can be mitigated somewhat by not allowing the browser to use default fonts, but using custom webfonts like Google’s toolkit. The rest of the rendering should look fine if you stay away from edge cases (literally) such as not drawing objects outside the main SVG canvas, for example:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100" height="100">
<rect x="10" y="10" width="50" height="80" rx="-10" ry="-10" fill="red"/>
</svg>

Difference between SVG rendering across browsers (source)

4. SVG and Fonts are not friends. Everything is supposed to be vectorized, but fonts aren’t handled that way. If you notice the animations in the example linked to near the end of this post, you’ll see that during zooming, the fonts ‘shake’ when resizing, because they don’t scale smoothly as normal vector content. The only way to achieve smooth scaling is to convert the text to paths, but that defeats the purpose of text accessibility. There is an SVG Fonts spec, which aims to remedy this by having each font glyph rendered using SVG paths, which would mean real vector fonts which can be selected with the mouse and handled as normal text, plus identical rendering everywhere. Webkit and Opera support this spec, but Mozilla and IE have outright refused to implement it, with the explanation being that WOFF is a ‘superior alternative’ or ‘enough’. This is quite wrong and their arguments are not satisfactory. WOFF is not vector content, and therefore can’t be (and isn’t) rendered identically everywhere. Period.

Taking 1 and 2 as points in our favor, and tolerating and 4, I chose SVG to be the superior but not polished-enough alternative.

Animation

Next, we want to animate. We won’t use CSS3 animations (not supported well enough everywhere). SMIL animation is fast, but works only with non-IE browsers. Heck, we’ll just use plain old JavaScript. I’m using Sozi‘s javascript code for animating.

The Editor

We want to make an SVG editor, in which after designing the document, we can choose certain elements to be nodes in the presentation path, and then have the editor inject the JavaScript code required to animate the presentation.

As it turns out, SVG-edit is an open source, completely client-side SVG editor, and perfectly suited for the task at hand.

I decided to take it’s core and build on top of it, stripping out the unneeded parts and adding some more useful features.  It looks like this right now:

The editor. Incomplete, but it works.
And here’s a link to the presentation shown above.

Rendering the Timeline

The sidebar on the left is supposed to show a strip of ‘snapshots’ of nodes in the presentation path, such as what Prezi shows:

Prezi strip. Nice snapshots.

And here’s a similar sequence rendered in Awwation:

Awwation strip. Okay snapshots.

The strip is generated using a hack. Due to browser security policies, you cannot render an SVG as an HTML5 Image and crop a region out using Canvas. So I had to use canvg, a client-side javascript library that tries to read SVG and render it onto Canvas. The code then converts the Canvas context to an image and adds it to the strip. It doesn’t work perfectly – if there’s external content in the SVG, such as an xlink’d image, it won’t render and you’ll get blank snapshots. Apparently the only perfect way to render snapshots is to actually send the SVG to the server, use PhantomJS to rasterize it, and send it back to the browser. But this defeats the purpose of doing everything client-side, so that’s a no-go.

Theming

Disclaimer: I haven’t done this one yet.

Prezi has a presentation themes collection. This is where Awwation can totally beat Prezi, and here’s how: CSS themes. SVG can be easily styled using CSS. WOFF fonts can be embedded as dataURLs in the CSS code. Anyone can create CSS files for this and you could have a huge user-generated corpus of themes!

Collaborative Editing

SVG-edit has already been extended to have real-time collaborative editing features using the Google Wave protocol. So Awwation can get collaborative editing for free! (once I or someone gets around to integrate it).

Saving

Since we’re doing all the work client-side, we don’t want to send the created SVG to the server and then download it back to the client’s file system. We want it saved to disk right here. This would be the ‘normal’, convoluted way of doing it, but fortunately there is an implementation of the proposed HTML5 FileSaver API which allows us to save the file directly from the browser to disk. Unfortunately this works perfectly only on Chrome. With Opera/Firefox, you’ll have to save the generated file, rename it to .svg, and then view it in the browser.

Conclusion

This can be much more capable than Prezi in terms of accessibility and extensibility. Holding it back are security policies and inconsistencies across browsers, which will hopefully have workarounds in the future.

Finally, 

Here’s the project page for Awwation: http://adityab.github.com/Awwation/.

Here’s a link to a sample presentation using Webfonts to make it look consistent across browsers: http://dl.dropbox.com/u/40496552/awwation-intro.svg.

Warning: The presentation doesn’t work in newer versions of opera at the moment, here’s a relevant issue in Sozi.

PS: I was inspired to work on this idea from Calligra Stage’s similar project.

23 thoughts on “Writing a Prezi clone with HTML5, SVG, and Javascript

  1. cool. Thank you so MUCH!! I was looking for something like that since a very long time now. I will test it soon…

  2. Pingback: SVG Animator
  3. I am jealous! I’ve been a huge SVG fan and been wanting to build something very much like this since you were about 5 years old, but never found the time. Glad you did. Nice job! 🙂

  4. “WOFF is not vector content”

    Err… yes – yes it is.

    Just because the browser chooses to render it through a different path (the platform’s font rendering engine) doesn’t mean it’s not vector content. And they probably choose to render it through a different path because it means they themselves don’t have to handle the truetype-ish font format – they can just hand it off to the system’s font renderer without having to worry about its geometry. There’s no fundamental reason you can’t have identical, “perfect” looking fonts using WOFF.

    So that’s not really the impetus behind SVG fonts – they have other merits (which I can’t remember right now).

    1. Hmm, I see. I wasn’t entirely aware of that. Thanks!
      That said, browsers do offload them to the system’s renderer which messes up the geometry. So SVGFonts will help in this regard, right?

  5. All I can say is: wow, great work!

    SVG has gone a looong way since last time I touched it (2001 I believe), when it was slow and hardly working (needed plugin for IE back then). Someone just showed me prezi and it was so slow, I almost cried, and then it downed on me that it’s using Flash — a nogo for three distinct reasons: slow, nonstandard, and closed-source.

  6. > Due to browser security policies, you cannot render an SVG as an HTML5 Image and
    > crop a region out using Canvas.

    Yes you can. I’m not sure what problem you’re referring to here. SVG images are not allowed to refer to external resources, in Firefox at least, so embedded images etc need to be encoded as data: URIs (or Blob URIs).

    For fonts, maybe we should make font-rendering:geometricPrecision extract the glyph paths and render them directly.

    1. Interesting, I remember that rendering SVG to canvas would make it write-only. Now that you mention it, I see that this has changed in newer browsers (Firefox at least)! I do want to reference external content in the future – maybe a youtube video embed as a foreignObject – so not sure if this is possible. What do you think?

    1. Right now, the way I have ‘hidden frames’ is to use a transparent rectangle and then set it as a presentation node. I agree, a separate hidden frame tool should be added.

      About the ‘appear’ thing, that isn’t so much of a priority right now. I can see it’s usefulness though.

      No, I don’t make presentations for money. 🙂

  7. Cool demo! My only complaint is that you completely slaughter the back button functionality. I guess having everything client side prevents ajax + html5 history but it seems to me you are limiting yourself for no reason.

    Far better, imo, to do as much possible client-side but fall back to server-side when the client-side tech just isn’t ready.

    Great job overall though.

Leave a Comment