Rendering complex graphs or designs to the web has always been a challenge that has typically been solved by using images, server-side processes, or plug-ins such as Silverlight or Flash. Although drawing charts with straight lines has never been a problem (with the use of some creative CSS), rendering different types of shapes and colors natively in the browser—such as ellipses, Bézier curves, and other custom shapes—has always been a problem. With the addition of the HTML5 canvas tag, available in the latest version of all major browsers, you can now do a lot using only JavaScript and HTML tags. In this article I'll provide an introduction to the canvas tag and demonstrate some of the fundamental tasks you can perform using it.

The Canvas: What Is It, and Why Use It?

So what is the canvas tag? Put simply, it's a way to render pixels on the client side using JavaScript. This includes rendering text, images, shapes, linear and radial gradients, and more. Unlike Scalable Vector Graphics (SVG), which is vector based (and also available in many modern browsers now), the canvas is pixel-based. This makes it more challenging in scenarios where a user can zoom in or out since code has to be written to re-render pixels based upon a specific zoom level. However, the canvas performs very well, making it a good candidate for many types of complex rendering scenarios, such as graphs, charts, and games. The performance is especially good in Internet Explorer 9 (IE9) because of the hardware acceleration it provides. On the web you can find several great examples of using the canvas, such as Microsoft's www.beautyoftheweb.com site. Check out Mike Tompkins' excellent Firework musical demo (see Figure 1).

Figure 1: Putting the canvas into action with other HTML5 features such as audio and video

Before jumping into a discussion of using the canvas, let's take a moment to consider why you'd want to use it instead of using Silverlight, Flash, or server-side image generation processes. Determining when to use the canvas (or, in my mind. any HTML5 feature) comes down to the target audience.

For example, I'm a big fan of Silverlight in addition to web technologies. If I'm building a line of business (LOB) application that will be deployed on only Windows or Macintosh machines using in-browser or out-of-browser techniques, then I'll generally look to Silverlight first since it works very well in that scenario and brings a lot of power and productivity to the table. However, if I'm writing an application that will be released on the Internet or an intranet and may be used by different devices such as iPads or iPhones, Android phones and tablets, or others, then I'll pick standard web technologies. Every application is different and I don't believe that one size or technology fits all. Of course, you'll have to evaluate whether your target users have browsers that support the canvas tag and plan an alternative strategy if they don't. The canvas is definitely a new feature and not supported by many older browsers including pre-IE9 Internet Explorer versions.

Now let's get started with an overview of how to define and interact with the canvas.

Getting Started with the Canvas

Canvas functionality is available in the latest versions of the major browsers (IE9, Chrome, Safari, Firefox and Opera) and can be defined using the <canvas> tag, as shown in the following example:

<canvas id="canvas" width="800" height="600"></canvas>

Once a canvas is defined (or dynamically added) in HTML, you can interact with it using standard JavaScript. I generally prefer to use jQuery in any JavaScript-oriented page, but you can also use the standard document.getElementById() function to locate a canvas tag and then interact with it. The following code demonstrates how to locate a canvas tag defined in a page and get access to its 2D context for drawing:

<script type="text/javascript">
    window.onload = function () {
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext("2d");
    };
</script>

If you're using jQuery it would look something like the following:

<script type="text/javascript">
    $(document).ready(function () {
        var canvas = $('#canvas');
        var ctx = canvas[0].getContext("2d");
    });
</script>

Notice that once the canvas object is located, you must access its 2D drawing context. The W3C defines the 2D context: "The 2D context represents a flat Cartesian surface whose origin (0,0) is at the top left corner, with the coordinate space having x values increasing when going right, and y values increasing when going down."

You can think of the 2D context as the drawing surface that you'll programmatically interact with using JavaScript. Once you have a reference to the 2D context object, you can use methods such as lineTo(), fillText(), and fillRect() to perform drawing operations. Let's take a look at a few of the drawing features available.

Drawing Shapes, Lines, and Text

