HTML5: Developing Rich Media Applications using Canvas

Exclusive offer: get 50% off this eBook here
HTML5 Multimedia Development Cookbook

HTML5 Multimedia Development Cookbook — Save 50%

Recipes for practical, real-world HTML5 multimedia driven development.

$23.99    $12.00
by Dale Cruse | May 2011 | Web Development

Putting an image on a website is so easy we take it for granted now. Through code, you simply tell the browser to display an image and, it's done. All that seems like child's play. Currently, some browsers can actually create dynamic images on the fly using the new canvas element.

In this article by Dale Cruse, author of HTML5 Multimedia Development Cookbook, we will cover:

  • Setting up the canvas environment
  • Understanding the 2d rendering context
  • Processing shapes dynamically
  • Drawing borders for images using canvas
  • Creating interactive visualizations
  • Bouncing a ball

 

HTML5 Multimedia Development Cookbook

HTML5 Multimedia Development Cookbook

Recipes for practical, real-world HTML5 multimedia driven development.

        Read more about this book      

(For more resources on Multimedia development, see here.)

The cool thing with the new open-source canvas element is that not only can you create dynamic images on the fly, but the users' actions can create new images in real time as well—all without requiring a plugin. Sounds great, right? In many ways it is, but it also leaves our friends using assistive technologies out in the cold.

What will happen if you're using a browser that doesn't support the new canvas element? Pretty much nothing. The browser just won't display it. That's why you'll need to be especially careful with this technology and not place anything inside the new canvas element on which your site or application absolutely depends. You must also consider fallback content.

Browsers that support canvas include:

HTML5 Multimedia Development Cookbook

Before proceeding with developing with the new canvas element, make sure you have a good foundation of skills with HTML and JavaScript. Being comfortable with object-oriented programming sure wouldn't hurt either.

Now, let's get cooking!

 

Setting up the canvas environment

Creating the new canvas element is easy.

How to do it...

Check out how simple this is:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

How it works...

Of course, we can use whatever height and width dimensions we need, but that simple set of tags is what we need to start.

You're probably thinking we could use CSS to control the height and width, but resist that temptation. Because the new canvas element contains a 2d rendering context, that approach can cause unpredictable behavior.

There's more...

Next, we'll call the new canvas element JavaScript API while calling jQuery:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

He's smart

"Let me make one thing completely clear: When you use canvas, you're not drawing on the canvas element itself. Instead, you're actually drawing on the 2d rendering context, which you're accessing through the canvas element via the JavaScript API." – Rob Hawkes

What am I sayin'?

Apple first introduced the new canvas element for the OSX Dashboard years ago. It was later implemented in web browsers Safari and then Chrome, with other browsers following suit. Since then it's become an official part of the HTML5 specification.

What's next for <canvas>?

Right now, we're barely scratching the surface of what the new canvas element can do. Now and in the future we'll use it to create animations, charts, diagrams, drawing apps, graphs, and user interfaces. What will you dream up?

See also

Developer Martin Angelov penned a great how-to guide titled, "An HTML5 Slideshow w/Canvas & jQuery" for Tutorial Zine at: http://tutorialzine.com/2010/09/html5-canvas-slideshow-jquery. In it, Martin demonstrates how to combine the new canvas element with jQuery, the most popular JavaScript framework, to create an intensely interactive image slideshow.

 

Understanding the 2d rendering context

It's important to understand that the new canvas element is really a "surface" on which to draw bitmapped images in the browser.

How to do it...

Defining a canvas tag like this only tells half the story:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

How it works...

By itself that HTML5 code does nothing. We have to use JavaScript to make the Document Object Model retrieve the 2d rendering context in order to get something to happen:

<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
});
</script>

To be fair, that bit of JavaScript won't do anything without the canvas tag in the HTML either.

There's more...

You may be wondering about the name. If there's a 2d rendering context, isn't there probably a 3d rendering context too? The short answer is yes. But the more detailed answer isn't so simple.

While a 3d rendering context does exists in theory, at the time of this publication no browser supports it. So if the new canvas element renders in 3d but nobody sees it, did it really do anything?

You can master <canvas>

The 2d context uses a number of different drawing contexts for the new canvas element that use syntaxes that should look quite familiar if you're experienced with CSS and JavaScript.

X, meet Y

When drawing, remember the X and Y axis in the top left corner of your browser window. Values increase going down the page.

Respect my authority!

