Nov
14
2010

 

This is a general outline of how to utilize HTML5 Canvas to do animation using the traditional cell-animations, aka: image-strips.
Here’s the image that I am using for this example; as you can see, it consists of 8 frames of equal width. It’s an animation of someone walking, shows in a top-down view.

To draw each frame, we need to ‘slice’ this image and cycle through each frame. For this example, I am looping the animation infinitely. This tutorial only covers the basic, so if you are making other application such as games, you will need to write more code control the animation.

Below is how the animation in our example looks like (if you don’t the the animation, make sure that you are using a HTML5 compliant browser). Tested on Windows with the latest version of Chrome and Firefox (Internet Explorer 9 is not supported).

As always there are many ways to accomplish this. For instance, A) you can draw each frame on its own canvas or B) you can draw the image on the same canvas. Technique A) is useful if you are going to reuse the animation in several places. This is conceptually
more elegant (you can throw out the original image and works with just canvas) and it is faster in most cases. Technique B) requires less steps and requires less amount of memory. Another approach will be to scan the image to look for cell-borders — this requires the source image to have markers, such as below.

For this example, Technique B is used. The gist of the technique is to draw portion of the image using drawImage function of CanvasContext.

There are severeal versions of this function but we will be using this version because this version allows drawing only portion of a source image onto the canvas:

[c]
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
[/c]

More reference: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html

The prefix s indicates source and d indicates destination, so sx is the source x position, sy is the source y position.

sw and sh are short for sourceWidth and sourceHeight, or the dimensions of the portion of the image that you want to draw.

The parameters prefixed with “d” have the same meanings. Notice in this example that dw and dh will always be the same as sw and sh unless we want to scale the image.

To make the code more extensible, this example is encapsulated in a class named CanvasAnimation. This class handles the loading of the image and drawing the appropriate frame. The timing is controlled by a timer using setInterval().

[c]
	function CanvasAnimation(imageFilename, numberOfFrames, onReadyCallback)
	{
		// Associate functions with class
		CanvasAnimation.prototype.draw=draw;
		CanvasAnimation.prototype.animate=animate;
		CanvasAnimation.prototype.getCanvas=getCanvas;	
		
		// Create a blank canvas for drawing
		this.canvas=document.createElement("canvas");	
		this.canvasContext=this.canvas.getContext("2d");
		
		// This variable is needed because the code doesn't know how many frames are in the image 
		this.numberOfFrames=numberOfFrames;
		this.currentFrame=0;

		// Create image object and load the image file into it
		this.image=new Image();
		
		// Set a callback to start animating after the image is loaded
		this.image.onload=onReadyCallback(this);		
		this.image.src=imageFilename;
		
		function animate()
		{
		
			this.currentFrame++;
			if (this.currentFrame>=this.numberOfFrames)
				this.currentFrame=0;
			this.draw(0,0);
		}
		
		function draw(x, y)
		{
			var frameWidth=this.image.width/this.numberOfFrames;
			var frameHeight=this.image.height;
			var xOffset=frameWidth*this.currentFrame;
			this.canvasContext.clearRect(0,0,this.canvas.width, this.canvas.height); 
			this.canvasContext.drawImage(this.image, xOffset, 0, 
				frameWidth, frameHeight, 
				0, 0, frameWidth, frameHeight);
		}
		
		function getCanvas()
		{
			return this.canvas;
		}
	}	

	// This function is called when the image has load.
	function onReadyCallback(canvasAnimationObject)
	{
		// I am placing the animation into this div
		var divElement=document.getElementById("animationDiv");
		divElement.appendChild(canvasAnimationObject.getCanvas());

		// Fire up the timer to start the animation.
		setInterval("testAnimationLoop()",50);
	}
	
	function testAnimationLoop()
	{
		myAnimation.animate();
	}

	// Create the animation	
	var myAnimation=new CanvasAnimation("walk.gif", 8, onReadyCallback);

[/c]

The portion of the code to pay attention to is the draw() function. Here we locate the portion of the image that the current frame by dividing the image width and the current frame to get the xOffset.

Also, I am using a transparent image so I need to clear the canvas everytime a new frame is drawn, using clearRect()

[c]

		function draw(x, y)
		{
			var frameWidth=this.image.width/this.numberOfFrames;
			var frameHeight=this.image.height;
			var xOffset=frameWidth*this.currentFrame;
			this.canvasContext.clearRect(0,0,this.canvas.width, this.canvas.height); 
			this.canvasContext.drawImage(this.image, xOffset, 0, 
				frameWidth, frameHeight, 
				0, 0, frameWidth, frameHeight);
		}
[/c]

You can check out the example code here:
http://www.permadi.com/tutorial/html5-canvas-animation/html5-canvas-animation.html

Leave a Reply

*