New Adventures In HTML5: Part 1 (HTML5 Canvas)

As developers we love building cutting-edge web apps for state-of-the-art browsers. Those are, fortunately, nowadays used be a vast majority of users (around 95% of all users in our 10 most recent projects). So for our newest project, we decided focusing on new technologies like HTML5 Canvas and the File API, among others. In this two-part article, we want to share our experiences using these techniques while building the Facebook app “tele.ring Poster-Creator”. Since this is an article mainly about the tech involved, I will not go into detail about the many social aspects of the app.

Very recently we launched Poster-Creator, a Facebook tab app for Austrian telecommunications provider tele.ring, together with our friends at ambuzzador (they conceived the app, we did the technical implementation). While the function of the app is rather simple and straightforward, the implementation was quite challenging and technologically very interesting to us. Here’s a screenshot:

To give you an idea what the app does, here’s the typical flow through the application and a screenshot:

The user logs in using Facebook.

The user is shown a poster with a hole in it which is initially filled with his or her Facebook profile picture.

The user can now choose to load a different picture into the poster, or just keep the default one.

The user moves, rotates and scales the picture until it fits perfectly in the cutout.

The user adds text to the poster.

When the user is ready, the finished poster is uploaded to the server.

The user now has several options to share the poster.

If you are a web developer, you are probably already pondering how you would implement each of these steps. As always, there is a multitude of possible implementations and goals (e.g. broad browser support, performance, minimizing server load, minimizing client load, etc.). We decided that our main goal was to give the user the best possible experience when interacting with the app. During the main phase of the app’s flow (steps 2 through 5) it should not feel like a web site, but like a native app. Here is how each of the technologies used in this project helped us achieve this goal:

AJAX/XHR

You might think I am kidding, but I am not. It is 2012 now, and AJAX has been used on every web site I can think of for years, but that does not mean it has become any less important for creating good user experiences. It would be wrong to not include it in this list. On the other hand, all of you probably know what XHR does and how to use it properly, so I’ll move right on to …

<canvas>

The HTML5 Canvas tag and the associated API are among the most useful new browser technologies. Essentially, it provides you with a rectangular area (or “canvas”, if you will) of arbitrary size that you can draw on. If you have a background in Java, you are probably familiar with the Graphics class. Canvas is very similar to this: You can manipulate every single pixel on the canvas, enabling you to do things you could not achieve in HTML and CSS. If you wanted to do complex animations or games (2D or 3D), you previously had to use Flash, forcing the user to install the a plugin. Thanks to Canvas, modern browsers have all these capabilities out of the box. And don’t forget that <canvas> is still an HTML tag, which means that you can apply CSS to it (including 3D transformations!) while it is rendering.

Browser support is very good, even IE9 supports it. Performance is a whole different story: Especially when doing animations where every singe pixel is changed in every frame (e.g. when moving a “camera”) some browsers hit their limits. While Google Chrome performs exceptionally well, Firefox has issues with its garbage collector, causing stuttering in your animation every few seconds. In IE9, you don’t notice the garbage collection, but only because the performance is rather bad to begin with. If you are, on the other hand, only redrawing the parts of the canvas that changed (like we do in the Poster-Creator), performance it very good across all browsers.

This snippet gets the drawing context of a Canvas element with the ID “my-canvas” an then draws a filled 42×42 box. It starts drawing 150 pixels from the left and 100 pixels from the top border of the canvas:

You can, of course, also draw other shapes, text or even complicated paths and Bezier curves. In our app, we draw multiple images onto the canvas, which is possible by using a JavaScript Image object as a source.

When doing animations, you would usually start every loop with the method clearRect() which simply deletes everything from a rectangular area of the canvas, allowing you to draw new content. If you don’t clear the canvas, you would draw every frame on top of one another, which normally is not what you want.

We briefly considered doing everything Canvas-related in this app in plain JavaScript, but since we wanted to use layers, events and transitions (all of which are not available in the Canvas API), we opted to use the Canvas framework KineticJS. Drawing with KineticJS works like this: You create shapes (like rectangles, images etc), add them to Layers and then add those to a Stage, like so:

Normally, when you draw shapes on a canvas, it immediately turns into pixels, which means that you cannot change it in any way after that, except by drawing on top of it. Using a Canvas framework removes this shortcoming: KineticJS shapes and layers can be changed at any time, and the framework redraws them automatically (if necessary). You can even change the order in which they are drawn (you can compare this to the z-index of an HTML element).

Another thing Canvas does not have is events for anything you draw. KineticJS adds this functionality. Let’s say we want the rectangle from the previous example turn blue when we hover over it:

rect.on("mouseover", function() {
this.setFill("blue");
});

As you might have noticed, the syntax for adding events in KinectJS is the same as in jQuery, further flattening the learning curve. Overall, working with KineticJS was a breeze, the only more complicated part being images: Due to security reasons, you can only get the pixel data out of a canvas if you only use images hosted on the same server. Of course, the users’ Facebook profile images are not hosted on our server, so we had to use a workaround: We wrote a very short (as in: 1 line of code) proxy that simply takes the URL of an image, downloads it and spits out the image data. The other slightly challenging part was the asynchronous nature of image loading. Thanks to the JavaScript Image object’s onload-callback, it isn’t really a problem at all:

One very handy feature of the Image object is that the src attribute does not have to be a regular URL, but can also be a data-URL! This enabled us to always use the same photo import method, no matter if the image was downloaded via URL or created using the File API. More about that later.

When the user is done creating his or her poster, we pull the image data from the canvas using KinectJS’s toDataURL() which is a method of the Stage object and behaves like the native JavaScript function of the same name. The data is then sent to the server where it is converted into an image and stored as a file on the file system, ready to be shared by the user.

That’s it for part one. In the next part we will be talking about the File API, native drag and drop events, and Local Storage. Do you want to receive regular updates on our blog-posts? Become a fan on Facebook!

Spread the ♥:

About Author

Patrick is a software developer at Die Socialisten. He is very passionate about JavaScript, HTML5, web standards and music. Some of his colleagues call him a hipster, but it's totally not his fault that he discovers everything before it gets big! Follow him on Twitter, Facebook or on Google+!