The World Wide Web Consortium's HTML5 Canvas 2d Context specification is online at: http://dev.w3.org/html5/2dcontext. There we can dig even deeper into information like conformance requirements, the canvas state, transformations, compositing, colors and styles, line styles, shadows, simple shapes, complex shapes, focus management, text, images, pixel manipulation, drawing model, examples, and more.

 

Processing shapes dynamically

Let's look at the JavaScript functions that allow the new canvas element to draw rectangles.

How to do it...

fillRect(x,y,width,height)
strokeRect(x,y,width,height)

In order:

fillRect(x,y,width,height)

draws a filled rectangle. Next,

strokeRect(x,y,width,height)

draws an outline around the rectangle.

Now, let's draw some shapes.

How it works...

We'll start with our basic canvas code and incorporate our new functions:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(10, 10, 396, 236);
ctx.fillStyle = "red";
ctx.fillRect(11, 11, 100, 100);
ctx.fillStyle = "white";
ctx.fillRect(111, 11, 34, 100);
ctx.fillStyle = "red";
ctx.fillRect(156, 11, 249, 100);

ctx.fillStyle = "white";
ctx.fillRect(11, 111, 394, 34);

ctx.fillStyle = "red";
ctx.fillRect(11, 145, 100, 100);
ctx.fillStyle = "white";
ctx.fillRect(111, 145, 34, 100);
ctx.fillStyle = "red";
ctx.fillRect(156, 145, 249, 100);
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="416" height="256">
<p>Flag of Denmark</p>
</canvas>
</body>
</html>

What we've created resembles the flag of Denmark!

HTML5 Multimedia Development Cookbook

There's more...

This example may not seem overwhelming at first, but when you remember that we've created an image with hardly any HTML and no CSS whatsoever, the new canvas element starts to look pretty impressive.

Any way you want it

Note that while we used color names ("white" and "red") we could also use hexadecimal values or RGB or even HSL! Use whatever makes the most sense for you and your interactive project.

Similar to tables?

Think of the color and size specifications for this example almost as the old-school tables we used to build back in the day for layout. While certainly not the same, there are definitely similarities to that technique in this case.

Be a square first

Mastering rectangles is the first canvas technique that's important to have under your belt after the ability to set up the element itself. Understanding the basics of this approach will help you grasp the fundamentals of the next few recipes.

 

Drawing borders for images using canvas

Let's take a closer look at the super simple method of drawing borders around images using the new canvas element.

How to do it...

First, we'll start with our basic canvas code and add one new line to draw a border:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

HTML5 Multimedia Development Cookbook

How it works...

That one line of JavaScript tells the browser to create a rectangle starting at 10 pixels from the left and 20 pixels from the top of the new canvas element. It draws the box 100 pixels square.

There's more...

That's nice, but if we want the border to be any other color than the default, we'll need to specify that:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "rgb(0, 128, 0)";
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

In this case we've used strokeStyle to specify an RGB color of pure green.

HTML5 Multimedia Development Cookbook

Style first

If you plan to style a border, you'll need to specify that before the border is drawn by the browser. If you specify that style afterward, the browser will simply ignore it.

Many color values work

The style attribute we just used was RGB, but the method also works with colors ("green", for example), hexadecimal values, HSL, and RGBA.

I like big borders and I cannot lie

If no border width is specified, the browser will automatically draw a one-pixel border. Here's how to change that:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.strokeStyle = "rgb(0, 128, 0)";
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

It's just this easy:

HTML5 Multimedia Development Cookbook

 

HTML5 Multimedia Development Cookbook Recipes for practical, real-world HTML5 multimedia driven development.
Published: May 2011
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

 

        Read more about this book      

(For more resources on Multimedia development, see here.)

Creating interactive visualizations

The team at Carbon Five had a daunting task: To create a physical diagram of their skills and interests. They may have started with a wall in their office, but quickly realized the new abilities the new canvas element brings to the table would allow interactivity and the ability to draw conclusions based on it. Here's how they did it at: http://carbonfive.github.com/html5-playground/interest-map/interest-map.html.

How to do it...

It will be very helpful to view the source code at: view-source: http://carbonfive.github.com/html5-playground/interest-map/interest-map.html while following along with this recipe.

The Carbon Five team reminds us that canvas is not officially part of the HTML5 spec by creating this interactive visualization using an HTML4.01 Transitional DOCTYPE.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

Here's a detailed look at some of what they're doing with JavaScript and the new canvas element. They start with some variables like the card style. Here, they do several things: set the background color, create a black border, the width of the card, and the values for a shadow around it.

var CARD_STYLE = {
fill:'rgb(240,240,240)',stroke:'rgb(0,0,0)',width:.05, shadow:{x:0,
y:4, blur:4, color:'rgba(0, 0, 0, 0.3)'} };

