Raining google with HTML5’s Canvas

Following on from the Great Balls of Gravity post, I’ve used the code from the post and adjusted to animate Google’s logo.  Each letter within the famous name will free-fall from top, bounce at the base and then fall off the bottom and repeat.

bouncing-letters

This can be viewed here.
To achieve this effect I started with the following HTML.

	
		
		Bounce Animation
		
		
	
	
		Canvas Not Supported
	

There are two parts to the implementation. This first part is the inclusion of the HTML5 canvas tag. This is used to draw and animate the logo. The animation is driven by the JavaScript code included within the files referenced by the script tags e.g.


The first section of JavaScript that is executed can be found within the file ‘bounce.js’:
window.addEventListener('load', function (ev) {
	canvas = document.getElementById('canvas');
	ctx = canvas.getContext('2d');
	loadBackground(function() { setUpBalls(); });
}, false);
By binding an anonymous function to the ‘load’ event we can execute the code that starts the animation. The code obtains a handle to the canvas element by using the ‘getElementById’ call. This is then used to obtain the canvas’ context. The context can be used to draw onto the canvas, allowing you to draw shapes or images. With the canvas and context set-up within a global scope the function that starts the drawing and animation is called e.g.
	loadBackground(function() { setUpBalls(); });
The ‘loadBackground’ function accepts one parameter. This parameter is another anonymous function. This function when executed will called the ‘setUpBalls’ function. The callback function is executed within the ‘loadBackground’ function:
function loadBackground(callback) {
	// Load the background
	bg = new Image();
	bg.src = 'background.png';
	bg.onload = callback;
}
The above creates an Image object and assigns an actual image to the source property. The callback parameter passed into the function is then assigned to onload event of the new image. The result of which is the execution of the callback function after the image has been loaded. We know the callback function simply calls the ‘setUpBalls’ function which includes the following:
function setUpBalls() {
	var iCounter,
		x = 0,
		lettersConf = setUpLetterArray();

	for(iCounter = 0; iCounter < lettersConf.length; iCounter++) {
		letters.push(new Letter(x, bg, lettersConf[iCounter]));
		x += lettersConf[iCounter].width;
	}

	loop();
}
The purpose of this function is to create an array of letters. Each letter in the array represents a letter within the word ‘Google’. The letter object contains the relevant attributes to render and animate each. The data structure used to create each letter is created within the ‘setUpLetterArray’ function:
function setUpLetterArray() {
	return [
		{
			/* G */
			bgimagex: 0,
			bgimagey: 0,
			factor: 1,
			height: 156,
			width: 130,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		},
		{
			/* o */
			bgimagex: 133,
			bgimagey: 35,
			factor: 1,
			height: 100,
			width: 90,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		},
		{
			/* o */
			bgimagex: 222,
			bgimagey: 35,
			factor: 1,
			height: 100,
			width: 90,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		},
		{
			/* g */
			bgimagex: 315,
			bgimagey: 50,
			factor: 1,
			height: 142,
			width: 88,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		},
		{
			/* l */
			bgimagex: 405,
			bgimagey: 0,
			factor: 1,
			height: 192,
			width: 40,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		},
		{
			/* e */
			bgimagex: 450,
			bgimagey: 45,
			factor: 1,
			height: 100,
			width: 75,
			top: (0 - Math.floor((Math.random() * 400) + 1))
		}
	];
}
The function above creates the data structure using JavaScript Object Notation (JSON). Each of the individual objects within the structure holds the parameters needed to draw the letter. This includes the start position, height and width, and finally the position of the letter within the loaded background image. Take for example the second letter: the letter ‘o’. This is represented by the following object:
{
	/* o */
	bgimagex: 133,
	bgimagey: 34,
	factor: 1,
	height: 100,
	width: 90,
	top: (0 - Math.floor((Math.random() * 400) + 1))
}
Visually you can see how these parameters map to the background image:

Sprite map theory

Now we understand the core data structure, we should return to the ‘setUpBalls’ function:
	for(iCounter = 0; iCounter < lettersConf.length; iCounter++) {
		letters.push(new Letter(x, bg, lettersConf[iCounter]));
		x += lettersConf[iCounter].width;
	}
Each element within the initial data structure is then used to create a Letter object which is added to the global array ‘letters’. The Letter object is defined within the file ‘letter.js’ which contains the following:
var Letter = function (x, bg, ballSettings) {
	this.vy = 0;
	this.vx = 0;
	this.vyAdjust = -13;
	this.width = ballSettings.width;
	this.height = ballSettings.height;
	this.x = x;
	this.y = ballSettings.top;
	this.originaly = ballSettings.top;
	this.imagex = ballSettings.bgimagex;
	this.imagey = ballSettings.bgimagey;
	this.bg = bg;
	this.bounceFactor = ballSettings.factor;
	this.bounces = 0;

	this.draw = function () {
		ctx.drawImage(this.bg,
			this.imagex, this.imagey,
			this.width, this.height,
			this.x, this.y,
			this.width, this.height
		);
	};

	this.impact = function () {
		this.vy = this.vyAdjust;
		this.bounces++;
	};

	this.move = function () {
		this.y += this.vy;
		this.vy += 0.25; //gravity;
		// Bounce the ball when it hits the bottom
		if(this.bounces > 1) {

			if ((this.y + this.height) > canvas.height + 200) {
				this.bounces = 0;
				this.vyAdjust = -13;
				this.y = this.originaly;
			}
		}
		else if ((this.y + this.height) > canvas.height - 10) {
			this.impact();
			this.vyAdjust = (this.vyAdjust * this.bounceFactor);
		}
	};
};
The Letter object above encapsulates the attributes required to draw and move each Letter. Through a combination of variables to track the position and three functions to apply the logic, each letter controls its own movement. This movement is controlled within the ‘loop’ function which is called on completion of the ‘setUpBalls’ function.
function loop() {
	update();
	window.requestAnimFrame(loop);
}
The above function recursively calls the ‘update’ function:
function update() {
	var i  = letters.length;
	clearCanvas();
	while (i--) {
		letters[i].move();
		letters[i].draw();
	}
}
This applies the main logic for the program by iterating through each object in the main array and calling the ‘move’ and ‘draw’ function. The ‘move’ function applies simple physics algorithm to calculate the letters new position. This is followed by a call to the object’s ‘draw’ function which performs the obvious. This logic is repeatedly applied to animate the letters.
That concludes this post. A working version can be viewed here. The source code is available in Github.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s