With the advent of tools like Adobe Edge and libraries like EaselJS, more resources are becoming available for developers looking to create interactive HTML5 content. Many of these tools are being geared specifically for Flash developers to make the transition from ActionScript to HTML5 canvas a smooth one. This article will overview oCanvas, an HTML5 library that developers might not only find invaluable but also very easy to use.
HTML5 Canvas Background
Before we dive into exploring oCanvas, let's quickly set the scene for how HTML5 canvas works. If you want a more thorough explanation on how to use HTML5 canvas, check out this tutorial.
If you know ActionScript, you already know a lot of JavaScript, which is where the real power resides when working with canvas. We use the HTML5 drawing API to create our content along with some good ol' JavaScript to make things interactive and dynamic. But when we combine the two, the approach behind how we go about putting together our code is a bit different than what we are used to with ActionScript.
In short, to use the native Canvas API, we draw pixels onto the drawing context of the canvas. But the key thing to remember is that we are working with the entire canvas, not just a single shape or image that we have drawn. Every time we want to alter something we have drawn we have to redraw the entire canvas. If we want to animate something we have to redraw the canvas over and over in our JavaScript to make it appear that things are moving.
This notion is very similar to traditional animation, where animators had to draw each and every pose in their sequence and have the camera move through them very quickly to simulate movement. But if you're used to tree-like structures such as the DOM, or the display list in Actionscript, this notion can be hard to get your head around. This rinse and repeat approach to programming is much different than working with objects for most developers.
Introducing oCanvas
Luckily for those of us who are so accustomed to working with objects, oCanvas brings that familiar approach to HTML5 canvas. oCanvas is a JavaScript library developed by Johannes Koggdal with the intention of making it easier to develop with HTML5 canvas. It allows you to work directly with objects, modify their properties and hook up events to them all while handling the nitty-gritty behind the scenes stuff for you. As put best by Johannes on his blog:
My goal has always been to make it really easy for people to build canvas things based on objects. I decided on the name oCanvas as a contraction of "object canvas".
Get the Library
To start using oCanvas we need to include a copy of the library on our HTML page. We can either reference the CDN-hosted file, or host a local copy ourselves. Jump over to the oCanvas website and you can either download a copy of the library or grab the reference to the CDN-hosted version. The current version is 2.0 and was released only a few weeks ago, which addressed many of the bugs that were in the initial release. On the site there is a minified production version, which is good to use when you're ready to deploy your project. There is also a development version, which is uncompressed but is better for debugging. I like to directly link to the hosted version for faster loading and caching by the browser.
<script src="http://cdnjs.cloudflare.com/ajax/libs/ocanvas/2.0.0/ocanvas.min.js"></script>
Initial Code Setup
After you make a reference to oCanvas, next we need to setup a canvas element in the body of our HTML and create a reference to it for use in our Javascript.
<canvas id="canvas" width="800" height="600"></canvas>
As always, if you place your script above the canvas element, you need to wrap it in a function so you know the DOM is ready. There's a couple ways to go here. You can either create your own function and then call it in your body element when it loads, like this:
function Main() { // your oCanvas code } <body onload="Main();">
Or you can wrap your code within oCanvas's built-in domReady()
method. This is the equivalent to jQuery's $(document).ready()
. In oCanvas we use this:
oCanvas.domReady(function () { //Your Code Here });
Note: You could use jQuery's $(document).ready()
method if you wanted to.
Initialize an Instance of oCanvas
This piece of code is absolutely necessary and is the first thing you must write when using oCanvas.
var canvas = oCanvas.create({ canvas: "#canvas", background: "#0cc", fps: 60 });
In this code we store a reference to the canvas element within our document and get access to the core instance, which will enable you to start creating objects. The create()
method takes an object as its argument which controls how oCanvas will work. There are numerous properties to pass into the create()
method, but the only mandatory one is the canvas property: a CSS selector that must point to a canvas element within the DOM.
The other properties passed in the above code are the background and fps properties. The background property allows you to apply a background to the canvas, which can be CSS color values, gradients and images. If it's omitted, the canvas will be transparent. The fps property sets the number of frames per second any animation will run at. The default is 30 fps.
Note: While we overview many of the features in oCanvas, I recommend checking out the library's documentation to get a better understanding of each section.
Display Objects
There are numerous types of display objects you can create with oCanvas. You can create shapes such as rectangles, ellipses, polygons and lines along with images, text and even sprite sheets. To create a new display object we use oCanvas's Display Module, and specify what kind of display object we want to create as well as some basic properties - like so:
var box = canvas.display.rectangle({ x: 50, y: 150, width: 50, height: 50, fill: "#000" });
Then to add it to the display we call a familiar method for you Flash developers...
Good Ol' addChild()
Yes an oldie but a goodie, which makes adding objects to oCanvas a familiar process. So to add our box to the canvas, we would write:
canvas.addChild(box);
Just like in ActionScript, addChild()
adds the specified object as a child of the caller. And in turn the child's x and y will be relative to its parent. So in this case we are making box a child of the canvas, which we could simplify like this:
box.add();
The add()
method also adds the object to the canvas — which is really the same thing as canvas.addChild(box). But addChild()
is most useful for adding an object as a child to an already created display object, like:
var square = canvas.display.rectangle({ x: 0, y: 0, width: 10, height: 10, fill: "#990000"}); box.addChild(square);
Let's take a look at some of the different types of display objects you can create in oCanvas.
Shapes
You already saw a square, but we can use the rectangle
display object to create a lot of things. Here's a rectangle with a blue stroke:
var rectangle = canvas.display.rectangle({ x: 500, y: 100, width: 100, height: 200, fill: "#000", stroke:"outside 2px blue" });
The fill
property can take any valid CSS color, along with CSS gradients and even image patterns.
To create an ellipse we would write:
var ellipse = canvas.display.ellipse({ x: 100, y: 100, radius_x: 20, radius_y: 30, fill: "rgba(255, 0, 0, 0.5)" });
If you want a full circle, just replace the radius_x
and radius_y
properties with a single radius
property.
Creating any kind of regular polygon is just as easy — all you have to do is specify the number of sides and the radius you want your shape to have. To create a triangle:
var triangle = canvas.display.polygon({ x: 320, y: 145, sides: 3, radius: 50, fill: "#406618" });
How about a pentagon?
var pentagon = canvas.display.polygon({ x: 200, y: 50, sides: 5, rotation: 270, radius: 40, fill: "#790000" });
To accomplish that with the HTML5 canvas API, you would have to draw a bunch of paths and try figure out what x and y positions to join them at. I attempted to draw an octagon for comparison's sake but as you can see below I gave up quite easily. Not quite sure what this is supposed to be.
var canvas = $("#canvas"); var ctx = canvas.get(0).getContext("2d"); ctx.fillStyle = '#000'; ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(100,50); ctx.lineTo(50, 100); ctx.lineTo(0, 90); ctx.closePath(); ctx.fill();
Images
Creating display objects with images doesn't get any simpler than in oCanvas. Just specify an x and y position and the path to the image file:
var tree = canvas.display.image({ x: 100, y: 350, image: "tree.png" });
A nice feature of the image display object is the tile
property, which lets you easily create a grid of the same image instead of drawing it over and over.
Text
oCanvas contains a text display object and handles font styling just like CSS does.
var text = canvas.display.text({ x: 70, y: 300, align: "center", font: "bold 18px sans-serif", text: "oCanvas Rocks", fill: "purple" });
You can use many of the other text properties you're familiar with from CSS. Check out the documentation on text for more.
Properties and Methods
All display objects inherit a common group of properties and methods. Some of the most common display object properties are: x, y, width, height, rotation, scalingX, scalingY, opacity, shadow
(uses CSS-box-shadow syntax) and zIndex
. You can check out this link for a full list of the base properties and methods. Let's take a look at some other noteworthy ones.
Origin
This method is a big time-saver because it let's you easily set the origin inside the object. In other words, it allows you to set the registration point of the object. If you ever tried to perform a rotation from the center with the HTML5 Canvas API, you know how big of a headache it can be. You have to do a slew of actions of saving the drawing state, translating the canvas, performing your rotation and then restoring the drawing state. With the origin
property you can easily define an object's origin:
var obj = canvas.display.image({ x: 270, y: 270, origin: { x: "center", y: "center" } });
This would draw the image from its center; if we were to rotate the object, it would rotate from its center, too. Besides "center" you could also pass in "left" or "right" for the x and "top" or "bottom" for the y positions. In addition to using the predefined keywords, you could also supply positive or negative numbers as values of where to draw the object. The default origin for all display objects is defined at its top left.
You can also use the setOrigin()
method at any time to define an object's origin:
obj.setOrigin("left", "bottom")
ID
A display object's id, which is really a read-only property, corresponds to where the object exists in the draw list — which you can think of as the display list. I find it to be very useful because it can serve as a unique identifier in certain situations when you might be seeking out a specific object in your code. Consider a basic snippet like this:
getId(box.id) function getId(id) { if (id==9) console.log("CORRECT ! " + id) else console.log("WRONG! " + id) }
Composition
The composition property is the equivalent of globalCompositeOperation
within the native Canvas API. If you're not familiar with it, it basically determines how pixels are rendered when drawn onto already existing pixels on the canvas. I encourage you to read up on the different compositing operations you can set, but with oCanvas you can simply set the operation you want by passing it as a string:
var shape = canvas.display.rectangle({ x: 270, y: 270, width: 180, height: 80, fill: "#ff6900", composition:"destination-atop" });
There are many different operations you can pass in but I think one of the neat things you can do with the composition property is create masks between different display objects. Check out the file named masks.html
in the download package. If you ever relied on creating layer masks in your Flash applications, you'll enjoy this one.
Methods of Note
Since we mentioned rotating objects earlier, you can quickly rotate an object with the rotate()
and rotateTo()
methods:
obj.rotate(45);
You can also simply set the rotation property:
obj.rotation=45;
There's also the move()
and moveTo()
methods which, like their names suggest, allows you to move an object by a specified amount of pixels for the former and toa specified x and y position for the latter.
obj.moveTo(100, 100)
The same idea works for the scale()
and scaleTo()
methods():
obj.scale(1.25, 0.25) obj.scaleTo(1.5, 1.5)
We mentioned addChild()
before; let's not forget about removeChild()
and removeChildAt()
. And like the add()
method, we can do the opposite with remove()
.
Another really useful method is clone()
, which allows you to duplicate a display object and all of its properties.
var box = canvas.display.rectangle({ x: 50, y: 150, width: 50, height: 50, fill: "#000"}); var box2 = box.clone(x:200)
Events
A big plus to oCanvas is that you can add events to specific objects. The oCanvas contains many methods and properties for easily handling mouse, keyboard and even touch events all with one simple method.
Bind()
If you're familiar with jQuery, you probably already know where I'm going with this.
canvas.bind("click tap", function () { canvas.background.set("#efefef"); });
All this does is change the background color of the canvas, but notice how we pass in "click tap" — easily allowing us to add support for both mouse and touch devices.
Besides click events, you can also listen for other mouse events:mousedown, mouseup, mousemove, mouseenter, mouseleave
and dblclick.
A simple rollover effect might look like this:
box.bind("mouseenter", function () { canvas.background.set("#333"); }).bind("mouseleave", function () { canvas.background.set("#000"); });
This is an example of chaining functions — which (not to sound like a broken record) is another jQuery feature leveraged in oCanvas.
But instead of altering the canvas when a mouse event occurs, what about altering an actual display object? This is still HTML5 Canvas after all, so we must remember to call an important method to tell the canvas to update itself.
canvas.redraw()
The redraw()
method (which is actually part of the Draw Module, not the Events Module) redraws the canvas with all the display objects that have been added. So if want to perform an action on a particular object and have the rest of the draw list stay intact, we must add this one simple line of code to our functions:
square.bind("click tap", function () { square.x+=50; canvas.redraw(); });
Unbind()
What good is an event listener if we can't remove it?
rectangle.bind("click tap", function onClick () { this.fill="#FF9933"; canvas.redraw(); rectangle.unbind("click tap", onClick) });
How About a Quick Drag and Drop?
We don't need the bind()
method for this one. We just write:
circle.dragAndDrop();
That's probably the quickest and easiest drag and drop code you'll ever write.
Note on events: When you're working with events, it's natural to want to get as much information as possible about the event. Luckily, we can still do so when working with oCanvas. For example if we take the click handler a few lines up and log the event to the console we can see all the properties we have from the event.
rectangle.bind("click tap", function onClick (e) { this.fill="#FF9933"; canvas.redraw(); rectangle.unbind("click tap", onClick); console.log(e); });
Keyboard and Touch Events
Besides mouse events, oCanvas has entire modules dedicated to keyboard and touch events with their own unique methods and properties. These events are also handled with the bind()
method. The events system in oCanvas is a very broad topic, so I encourage taking a look at the events section in the documentation and experimenting.
Timeline
With the Timeline Module we can set up our main loop for our application. If you were creating a game, this would essentially be your game loop. I like to think of it as the equivalent of an ENTER_FRAME
in Flash.
It's simple to set up — we just call the setLoop
function and chain the start()
method to it:
canvas.setLoop(function () { triangle.rotation+=5; }).start();
If we wanted to tie the setLoop()
function to an event - say to a mouse click - we could do something like this:
canvas.setLoop(function () { triangle.rotation+=5; }) button.bind("click tap", function () { canvas.timeline.start() });
And we could stop the timeline by simply calling:
canvas.timeline.stop();
Animation
Using setLoop()
is the way to go for animations that will occur over a long period of time and to handle constant updates you have to make throughout your application. But oCanvas has built in methods to handle more simpler and basic animations that are commonly needed. These methods are also practically taken verbatim from jQuery.
Animate()
The animate()
method works just like it does in jQuery. If you're not familiar with this side of jQuery, think if it like a tweening engine like TweenMax or Tweener for Flash. You can animate any property that can be set by a numeric value:
circle.animate( { y: circle.y - 300, scalingX:.5, scalingY: .5 }, "short", "ease-in", function () { circle.fill = "#45931e"; canvas.redraw(); } );
Here we animate the circle's y position and overall size, apply some easing, and when it is finished we run a callback function that changes its fill color. But don't forget to call redraw()
.
fadeIn()
, fadeOut()
, and fadeTo()
To fade an object in and out we could simply call:
square.fadeIn(); square.fadeOut();
To fade the opacity to a specific value, we'd use fadeTo()
:
square.fadeTo(.6);
You can also define the duration, easing and provide a callback function for these methods in the same way you would with the animate()
method.
Scenes
oCanvas contains a very useful Scenes Module that allows you to easily separate your application into different states. Game developers might appreciate this one because it's a simple approach to breaking down your game into different sections. Even old school Flash animators might liken the Scenes Module to the Scenes panel, which allows you to literally create different scenes within a Flash project.
To create a scene in oCanvas we call the create()
method to return a scenes
object:
var intro = canvas.scenes.create("intro", function () { // add display objects here });
Within the create()
method we pass in two arguments: the name of the scene as a string, and a function where we add the display object we want to add to that scene.
var introText = canvas.display.text({ x: canvas.width / 2, y: canvas.height/2, align: "center", font: "bold 36px sans-serif", text: "Introduction", fill: "#133035" }); var intro = canvas.scenes.create("intro", function () { this.add(introText); });
Now we have to load our scene and those objects will be added to the display:
canvas.scenes.load("intro");
Notice we pass in the name we gave the scene when we created it.
And of course we can unload a scene at any time:
canvas.scenes.unload("intro");
Imagine how much of a time-saver this could be if you used scenes and event handlers together.
oCanvas vs. EaselJS
The only real downside to oCanvas is that it hasn't gained as much traction in the development community as you might guess - or at least it seems that way for now. Part of that reason for this, I think, is because of the popularity of EaselJS. There seems to be alot more awareness and resources out there for EaselJS than there are for oCanvas — which is hard to believe since the latter was first released in March 2011, but for some reason it has flown under the radar.
I've been using both libraries for quite some time now, and I can honestly say I am big fan of both. EaselJS definitely feels more like you are using ActionScript and if you're a Flash developer will be easy to pick up. And as we've seen, oCanvas could pass for jQuery's long lost brother in many ways. So if you're a pure ActionScripter, you might just naturally gravitate towards EaselJS— especially since Easel was written specifically to appeal to Flash developers.
However, I've been using Actionscript much longer than jQuery and I personally find oCanvas simpler to use and less verbose to write. And even though EaselJS is pretty easy to use itself, the simple syntax in oCanvas just makes it such a welcome tool.
But besides the simpler syntax, oCanvas and EaselJS in many ways are are pretty much interchangeable. Both libraries can accomplish more or less the same tasks and there's very little difference in performance, if any. However I do notice the Ticker function in EaselJS runs a little more smoothly than oCanvas' setLoop
function (though that could just be a browser-based difference).
EaselJS does have much more of an extensive API — especially when it comes to drawing and effects. And if you take into account TweenJS and SoundJS, Easel is definitely a more complete tool — especially if you're used to using an application like Flash that offers fine-tune control over your projects. But if you're new to the whole HTML5 game, you're likely to hit the ground running with oCanvas much faster. When I was first introduced to oCanvas, I found it so much fun to play with. Everything is already there for you — all the necessary methods and events to start creating, manipulating and animating objects right away.
Wrapping Up
Whichever library you prefer, oCanvas and EaselJS are only the beginning of what I think will be an influx of tools and resources to allow developers to easily create browser-based applications. The features of oCanvas detailed in this article barely scratch the surface of what could be created using this very powerful library.
By no means though is oCanvas (or any library for that matter) a reason not to learn and use the native HTML5 Canvas API. But if you find yourself in a situation where all your former Flash clients are now looking for you to create HTML5 apps (like mine were) and you don't have time to learn something like the unfriendly transformation matrix in the native Canvas API — oCanvas can definitely ease the learning curve.
Comments