Setting Up the Canvas

To set up a canvas for drawing, you need to add a <canvas> tag to your HTML and assign a 2D drawing context to it. All your drawing operations are performed on the context.

Start by Adding a <canvas> Tag

In your HTML, include a line that defines the canvas element, giving it a width and height. Be sure to include a closing tag.

<canvas width="400" height="300">

</canvas>

If you don’t specify a width or height, the default width of 300 pixels and the default height of 150 pixels are used. The canvas is initially empty and transparent.

Specify the Fallback Behavior

Put any fallback behavior for older browsers between the opening and closing <canvas> tags.

<canvas height="300" width="400">
    <img src="fallback.jpg" />
</canvas>

HTML5-savvy browsers ignore everything between the opening and closing <canvas> tags. Browsers that don’t support the canvas element ignore the <canvas> tags and display the fallback content.

Create a Drawing Context

Using JavaScript, get the canvas element into an object and get a "2d" drawing context. You perform all drawing operations on the context. Currently, only a "2d" context is supported. The canvas specification is designed to support 3D drawing contexts, such as WebGL, in the future.

<html>
<head>
    <title>Simple Canvas</title>
    <script type="text/javascript">
        function init() {
            var can = document.getElementById("canvas");
            var ctx = can.getContext("2d");
        }
    </script>
</head>
<body onload="init()">
    <canvas id="can" height="300" width="400">
    </canvas>
</body>
</html>

Support Retina Displays From the Start

Enabling your canvas to appear crisp on Retina as well as standard-definition displays is as simple as multiplying your canvas instructions by a ratio determined by the screen’s pixel density. First, you need to understand how pixel values are stored in a canvas, and how iOS and OS X interpret these pixel values differently.

The backing store is where the canvas stores data for each pixel’s color value. Before the pixels are pushed to the screen, their values are computed here. However, the number of pixels represented in the backing store may not be equal to the number of pixels pushed to the screen. On Retina displays, the canvas doubles its width and height to maintain consistent size and position relative to other HTML elements, and as a result, it stretches and blurs its contents. To counteract this stretching, you need to double the width and height of the backing store when appropriate. The goal is to provide a pixel in the backing store for each display pixel rendered on the canvas.

Depending on the operating system, your canvas may already be optimized for Retina displays. OS X automatically doubles the size of the canvas’s backing store if the user is viewing a Retina display. Unless you are placing raw image or video data into your canvas, your canvas will automatically be enhanced for Retina-capable devices. If you are dealing with raster image or video data, find out how to further optimize your canvas for Retina displays in “Pixel Manipulation.”

Because memory is a more precious commodity on iOS, you need to opt in to optimize your canvas for Retina displays. First, determine whether the display presenting your canvas is indeed of Retina caliber. If it is, see whether the operating system automatically doubles the size of the backing store for you (otherwise you might enlarge a canvas that has already been doubled). If it doesn’t, you need to manually scale your backing store by 2. This workflow is best explained visually, as shown in the flowchart Figure 1-1.

Figure 1-1  When to manually scale the backing store of the canvas

You can determine the factor of the backing scale in JavaScript. First, see whether the browser visiting your web page has window.devicePixelRatio defined. If the device pixel ratio is greater than 1, the user is on a Retina display. Next, check that the operating system does not autodouble the backing store’s pixel values by asserting that its context.webkitBackingStorePixelRatio is less than 2. If the assertion passes, you must manually multiply your canvas pixel values by the device pixel ratio to make your canvas Retina-ready. The code for determining the appropriate backing scale is listed in Listing 1-1.

Listing 1-1  Determining a backing store multiplier

function backingScale(context) {
    if ('devicePixelRatio' in window) {
        if (window.devicePixelRatio > 1 && context.webkitBackingStorePixelRatio < 2) {
            return window.devicePixelRatio;
        }
    }
    return 1;
}

Multiply the width and height of your canvas by the backing scale determined by Listing 1-1. Drawing instructions that refer to points in the coordinate space must also be multiplied by this backing scale.

All Retina displays have a device pixel ratio of 2 because there is a 2:1 ratio of display pixels to backing store pixels in both the x and y direction. Standard-resolution displays, on the other hand, map one backing store pixel to one display pixel, so their device pixel ratio will always be 1.

For more information regarding how to present images on displays of all resolutions in Safari, read Safari Image Delivery Best Practices.

Save and Restore the Context

The context is, among other things, where you store settings such as line color, fill color, line thickness, rotation, and scaling.

To draw different elements in different colors or at different rotations, for example, you need to change the context settings.

Instead of setting and resetting large numbers of drawing parameters, it’s easier to save the current context with all its settings, then restore it as needed.

When you save a context, the settings are pushed onto a stack. When you restore a context, the settings are popped off the stack. Saving and restoring contexts is therefore a very fast operation, and is nestable.

You save the current context settings by calling the save() method on the context. Restore the previous settings by calling restore().

The following snippet saves the context, changes the rotation, calls a drawing operation, then restores the context.

ctx.save();
ctx.rotate(Math.PI);
drawSomething();
ctx.restore();

Did this document help you? Yes It's good, but... Not helpful...