If you've ever used GDI+ (Graphics Device Interface) in the .NET framework (System.Drawing namespace), you'll feel right at home using the canvas since it's similar to GDI+ drawing in many ways. If you've never touched GDI+, then don't worry about it; it's simple to get started using the canvas once you know a few fundamentals. Drawing is accomplished by calling standard JavaScript functions that handle rendering lines, shapes, colors, styles, and more. Figure 2 shows several of the key functions you can use.

Function Description
Figure 2: Key canvas functions
arc() Used to render an arc by defining a center x/y coordinate, a radius, a starting angle and ending angle
beginPath() Signals the start of a new path
bezierCurveTo() Handles drawing a Bézier curve to the canvas
closePath() Signals the end of a path
createLinearGradient() Used to create a linear gradient with multiple gradient stops
drawImage() Used to render an Image object to the canvas
fill() Fills a shape such as a rect or arc
fillText() Renders text to the canvas
fillRect() Fills a rectangle with a defined color
lineTo() Draws a line from the current position to a defined x/y coordinate
moveTo() Moves the "pen" to a specific position on the drawing surface
stroke() Used to render a line

Let's look at a few things you can do with the canvas starting with rendering rectangles or squares. To draw rectangles or squares you can use the fillRect(topLeftCornerX,topLeftCornerY,width,height) function. It accepts the x/y coordinates of where to start the shape as well as its height and width. Figure 3 shows an example of defining a rectangle.

Figure 3: Rendering a rectangle using the fillRect() function
<script type="text/javascript">
    window.onload = function () {
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext("2d");

        //Render a rectangle
        ctx.fillStyle = 'Green';
        ctx.fillRect(0, 0, 200, 100)
   };
</script>

In this example, the 2D context has its fillStyle set to a color of Green. The square that's rendered by calling fillRect() will be displayed in the upper left of the screen (0,0 point) and have a width of 200 and a height of 100.

If you'd like to render an arc or circle, the arc() function can be used. It has the following signature:

arc(centerX,centerY,radius,startAngle,endAngle,antiClockwise);

The centerX and center Y parameters define where the middle of the ellipse will be, the radius defines the size of the ellipse, and the startAngle and endAngle parameters control the start and end points of the ellipse (note that the startAngle and endAngle parameters are defined using radians rather than degrees). The antiClockwise parameter will draw an arc (part of a circle) in an anticlockwise direction when set to true. Here's an example of using the arc() function:

//Render a circle
ctx.arc(100, 200, 50, 0, 2 * Math.PI, false);
ctx.fillStyle = 'Navy';
ctx.fill();

Passing a value of 0 and 2 * Math.PI for the start and end angle parameters will result in a complete circle being rendered. To render part of a circle, simply supply a different value for the startAngle or endAngle parameter, as shown next.

ctx.beginPath();
ctx.arc(100, 300, 50, 0, Math.PI, false);
ctx.fillStyle = 'Navy';
ctx.fill();

This example will result in 1/2 of a circle being rendered. Figure 4 shows the rectangle, circle and arc that are rendered to the canvas.

Figure 4: The results of rendering a rectangle, circle, and arc

It's important to note that a call to beginPath() was performed before the arc() function call so that each circle/arc shape stayed distinct and didn't merge into the following one as shown in Figure 5.

Figure 5: The result of two shapes combining as a result of not making a call to beingPath()