The next variable should look familiar to those who know CSS. Here, the card font weight, size, face, color, and more are set:

var CARD_FONT = {font:'bold 8pt Courier', color:'#555',
yoffset:10, height:14};

Next, they set several more variables related to margin, width, height, scale, radius, shadow, and more.

var MARGIN = [75,75,75,100], WIDTH = 1000-MARGIN[1]-MARGIN[3],
HEIGHT = 650-MARGIN[0]-MARGIN[2], CARD_SCALE=.75, CARD_RADIUS = 40,
TAG_RADIUS = 50, CACHE_RADIUS=70, CLEAR_RADIUS = 50,
ITERATIONS = 20, DEGREE = .5, CARD_SHADOW = 2, AXIS_ANIM=700;

Lastly, they set up variables for skills, people, and a people-to-skill matrix. Unfortunately, these code chunks too long for republication here.

How it works...

Variables by themselves don't do a whole lot of good unless they have functions to act upon them.

After initializing the display, the Carbon Five team uses more functions like drawing on the 2d canvas rendering element:

function draw(t) {
var ctx = el('display').getContext('2d');
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.save(); ctx.globalAlpha = 1 - .75*arrow_visibility;
each( cards, function(card) {
var t0=card.tween(t); x = MARGIN[3] + card.lx +
(card.x-card.lx)*t0, y = MARGIN[0] + card.ly +
(card.y-card.ly)*t0;
draw_card( ctx, x, y, card.index);
});
ctx.restore();
if ( arrow_visibility > 0 ) {
ctx.save(); ctx.globalAlpha = arrow_visibility;
each( PEOPLE, function(p) { draw_interest_arrow(ctx,p,t); });
ctx.restore();
if (over_person) draw_over_arrow(ctx,over_person,t);
}
draw_axes(ctx);
}

as well as creating the name tags:

function nametag( ctx, cardx, cardy, person, r, interest ) {
ctx.save(); ctx.translate( cardx, cardy );
ctx.rotate( r + .4*(Math.random()-.5) );
ctx.translate( -TAG_RADIUS - + 4*Math.random(), 0 );
ctx.rotate( -r );
draw_nametag( ctx, person, interest );
ctx.restore();
}

and drawing the arrows:

function draw_arrow( ctx, length, head_length, head_width ) {
var cx1 = .9*(length - head_length), cy1 = .2*head_width,
cx2 = (length - head_length), cy2=.2*head_width;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.bezierCurveTo( cx1, cy1, cx2, cy2, length-head_length,
head_width );
ctx.lineTo( length, 0 ); ctx.lineTo( length-head_length,
-head_width );
ctx.bezierCurveTo( cx2, -cy2, cx1, -cy1, 0, 0 );
ctx.closePath();
}

There's more...

With variables and functions already set, the last thing to do is call the canvas element itself in the HTML to give it all a space in which to run:

<canvas id="display" width="1000" height="650"></canvas>

Evil of two lessors

In the old days of the web, the Carbon Five team would have had the choice of leaving their map on a physical wall or creating a static graphic image of it for computer display. While either might render just as well as using the new canvas element, neither of them allow the team to extract valuable information the way the new canvas element does.

What about fallback content?

Interestingly, Carbon Five used no fallback content within the new canvas element in this instance. This is an approach you'll have to weigh carefully, as those with older browsers or who use assistive technologies will see nothing, literally nothing. Carbon Five gets away with that for this internal project. Can you?

Take him up on his offer.

When writing about the project at http://blog.carbonfive.com/2011/02/17/visualizing-skillsets-in-html5-canvas-part-1 Carbon Five developer Alex Cruikshank went so far as to offer to create visualization maps to the first five people who wrote in with data in a reasonable format. As of publication date, it's unclear if anyone's taken him up on it.

See also

Jacob Seidelin hit another home run with his new canvas element visualization of the band Radiohead's song "Idioteque" from the album "Kid A" at: http://nihilogic.dk/labs/canvas_music_visualization. Jacob's pushing the limits of what can be done with the canvas element and JavaScript – and that's why we think he's terrific!

 

Bouncing a ball

We've looked at how do draw shapes using the new canvas element, and next we'll turn our attention to making those shapes move. Author Vinci Rufus shows us how.

How to do it...

We'll start with our usual canvas HTML code:

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

Next up is the unique part: the JavaScript. Here, Vinci chose a slightly different method of calling the 2d canvas rendering context than we did, but his method works just fine too. Check it out:

