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>
<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
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.
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).
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.
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.
circle1.addFrameListener(
function(t, dt)
{
this.scale = Math.sin(t / 1000);
}
);
The Circle
is then added as a child of the Canvas
.
CAKECanvas.append(circle1);
The whole process is then repeated with a second circle.
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
:
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
.
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
.
this.after(200,
function()
{
this.color = 'blue';
}
);
Finally, the ElementNode
is appended to the Canvas
.
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.
History
- August 25 2009 - Initial post