After all the fuzz cause by Steve Jobs objections against Flash and indirect promotion of HTML5 I wanted to see whats possible using HTML5 and the canvas element. After searching a bit online I stumbled upon some interesting articles. One implementation of Quake2 using HTML5, and the implementation of an SWF player using HTML5. This seeded my interest a little more and I wanted to see how easy it is to get something on the screen.
Simple outline of a tree based renderer
As an example project I wanted to create a simple tree graph renderer inspired by the Flash MovieClip hierarchy. The final outcome should become something like this.
// add root shapes
var canvas = new Canvas(c.canvas, c.ctx);
canvas.addShape(new Symbol(50, 25));
canvas.addShape(new Symbol(160, 25));
canvas.addShape(new Symbol(160, 135));
canvas.addShape(new Symbol(50, 135));
The Canvas element should take care of the rendering process and render the symbols. Rendering the complete tree at 20 frames a second will be done using the following code.
canvas.init();
canvas.render();
canvas.run(20);
Shapes
At a minimum our renderer should be able to place shapes onto the screen. The minimal information I want to update through the Tree is the x and y position. They should be able to update their state and be capable of rendering themselves on a context.
- update(timeInMilliseconds), function to update properties of the shape.
- draw(context), actual rendering on the canvas
The Box as you can see it moving above has been defined as:
function Box(x, y, width, height) {
// simple element, just renders a strokeRect
Shape.call(this, x, y);
this.width = width;
this.height = height;
this.draw = function (ctx) {
ctx.strokeRect(this._x, this._y, this.width, this.height);
}
}
This setup enables composition of complex shapes using simpler shapes as can be seen below.
function Symbol(x, y) {
// initialise shape
Shape.call(this, x, y);
// compose this shape out of 2 boxes
this.box = this.addChild( new Box(0,0,100,100) );
this.innerbox = this.box.addChild(new Box(10,10,80,80));
}
Behaviours
To create animations we have multiple options. One can always supply a function to update x,y,width,heigh or rotation. But many behaviours are standard, and especially with complex behaviours we would like to compose them. So I added the possibility to add behaviours to specific shapes.
function Behaviour() {
// Basic methods for a behaviour
// stores shape in shape and original coords
this.init = function (s) {
this.shape = s;
this.original_x = s.x;
this.original_y = s.y;
}
// apply applies the behaviour .. should
// be implemented ina specific behaviour
this.apply = function (time) {
}
}
To test this behaviour I implemented the Wobble as can be seen above:
function BehWobble(duration,amplitude) {
// BehWobble is a behaviour
Behaviour.call(this);
this.wobble = 0;
this.duration = 1000*duration;
this.amplitude = amplitude;
this.apply = function (time) {
this.shape.x -= this.wobble;
this.wobble = this.amplitude * Math.sin(toRad(360*((time%this.duration)/this.duration)));
this.shape.x += this.wobble;
}
}
Putting it together
I update the symbol function to add the behaviour to the boxes. And voila the result can be seen above:
function Symbol(x, y) {
Shape.call(this, x, y);
this.box = this.addChild( new Box(0,0,100,100) );
this.innerbox = this.box.addChild(new Box(10,10,80,80));
// let the innerbox wobble
this.box.addBehaviour(new BehWobble(4,10));
this.innerbox.addBehaviour(new BehWobble(2,10));
this.innerbox.addBehaviour(new BehWobble(1,-10));
}
Conclusion
Just a little abstraction to rendering stuff in the HTML5 canvas element. So far I am pretty happy with it but started looking for some existing frameworks. Landed on processing.js which looks promising.
Code can be read here, Simple engine code, and the wobbling squares are defined here.