Using cache in complex shapes and animations

Caching in EaselJS comes in handy when you have a complex shape or animation in your canvas. In most cases, complex shapes with details shouldn't get rendered in every tick. So you can simply use the cache method to cache it in order to prevent rendering overhead.

Now we will see a complex example from the EaselJS library (source: https://github.com/CreateJS/EaselJS/blob/master/examples/Cache.html) and the effect of using a cache technique on that. In this animation, we will create about 200 complex circles and move them on each tick. There is a checkbox on the page that controls the enabling or disabling of caching for all shapes inside the canvas area using cache and uncache methods.

The following screenshot shows us a preview of our animation (notice the checkbox):

Using cache in complex shapes and animations

There are three main functions that handle this animation and all the logics; init, tick, and toggleCache. We will discuss each one of them separately.

In the first lines of the code, we will use the following variables:

var canvas;
var stage;
var shape;
varcircleRadius= 30;
var rings = 30;

The first variable holds the canvas element, the second one is used for the Stage object, the shape variable is used to draw shapes on the stage, and circleRadius and rings are used for basic settings of circles. circleRadius is used to define the radius of each circle and rings is used to define the number of rings inside each circle.

The following code shows the the basic init method that draws all shapes and prepares the stage:

Function init() {
  // create a new stage and point it at our canvas:
  canvas = document.getElementById("testCanvas");
  stage = new createjs.Stage(canvas);

  // create a large number of slightly complex vector shapes, and give them random positions and velocities:

  var colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"];

  for(var i= 0; i< 200; i++) {
    shape = new createjs.Shape();
      for(var j = rings; j > 0; j--) {
        shape.graphics.beginFill(colors[Math.random() * colors.length | 0]).drawCircle(0, 0, circleRadius * j / rings);
    }
    shape.x = Math.random() * canvas.width;
    shape.y = Math.random() * canvas.height;
    shape.velX = Math.random() * 10 - 5;
    shape.velY = Math.random() * 10 - 5;

    stage.addChild(shape);
  }

  // add a text object to output the current FPS:
  fpsLabel = new createjs.Text("-- fps", "bold 18px Arial", "#FFF");
  stage.addChild(fpsLabel);
  fpsLabel.x = 10;
  fpsLabel.y = 20;

  // start the tick and point it at the window so we can do some work before updating the stage:
  createjs.Ticker.addEventListener("tick", tick);
  createjs.Ticker.setFPS(50);
}

This code is used to create the stage and all shape objects. In lines 3 and 4, the Stage object is created. In line 8, we defined random colors for circle rings. After that, we have used a for-loop, which draws 200 different circles with random positions on the stage. We have another for-loop to draw rings inside the circles in line 12.

In our animation, we have a label that indicates the Frames per Second (FPS) rate on each tick. So, in lines 28 to 31, we have defined our label properties. In line 34, the Ticker class is created and in line 36, the FPS of the animation is set to 50.

After the init function, we have a tick function that will be called on each tick by EaselJS:

function tick(event) {
  var w = canvas.width;
  var h = canvas.height;
  var l = stage.getNumChildren() - 1;

  // iterate through all the children and move them according to their velocity:
  for(var i= 1; i< l; i++) {
    var shape = stage.getChildAt(i);
    shape.x = (shape.x + shape.velX + w) % w;
    shape.y = (shape.y + shape.velY + h) % h;
  }
  fpsLabel.text = Math.round(createjs.Ticker.getMeasuredFPS()) + " fps";
  // draw the updates to stage:
  stage.update(event);
}

The main job of the above init function is to change the position of all the circles on the stage on each tick, set the current FPS rate to the label, and then update the stage. The reason there is -1 in line 4 is to exclude the label object from children; keep in mind that we only need to change the position of all the circles.

The last function is the toggleCache function. This method enables or disables caching for all circles:

function toggleCache(value) {
  // iterate all the children except the fpsLabel, and set up the cache:
  var l = stage.getNumChildren() - 1;
  for(var i= 0; i< l; i++) {
    var shape = stage.getChildAt(i);
    if (value) {
      shape.cache(-circleRadius, -circleRadius, circleRadius * 2,circleRadius * 2);
    } else {
      shape.uncache();
    }
  }
}

This function is called only when you check or uncheck the checkbox on the page so it enables or disables caching for all circle objects on stage. There is a for-loop that iterates over all circle shapes and calls the cache or uncache method according to the status of the checkbox. Consequently, the caching for circle shapes will be enabled or disabled.

By clicking on the checkbox, you can obviously see that the animation rendering gets smoother when caching is enabled.

Finally, you can find the complete source code of our animation on the Packt website.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.61.170