Over the past few weeks my blog posts have been exploring different animation options available in modern browsers. First, I looked at using CSS, and then jQuery. In this article I want to take a look at a third option, Canvas, and talk about some of the advantages and limitations of working with this part of the HTML5 specification.
What is Canvas?
Canvas part of a series of expansions to the HTML language known as HTML5. Specifically, the
<canvas> tag is an element that lets you identify a drawable bitmap region within an HTML5 page.
The canvas element is known as an immediate mode drawing element, which means as soon as you execute Canvas drawing commands, they get converted into pixels and will no longer be accessible as objects. This is wildly different than drawing with other methods like CSS, jQuery, SVG, or Flash where what you draw and animate remain accessible as vector objects. It’s one of the main weaknesses of working with Canvas.
That being said, what you lose in convenience you gain in speed, as drawing with Canvas is way faster than drawing any other way. This is because Canvas doesn’t need to keep track of objects created like other methods do. So it’s ideal for game development, and other drawing tasks where performance is critical.
The immediate drawing mode also has some less-than-ideal side effects when it comes to animation. For instance, when you want to animate an object, you don’t simply tell that object to move to a new location. You have to draw every element in the canvas, including the object you want to move at new coordinates. It’s up to you to keep track of the objects because having no saved objects also means you don’t have a list of display objects when you work with Canvas. Thankfully, there are some cool libraries like CreateJS that help overcome some of the weaknesses associated with Canvas.
Drawing with Canvas
Let’s take a closer look at Canvas drawing with a simple example. If your browser has a problem displaying the example below, try viewing it with this direct link.
The HTML of a Canvas drawing is pretty simple. In the body of our document, there’s only one element—the
<canvas> tag creates a completely transparent inline element. If you want to see it, you’ll need to style it with some CSS. In our CSS above, we simply type in a background color for our body and our canvas. Since I want to center the
<canvas> element, I need to change the display type from inline to block. Finally, to center the canvas on our window, we use a margin of 0 (top and bottom) and auto so the element centers horizontally.
Now that our canvas tag is set up and we can see it in the browser, all the HTML and CSS you’ll need is written.
context = mycanvas.getContext("2d");
This specification tells the browser that we want to draw into mycanvas with 2D methods. Now we can simply execute any of the 2D drawing commands. In our example below, I’ve added some extra variables so I can keep track of the object’s size as well as the center of the canvas and the rotation property of the object. Altogether our variable definitions look like this:
var canvas = document.getElementById("htmlcanvas"), context = canvas.getContext("2d"), SIZE = 100, centerX = canvas.width/2, centerY = canvas.height/2, rotation = 0;
If you want to draw a rectangle into your canvas, you will need to specify a fillStyle with the fillStyle property:
context.fillStyle = "rgb(162, 216, 255)";
You can also specify a color using CSS-compatible notation, so elements like an RGB color, as seen in the example above, will work just as well as a hex #F00, or a color name like blue. Once you have a color designated, you can use one of the canvas 2D primitives to draw something. Here’s an example:
context.fillRect(0, 0, SIZE, SIZE);
Canvas tough primitives
Canvas has very few graphic primitives, or in layperson terms, ways to draw simple shapes. You can draw lines, rectangles, arcs, and curves, but there’s not a lot of variety and arcs and curves can be pretty complicated. Let’s say you wanted to draw the outline of a circle. There is no circle method, so you would use an arc with the following code:
That’s enough to scare a lot of people away from Canvas because drawing simple shapes like circles involves converting the starting and ending points of the arc from radians to degrees, and specifying the X and Y positions, a radius, the starting and ending point of the arc, plus the direction of the curve, which has a scary boolean parameter called anticlockwise.
If drawing primitives with Canvas is scary, transformations like rotations can be downright terrifying. That’s because transformations in Canvas affect the entire context. In other words, you can’t normally rotate individual objects (remember—there are no objects in Canvas, just pixels), you have to rotate everything. If you want to rotate an object, you have to first save the way the canvas looks (it’s called saving the context), rotate, then restore the context to its original state. Here’s what that looks like:
If we don’t save and restore the context, Canvas draws all objects with the same rotation, and all objects after the original transformation will be drawn at the same rotation as well. Additional transformations would compound the problem.
When you animate you’re essentially drawing every object on the canvas over and over again, and you have to keep track of all the objects and their movements yourself. Here’s a simple example of a rectangle animating:
This doesn’t seem too bad until you have to keep track of a ton of elements. In that case you’ll probably have to create classes, methods, and properties to keep track of the objects dancing across the screen.
Canvas with rainbows and kittens
Animating with Canvas is great for creating games, but it’s definitely tough to work with. That’s why there are so many libraries that simplify this process. If you come from the Flash gaming arena like me, you need to check out a library like EaselJS, which is part of the CreateJS library of products that Adobe acquired. It makes drawing in Canvas more approachable by creating a display list and adding a bunch of methods for drawing primitives and animating objects, which makes the process more like working with Adobe Flash. Check out my course EaselJS First Look to get started.