Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / XHTML

CAKE Programming Tutorial - Getting Started

5.00/5 (5 votes)
24 Aug 2009CPOL3 min read 66.1K  
An introductory look at the JavaScript CAKE library, which allows you to build up the HTML5 canvas element like a vector image.

Introduction

CAKE is a JavaScript library that allows you to use the HTML5 canvas element as a scenegraph, much like an SVG or other vector image. This article will show you how to get started with this powerful library.

Background

This article was presented as part of the CAKE Programming Tutorials collection

Using the Code

CAKE allows developers to build up a canvas element from a number of individual elements, rather than working with the pixels directly. Now we will look at a sample application that demonstrates this effect.

cake.html
HTML
<html>
	<head>
		<script type="text/javascript" src="../cake.js"></script>
		<script type="text/javascript" src="cake-demo.js"></script>
		<title>CAKE Programming Tutorial</title>
	</head>
	<body style="margin: 0">
	</body>
</html>

First of all, we need an HTML file to host the application. As you can see, the HTML is very basic. Apart from the two JavaScript source files (cake.js being the CAKE library source, and cake-demo.js being our own JavaScript file) and a simple style tag to remove the margins, this HTML is the bare minimum needed to display a page.

cake-demo.js
JavaScript
window.onload = function() 
{
	var CAKECanvas = new Canvas(document.body, 600, 400);
	
	var circle1 = new Circle(100, 
		{
			id: 'myCircle1',
			x: CAKECanvas.width / 3,  
			y: CAKECanvas.height / 2, 
			stroke: 'cyan', 
			strokeWidth: 20,
			endAngle: Math.PI*2
		}
	);
	
	circle1.addFrameListener(
		function(t, dt) 
		{
			this.scale = Math.sin(t / 1000);
		}
	);
	
	CAKECanvas.append(circle1);

	var circle2 = new Circle(100, 
		{
			id: 'myCircle2',
			x: CAKECanvas.width / 3 * 2,  
			y: CAKECanvas.height / 2, 
			stroke: 'red', 
			strokeWidth: 20,
			endAngle: Math.PI*2
		}
	);
	
	circle2.addFrameListener(
		function(t, dt) 
		{
			this.scale = Math.cos(t / 1000);
		}
	);
	
	CAKECanvas.append(circle2);
	
	var hello = new ElementNode(E('h2', 'Hello, world!'), 
		{
			fontFamily: 'Arial, Sans-serif', 
			noScaling: true, 
			color: 'black',
			x: CAKECanvas.width / 2, 
			y: CAKECanvas.height / 2,
			align: 'center',
			valign: 'center'
		}
	);
	
	hello.every(1000, 
		function() 
		{
			this.color = 'magenta';
			this.after(200, 
				function() 
				{
					this.color = 'blue';
				}
			);
		},
		true
	);
					
	CAKECanvas.append(hello);
};

The real work is done in the cake-demo.js script. First a function is created and assigned to the windows onload event.

JavaScript
window.onload = function() 
{
   ...
}

A Canvas object is created. Although this does create a canvas element in the HTML page, the Canvas object is actually part of the CAKE library. Here we specify the parent element (page.body) and the dimensions (600 x 400).

JavaScript
var CAKECanvas = new Canvas(document.body, 600, 400);

A Circle is then created. The first parameter is the size of the circle. The second parameter is an object that has been created via literal notation. Literal notation is a feature of JavaScript where the properties of an object can be defined and initialised inline, like {paramapter_a: “a”, parameter_b: 100}. This is a convenient way around JavaScript’s lack of function overloading or optional parameters. Since the properties of this object are labelled, they are also self documenting.

JavaScript
var circle1 = new Circle(100, 
	{
		id: 'myCircle1',
		x: CAKECanvas.width / 3,  
		y: CAKECanvas.height / 2, 
		stroke: 'cyan', 
		strokeWidth: 20,
		endAngle: Math.PI*2
	}
);

A function is added to the Circle to be called every frame. The t parameter is the total time in milliseconds that the application has been running, while the dt parameter is the milliseconds since the last frame. Here we use the total time to modify the scale of the circle along a sine wave.

JavaScript
circle1.addFrameListener(
	function(t, dt) 
	{
		this.scale = Math.sin(t / 1000);
	}
);

The Circle is then added as a child of the Canvas.

JavaScript
CAKECanvas.append(circle1);

The whole process is then repeated with a second circle.

JavaScript
var circle2 = new Circle(100, 
	{
		id: 'myCircle2',
		x: CAKECanvas.width / 3 * 2,  
		y: CAKECanvas.height / 2, 
		stroke: 'red', 
		strokeWidth: 20,
		endAngle: Math.PI*2
	}
);

circle2.addFrameListener(
	function(t, dt) 
	{
		this.scale = Math.cos(t / 1000);
	}
);

CAKECanvas.append(circle2);

Next we create an ElementNode. Whereas the Circle will render directly to the canvas (meaning that you won't see a circle in the page DOM), the ElementNode is used to create a standard HTML element. From the developer's point of view, the ElementNode is created and modified just like any other object added to the Canvas, but because it is rendered as an HTML element, it can be interacted with in a standard way by the end user (like selecting and copying text). The first parameter is an E object, which is a shorthand way to define the element type and its contents. The second parameter is an object created with literal notation, just like the Circle:

JavaScript
var hello = new ElementNode(E('h2', 'Hello, world!'), 
	{
		fontFamily: 'Arial, Sans-serif', 
		noScaling: true, 
		color: 'black',
		x: CAKECanvas.width / 2, 
		y: CAKECanvas.height / 2,
		align: 'center',
		valign: 'center'
	}
);

A function is set to run every second (or 1000 milliseconds) using every function. This allows code to be run at regular intervals. In this case, we set the colour of the text to magenta.

JavaScript
hello.every(1000, 
	function() 
	{
		this.color = 'magenta';
                ...
	},
	true
);

With each call to the function defined in the call to every function, we also set a function to be run after 200 milliseconds using the after function. Unlike with the every function, code assigned to the after function is run once (although assigning code to the after function inside code assigned to the every function does mean that, in this code, it will be run every second). In this case, we set the colour of the text back to blue.

JavaScript
this.after(200, 
	function() 
	{
		this.color = 'blue';
	}
);

Finally, the ElementNode is appended to the Canvas.

JavaScript
CAKECanvas.append(hello);

The end result is an animated web page, not unlike what you would expect to see created with Flash or Silverlight. The page itself has been rendered with a canvas and a H2 element, but this is mostly transparent to the developer who can think of the page in terms of a scene graph.

See the live demo here, and download the source code here.

Image 1

History

  • August 25 2009 - Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)