
Drawing on canvas using just the API is tricky, requiring at least a working knowledge of the browser canvas API, as well as JavaScript itself. While the process can be made easier by using a library or framework, doing so can have its drawbacks. Sometimes the library that you haven chosen (often arbitrarily because you’ve previously heard of it, or a colleague recommended it) can provide just as many limitations to the task at hand as it offers solutions.
This tutorial is going to provide an introductory look at using TweenJS – a library designed to simplify the process of animating tweens on canvas elements. By focusing on this one potentially troublesome aspect of using <canvas>, and remaining compatible with the native canvas API, TweenJS offers a great lightweight solution to speeding up your workflow without imposing any real limitations.
A basic page
All of the vector graphics will be created using the EaselJS library, which abstracts the core canvas API to make it as easy as possible to get everything going. Not much is needed in the way of an HTML page to get started, so quickly create a blank document with a single <canvas> element. Give the <canvas> an id of mycanvas, add a width and height of 900px, then make sure to save the file as index.html.
001 <!DOCTYPE HTML>
002 <html lang=”en”>
003 <head>
004 <title>TweenJS Example</title>
005 <meta charset=”utf-8”>
006 <style type=”text/css”>
007 body {
008 margin: 0px;
009 background: #000;
010 }
011 /* Centre the <canvas> on the page */
012 #mycanvas {
013 width: 900px;
014 height: 900px;
015 position: relative;
016 margin: auto;
017 display: block;
018 border: 1px solid #333;
019 }
020 </style>
021 </head>
022 <body>
023 <canvas id=”mycanvas” width=”900” height=”900”></canvas>
024 </body>
025 </html>
Include TweenJS
Visit www.createjs.com and download the production scripts of both EaselJS and TweenJS for inclusion on your page. Once you’ve grabbed them, add the libraries to the page by using <script> tags in the <head> section of the page. You’ll also need to include the EventDispatcher and Ease plug-ins. Create a blank JavaScript file and add a final <script> tag in your HTML to point to it. This will hold the canvas drawing code.
001 <!-- The main Easel Library --> 002 <script src=”scripts/easel.js”></script> 003 <!-- Handle events --> 004 <script src=”scripts/eventdispatcher. js”></ script> 005 <!-- The main Tween Library --> 006 <script src=”scripts/tween.js”></script> 007 <!-- Easing functions --> 008 <script src=”scripts/ease.js”></script> 009 <!-- Our Script! --> 010 <script src=”scripts/vector.js”></script>
Locate the canvas
Before being able to do any drawing, it is necessary to programmatically connect to the canvas on the page using JavaScript. This is done by first grabbing a reference to the <canvas> element using the getElementById method, then using this reference to create a drawing instance. Add the code shown to the ‘vector.js’ file, which will be the one you’ll be working in for the remainder of the tutorial.
001 // This function will be called when the page DOM is ready for manipulation
002 function init(){
003
004 // Set up the stage and draw an object on it
005
006 // Create an EaselJS stage object
007 mycanvas = document. getElementById(“mycanvas”);
008 stage = new createjs.Stage(mycanvas);
009
010 // The stage is now ready to be drawn upon
011 }
012
Basic drawing with EaselJS
Now everything should be prepped and ready to do some basic drawing in the browser using the EaselJS library. With the created 900px square canvas, you can plot and draw lines, shapes and text anywhere you like within these confines. Keep in mind that the origin point (0,0) is in the top left corner of the canvas, rather than the bottom left as you might have expected.
Basic shapes
The EaselJS graphics library includes a series of methods for drawing shapes and lines. One of the best ways to understand how it works is to get stuck straight in, so create a simple square that you can later use as part of the animation routine. Add the following lines of code to draw a square now – you’ll be able to see exactly what’s going on in the next step.
001 var square = new createjs.Shape(); 002 003 square.graphics.setStrokeStyle(5); 004 005 // a nice orange colour! 006 square.graphics.beginStroke(“#ff9900”); 007 008 square.graphics. drawRect(100,100,200,200); 009 stage.addChild(square); 010 011 <body onload=”init()”>
What’s happening?
You can get a full reference guide by looking in the documentation folder within the EaselJS folder, but briefly, a stroke (outline) style of 5px has been set, then a rectangle drawn starting at 100,100 and extending 200px on the X axis, and 200px on the Y axis. Then it is added to the canvas to make it display on screen.
Missing links
A square has been drawn in the previous steps, but at the moment there’s no way of remembering it; once the square is drawn, unless there is a reference kept to it, it’s forgotten. In order to be able to manipulate its position, you need to store a note of it. Change the code to look like that shown below, which remembers the square for easy later access.
001 var tweens;
002
003 function init() {
004
005 tweens = [];
006
007 var square = new createjs.Shape();
008
009 square.graphics.setStrokeStyle(5);
010
011 // a nice orange colour!
012 square.graphics.beginStroke(“#ff9900”);
013
014 square.graphics. drawRect(100,100,200,200);
015 tweens.push({ref:square});
016 stage.addChild(square);
017
018 }
019
Lots of squares!
Now you know how to create a square and store a reference to it, use this knowledge to create 25 squares instead of just one. While you’re at it, position each one randomly on the canvas, and make each one slightly bigger than the last. Change the code to look like the following, then give it a try.
001 var tweens;
002 var squareCount = 25;
003 function init() {
004
005 tweens = [];
006 for (var i=0; i<squareCount; i++) {
007 // draw the square, and put it on stage:
008 var square = new createjs.Shape();
009 square.graphics.setStrokeStyle(5);
010 square.graphics. beginStroke(“#ff9900”);
011 square.graphics. drawRect(0,0,(i+1)*6,(i+1)*6);
012 square.alpha = 1-i*0.02;
013 square.x = Math.random()*550;
014 square.y = Math.random()*400;
015 tweens.push({tween:tween, ref:square});
016 stage.addChild(square);
017 }
018 }
Set the colour
At the moment, the squares block each other out as they overlap. It’s easy to improve the way this looks by simply using a blending mode for the squares, allowing their colour to interact and making the entire canvas take on a bit of zing. Add the code shown below to the square creation loop.
001 var tweens;
002 var squareCount = 25;
003 function init() {
004 tweens = [];
005 for (var i=0; i<squareCount; i++) {
006 // draw the square, and put it on stage:
007 var square = new createjs.Shape();
008 square.graphics.setStrokeStyle(5);
009 square.graphics. beginStroke(“#ff9900”);
010 square.graphics. drawRect(0,0,(i+1)*6,(i+1)*6);
011 square.alpha = 1-i*0.02;
012 square.x = Math.random()*550;
013 square.y = Math.random()*400;
014 square.compositeOperation = “lighter”;
015 tweens.push({ref:square});
016 stage.addChild(square);
017 }
018 }
019
Animate positions
It’s now possible to animate the squares using the TweenJS library. Start off by moving each square into the same position, so that you end up with a set of concentric squares. You’ll animate to this position after the squares have been drawn in their random positions.
001 var tweens;
002 var squareCount = 25;
003 function init() {
004
005 tweens = [];
006 for (var i=0; i<squareCount; i++) {
007 // draw the square, and put it on stage:
008 var square = new createjs.Shape();
009 square.graphics.setStrokeStyle(5);
010 square.graphics. beginStroke(“#ff9900”);
011 square.graphics. drawRect(0,0,(i+1)*6,(i+1)*6);
012 square.alpha = 1-i*0.02;
013 square.x = Math.random()*550;
014 square.y = Math.random()*400;
015 square.compositeOperation = “lighter”;
016 var tween = createjs.Tween. get(square).to({x:275-(i*3),y:200-(i*3)}, (0.5+i*0.04)*1500, createjs.Ease.bounceOut). call(tweenComplete);
017 tweens.push({tween:tween, ref:square});
018 stage.addChild(square);
019 }
020 createjs.Ticker.addEventListener(“tick”, tick);
021 }
022
023 function tick(event) {
024 stage.update(event);
025 }
What’s going on?
The TweenJS library is automatically handling the movement of the squares from their starting position to their final positions on the stage. All we had to do was pass in the final position we’d like the squares to arrive at, and the easing method we’d like to use.
The tweens array
You’ll notice that the squares tween has been added to the tweens array at the end of the loop. This is an easy way to keep track of both the tween being applied, and the object it’s applied to. These references will be used a little later on to animate the squares again in response to a mouse click.
001 var tween = createjs.Tween.get(square).
002 to({x:275-(i*3),y:200-(i*3)}, (0.5+i*0.04)*1500, createjs.Ease.bounceOut). call(tweenComplete);
003 tweens.push({tween:tween, ref:square});
Easy does it
There are many different easing methods available to make use of. Each offers a different way of mathematically calculating which position the object being animated should occupy at a specific point in time. Experiment with the different options (check the documentation for details), and find one you like. The code below uses bounceOut.
001 var tween = createjs.Tween.get(square).
002 to({x:275-(i*3),y:200-(i*3)}, (0.5+i*0.04)*1500, createjs.Ease.bounceOut). call(tweenComplete);
Click to animate
Now you can start writing a function that will fire each time the mouse button is pressed. Aim for an effect where the squares animate to the position where the mouse was clicked, allowing the user to change the position of the squares as they like. Start off by adding the basic function shown below.
001 function clicked(event) {
002 // This function will be fired when the mouse is clicked
003
004 // Loop through each of the squares and provide a tween
005 }
006 stage.addEventListener(“stagemouseup”, clicked);
Make it happen
Now a function has been set up, you can work through each of the squares and set it to animate into position in the same way you did for the opening animation, but this time using the mouse-click position instead of the hard-coded values for X and Y.
001 function clicked(event) {
002 for (var i=0; i<squaresCount; i++) {
003 var ref = tweens[i].ref;
004 var tween = tweens[i].tween;
005 createjs.Tween.get(ref,{override:true}). to({x:stage.mouseX,y:stage.mouseY}, (0.5+i*0.04)*1500, createjs.Ease.bounceOut). call(tweenComplete);
006 }
007 activeCount = squaresCount;
008 }
The ticker
You’ll find that there’s no need to worry about when to draw and update – it’s all handled automatically by the tick() function. The tick function has been added as the target for the tick event. This is an internal object that provides abstracted access to the requestAnimationFrame() method – see the ‘Why use a ticker?’ section on the previous page for more details.
001 function tick(event) {
002 stage.update(event);
003 }
004
Test and perfect
There’s no need to continually redraw the canvas if nothing is being animated, so each time a square finishes its tween, just make a note – and if no squares are being animated, you can prevent the redraw from happening at all. Doing this will save processor power and battery life for your users. Once completed, give it a quick test and review!
001 function tweenComplete() {
002 activeCount--;
003 }
004
005 function tick(event) {
006 if (activeCount) {
007 stage.update(event);
008 }
009 }
010