The beginPath() function tells the canvas to start rendering a new path, while fill() ends the path (you can also add a call to closePath() after each call to fill() if desired although it's not required in this case).

The final topic that I'll cover in this section is rendering lines. This is accomplished by using moveTo() and lineTo() along with the stroke() or fill() functions. The moveTo() function positions the virtual pen at a specific location which can then draw a line to a specific x/y coordinate by using lineTo(). Figure 6 shows an example of drawing lines.

Figure 6: Drawing lines and filling an area
ctx.beginPath();
ctx.moveTo(100, 400);
ctx.lineTo(50, 500);
ctx.lineTo(150, 500);
ctx.lineTo(100, 400);
ctx.strokeStyle = 'Red';
ctx.lineWidth = 4;
ctx.stroke();
ctx.fillStyle = 'Yellow';
ctx.fill();

The complete code for the shapes and lines rendered to this point is shown in Figure 7.

Figure 7: Rendering shapes and lines using the canvas
<!DOCTYPE>
<html>
<head>
    <title>Canvas Fundamentals</title>
    <script type="text/javascript">
        window.onload = function () {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext("2d");

            //Draw a rectangle
            ctx.fillStyle = 'Green';
            ctx.fillRect(0, 0, 200, 100);

            //Draw a circle
            ctx.arc(100, 200, 50, 0, 2 * Math.PI, false);
            ctx.fillStyle = 'Navy';
            ctx.fill();

            //Draw an arc
            ctx.beginPath();
            ctx.arc(100, 300, 50, 0, Math.PI, false);
            ctx.fillStyle = 'Navy';
            ctx.fill();

            //Draw lines
            ctx.beginPath();
            ctx.moveTo(100, 400);
            ctx.lineTo(50, 500);
            ctx.lineTo(150, 500);
            ctx.lineTo(100, 400);
            ctx.strokeStyle = 'Red';
            ctx.lineWidth = 3;
            ctx.stroke();
            ctx.fillStyle = 'Yellow';
            ctx.fill();
        };
    </script>
</head>
<body>
    <canvas id="canvas" width="800" height="600"></canvas>
</body>
</html>

There are certainly other types of shapes you can draw with the canvas, including Bézier and quadratic curves. They're useful when you need to draw nonstandard shapes or add rounded corners to something like a rectangle. The Mozilla canvas documentation provides an example of using lines and quadatric curves to render a rectangle with rounded corners (see Figure 8).

Figure 8: Drawing a rectangle with rounded corners
function roundedRect(ctx, x, y, width, height, radius) {
    ctx.beginPath();
    ctx.moveTo(x, y + radius);
    ctx.lineTo(x, y + height - radius);
    ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
    ctx.lineTo(x + width - radius, y + height);
    ctx.quadraticCurveTo(x + width, y + height, x + width,
      y + height - radius);
    ctx.lineTo(x + width, y + radius);
    ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
    ctx.lineTo(x + radius, y);
    ctx.quadraticCurveTo(x, y, x, y + radius);
    ctx.strokeStyle = 'Black';
    ctx.lineWidth = 10;
    ctx.stroke();
    ctx.fillStyle = 'Lime';
    ctx.fill();
}

The roundedRect() function can be called as shown here:

roundedRect(ctx, 250, 5, 150, 150, 15);

 This function will render the rectangle shown in Figure 9.

Figure 9: Using lineTo() and quadraticCurveTo() to draw a rounded rectangle

The final topic that I'll cover is text rendering. Although rendering shapes can be good for charts and a variety of other tasks, at some point you'll want to render text to a canvas. Fortunately, that's an easy proposition and something that's also quite flexible since the canvas supports different types of transforms as well (e.g., scaling and rotating objects). To render text to the canvas, you can use the fillText() method, which accepts the text to add as well as the x and y coordinates of where to add it. The following is an example of using fillText().

ctx.fillStyle = 'Black';
ctx.font = '30pt Arial';
ctx.fillText('Drawing with the Canvas', 0, 550);

Canvas Tools—and More to Come

Although I've only scratched the surface of what can be done with the canvas, at this point you can see that using it to perform basic drawing functions is pretty straightforward (and much like GDI+ if you've worked with that). Using the canvas definitely involves a fair amount of JavaScript, though. You may wonder (as I did) if there isn't an easier way to render shapes, especially given that you have to figure out the coordinates yourself. Although the tooling story for the canvas isn't great quite yet, there are plug-ins for tools such as Adobe Illustrator that can be used to export shapes and even animations to JavaScript. One example is Ai->Canvas. A project that provides a library of shapes and other samples for the canvas can be found at code.google.com/p/html5-canvas-graphics/.

In "HTML5 Tutorial: Build a Chart with JavaScript and the HTML5 Canvas," I'll provide additional examples of using the canvas to generate more useful graphics that can be displayed in a web application. Figure 10 shows an example of the types of topics that I'll cover to help teach canvas features.

Figure 10: Building a chart using the HTML5 canvas