<script>
var context;
function init()
{
context= myCanvas.getContext('2d');
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100,
100 on the canvas
context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();
}
</script>

Put together, that code should look like. Note the addition of an onLoad function added to the body tag.

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
var context;
function init()
{
context= myCanvas.getContext('2d');
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100,
100 on the canvas
context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();
}
</script>
</head>
<body onLoad="init();">
<canvas id="myCanvas" width="300" height="300">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>

And render this blue ball:

HTML5 Multimedia Development Cookbook

How it works...

So far Vinci's code is pretty straightforward. We saw how he called the 2d canvas rendering context. He sets the color of the fill next

context.fillStyle="#0000ff";

And then draws an arc 100 pixels from the top and left and fills it with the blue he already set:

context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();

But now all we've got is a blue ball just sitting there. Next, Vinci shows us how to make it move using variables and a new function named draw.

There's more...

<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script
src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="http://ajax.googleapis.com/ajax/libs/jquery/1/
jquery.min.js"></script>
<script>
var context;
var x=100;
var y=200;
var dx=5;
var dy=5;

function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100,
100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
x+=dx;
y+=dy;
}
</script>
</head>
<body onLoad="init();">
<canvas id="myCanvas" width="300" height="300" >
</canvas>
</body>
</html>

HTML5 Multimedia Development Cookbook

As you can see, the ball is in motion but has simply drawn a straight line off the edge of the canvas. Vinci explains why:

"This is because each time the draw() function is called, it draws a circle at the new coordinates without removing the old ones. That's how the getContext object works so it's not a bug; it doesn't really move the circle and, instead, it draws a circle at the new coordinates each time the function is called."

Start again

Vinci shows us a method to erase the old circles as the new canvas element draws each new one:

<script>
var context;
var x=100;
var y=200;
var dx=5;
var dy=5;
function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.clearRect(0,0, 300,300);
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100,
100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
x+=dx;
y+=dy;
}
</script>

Now, the ball appears to fall down to the right outside of the canvas border.

Don't box me in

To ensure that the ball stays within the border of the canvas, Vinci wrote some logic to check if the x and y coordinates are beyond the canvas dimensions. If they are, he makes the ball reverse directions.

<script>
var context;
var x=100;
var y=200;
var dx=5;
var dy=5;
function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.clearRect(0,0, 300,300);
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100,
100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
// Boundary Logic
if( x<0 || x>300) dx=-dx;
if( y<0 || y>300) dy=-dy;
x+=dx;
y+=dy;
}
</script>

Now the ball should be bouncing around all four sides of the canvas continually.

HTML5 Multimedia Development Cookbook

And that's one to grow on

As Vinci reminds us in his compelling tutorial at http://sixrevisions.com/html/bouncing-a-ball-around-with-html5-and-javascript, the bouncing ball may seem simple at first, but it's actually a key technique to understand in order to develop just about any game for the new HTML5 canvas element.

See also

A beautiful example of user-generated graphics can be seen at Yuri Vishnevsky's http://weavesilk.com. The site uses the new canvas element as part of an experiment in generative art. Some of the generated images are so beautiful, Yuri has made them available as stunning desktop background images. A version for iPhone and iPad is planned also.

Summary

In this article, we took a look at real-life examples of setting up the canvas environment, understanding the 2d rendering context, processing shapes dynamically, drawing borders for images using canvas, creating interactive visualizations, and bouncing a ball.


Further resources on this subject:


HTML5 Multimedia Development Cookbook Recipes for practical, real-world HTML5 multimedia driven development.
Published: May 2011
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Dale Cruse

Since 1995, Boston-area web developer Dale Cruse has been publishing websites for high-profile clients ranging from the U.S. Army to Bloomingdale's. He has been a guest lecturer at the Art Institute of New England & is currently pursuing speaking opportunities. Contact him at http://dalejcruse.com. He is also the author of the Champagne blog Drinks Are On Me at http://drinksareonme.net.

Books From Packt


MODx Web Development - Second Edition
MODx Web Development - Second Edition

Plone 3 Multimedia
Plone 3 Multimedia

Kentico CMS 5 Website Development: Beginner's Guide
Kentico CMS 5 Website Development: Beginner's Guide

Inkscape 0.48 Essentials for Web Designers
Inkscape 0.48 Essentials for Web Designers

Grok 1.0 Web Development
Grok 1.0 Web Development

Yii 1.1 Application Development Cookbook: RAW
Yii 1.1 Application Development Cookbook: RAW

Python 3 Web Development Beginner's Guide
Python 3 Web Development Beginner's Guide

Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
t
6
7
C
S
3
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software