David Geary introduces you to the magical canvas element in HTML5, which lets you do amazing things in a browser. You can implement image panning; an interactive magnifying glass; a paint application that runs in any self-respecting browser and that also runs on an iPad; several animations and games, including an industrial-strength pinball game; image filters; and many other web applications that in another era were almost entirely the realm of Flash.



In 1939, Metro-Goldwyn-Mayer Studios released a film that, according to the American Library of Congress, was destined to become the most watched film in history. The Wizard of Oz is the story of a young girl named Dorothy and her dog Toto, who are transported by a violent tornado from Kansas in the central United States to the magical land of Oz.

The film begins in Kansas and is shot in a bland and dreary black-and-white. When Dorothy and Toto arrive in the land of Oz however, the film bursts into vibrant color, and the adventure begins.

For more than a decade, software developers have been implementing bland and dreary web applications that do little more than present bored-to-death users with a seemingly unending sequence of banal forms. Finally, HTML5 lets developers implement exciting desktop-like applications that run in the browser.

In this HTML5 land of Oz, we will use the magical canvas element to do amazing things in a browser. We will implement image panning, as shown in Figure 1.1; an interactive magnifying glass; a paint application that runs in any self-respecting browser and that also runs on an iPad; several animations and games, including an industrial-strength pinball game; image filters; and many other web applications that in another era were almost entirely the realm of Flash.

Figure 1.1. Canvas offers a powerful graphics API

Let’s get started.

1.1. The canvas Element

The canvas element is arguably the single most powerful HTML5 element, although, as you’ll see shortly, its real power lies in the Canvas context, which you obtain from the canvas element itself. Figure 1.2 shows a simple use of the canvas element and its associated context.

The application shown in Figure 1.2 simply displays a string, approximately centered in the canvas itself. The HTML for that application is shown in Example 1.1.

The HTML in Example 1.1 uses a canvas element and specifies an identifier for the element and the element’s width and height. Notice the text in the body of the canvas element. That text is known as the fallback content, which the browser displays only if it does not support the canvas element.

Besides those two elements, the HTML in Example 1.1 uses CSS to set the application’s background color and some attributes for the canvas element itself. By default, a canvas element’s background color matches the background color of its parent element, so the CSS sets the canvas element’s background color to opaque white to set it apart from the application’s light gray background.

The HTML is straightforward and not very interesting. As is typically the case for Canvas-based applications, the interesting part of the application is its JavaScript. The JavaScript code for the application shown in Figure 1.2 is listed in Example 1.2.

Example 1.1. example.html

<!DOCTYPE html > <html> <head> <title> A Simple Canvas Example </title> <style> body { background: #dddddd ; } #canvas { margin: 10px ; padding: 10px ; background: #ffffff ; border: thin inset #aaaaaa ; } </style> </head> <body> <canvas id = 'canvas' width = '600' height = '300' > Canvas not supported </canvas> <script src = 'example.js' ></script> </body> </html>

Example 1.2. example.js

var canvas = document . getElementById ( 'canvas' ), context = canvas . getContext ( '2d' ); context . font = '38pt Arial' ; context . fillStyle = 'cornflowerblue' ; context . strokeStyle = 'blue' ; context . fillText ( 'Hello Canvas' , canvas . width / 2 - 150 , canvas . height / 2 + 15 ); context . strokeText ( 'Hello Canvas' , canvas . width / 2 - 150 , canvas . height / 2 + 15 );

The JavaScript in Example 1.2 employs a recipe that you will use in your Canvas-based applications:

Use document.getElementById() to get a reference to a canvas. Call getContext('2d') on the canvas to get the graphics context (note: the ‘d’ in ‘2d’ must be lowercase). Use the context to draw in the canvas.

After obtaining a reference to the canvas’s context, the JavaScript sets the context’s font , fillStyle , and strokeStyle attributes and fills and strokes the text that you see in Figure 1.2. The fillText() method fills the characters of the text using fillStyle , and strokeText() strokes the outline of the characters with strokeStyle . The fillStyle and strokeStyle attributes can be a CSS color, a gradient, or a pattern. We briefly discuss those attributes in Section 1.2.1, “The 2d Context,” on p. 9 and take a more in-depth look at both the attributes and methods in Chapter 2.

The fillText() and strokeText() methods both take three arguments: the text and an (x, y) location within the canvas to display the text. The JavaScript shown in Example 1.2 approximately centers the text with constant values, which is not a good general solution for centering text in a canvas. In Chapter 3, we will look at a better way to center text.

CAUTION: The suffix px is not valid for canvas width and height Although it’s widely permitted by browsers that support Canvas, the px suffix for the canvas width and height attributes is not technically allowed by the Canvas specification. The values for those attributes, according to the specification, can only be non-negative integers.

NOTE: The default canvas size is 300 × 150 screen pixels By default, the browser creates canvas elements with a width of 300 pixels and a height of 150 pixels. You can change the size of a canvas element by specifying the width and height attributes. You can also change the size of a canvas element with CSS attributes; however, as you will see in the next section, changing the width and height of a canvas element may have unwanted consequences.

1.1.1. Canvas Element Size vs. Drawing Surface Size

The application in the preceding section sets the size of the canvas element by setting the element’s width and height attributes. You can also use CSS to set the size of a canvas element, as shown in Example 1.3; however, using CSS to size a canvas element is not the same as setting the element’s width and height attributes.

Example 1.3. Setting element size and drawing surface size to different values

<!DOCTYPE html > <head> <title> Canvas element size: 600 x 300, Canvas drawing surface size: 300 x 150 </title> <style> body { background: #dddddd ; } #canvas { margin: 20px ; padding: 20px ; background: #ffffff ; border: thin inset #aaaaaa ; width: 600px ; height: 300px ; } </style> </head> <body> <canvas id = 'canvas' > Canvas not supported </canvas> <script src = 'example.js' ></script> </body> </html>

The difference between using CSS and setting canvas element attributes lies in the fact that a canvas actually has two sizes: the size of the element itself and the size of the element’s drawing surface.

When you set the element’s width and height attributes, you set both the element’s size and the size of the element’s drawing surface; however, when you use CSS to size a canvas element, you set only the element’s size and not the drawing surface.

By default, both the canvas element’s size and the size of its drawing surface is 300 screen pixels wide and 150 screen pixels high. In the listing shown in Example 1.3, which uses CSS to set the canvas element’s size, the size of the element is 600 pixels wide and 300 pixels high, but the size of the drawing surface remains unchanged at the default value of 300 pixels × 150 pixels.

And here is where things get interesting because when a canvas element’s size does not match the size of its drawing surface, the browser scales the drawing surface to fit the element. That effect is illustrated in Figure 1.3.

Figure 1.3. Top: element and coordinate system = 600 × 300; bottom: element = 600 × 300, coordinate system = 300 × 150

The application shown at the top of Figure 1.3 is the application that we discussed in the preceding section. It sets the canvas element’s size with the element’s width and height attributes, setting both the element’s size and the size of the drawing surface to 600 pixels × 300 pixels.

The application shown at the bottom of Figure 1.3 is the application whose HTML is shown in Example 1.3. That application is identical to the application in the preceding section, except that it uses CSS to size the canvas element (and has a different title in the window’s title bar).

Because the application shown in the bottom screenshot in Figure 1.3 uses CSS to size the canvas element and does not set the element’s width or height attributes, the browser scales the drawing surface from 300 pixels × 150 pixels to 600 pixels × 300 pixels.

CAUTION: The browser may automatically scale your canvas It’s a good idea to use the canvas element’s width and height attributes to size the element, instead of using CSS. If you use CSS to size the element without also specifying the width and height attributes of the canvas element, the element size will not match the canvas’s drawing surface size, and the browser will scale the latter to fit the former, most likely resulting in surprising and unwanted effects.

1.1.2. The Canvas API

The canvas element does not provide much of an API; in fact, that API offers only two attributes and three methods that are summarized in Table 1.1 and Table 1.2.

Table 1.1. canvas attributes

Attribute Description Type Allowed Values Default width The width of the canvas’s drawing surface. By default, the browser makes the canvas element the same size as its drawing surface; however, if you override the element size with CSS, then the browser will scale the drawing surface to fit the element. non-negative integer Any valid non-negative integer. You may add a plus sign or whitespace at the beginning, but technically, you cannot add a px suffix. 300 height The height of the canvas’s drawing surface. The browser may scale the drawing surface to fit the canvas element size. See the width attribute for more information. non-negative integer Any valid non-negative integer. You may add a plus sign or whitespace at the beginning, but technically, you cannot add a px suffix. 150

Table 1.2. canvas methods