The HTML5 Canvas

This walk-through demonstrates the some basic principles of drawing on the canvas element.  One of the defining characteristics of the canvas is that once it is transformed via a scale, translate, or other transforming operation, it can be drawn upon.  However, while the rendered drawing remains, you have to put the canvas back into the state it was in prior to its transformation.  This kind of repetitive "transform, draw, then reset and repeat" operation is just how the drawing stack state works with save() and restore() API methods.  

 

 

 

If you have a large number of images in a scene and you need to draw them in a relatively small amount of pixel space, when compared to the size of the screen, you will most likely choose the canvas for your drawing operations.  Drawing on the canvas element is easy if you become familiar with a few simple functions and techniques.  This example is perfect for demonstrating the capabilities of the canvas.  

First, let's stage the images we will be drawing and transitioning on the canvas.  

 

    // Create new images, using the Image constructor, for the objects in our canvas.
    //
    var sun = new Image();
    var moon = new Image();
    var earth = new Image();

    /** 
    * @memberOf window.jQuery.ready
    * @method 
    * The init method stages the images used in the canvas animation, 
* and launches the javascript setInternal function to continuously redraw the canvas.
*/ function init() { // Assign image source attributes. // sun.src = 'content/images/sun.png'; moon.src = 'content/images/moon.png'; earth.src = 'content/images/earth.png'; // invoke the draw function every 60ms using setInterval. // setInterval(draw, 60); }

 

The draw function, invoked by setInterval every 60 milliseconds, is the function that places the drawn images where they need to go on the canvas, transitions them, rotates them, and takes care of storing and retrieving the state of the canvas during the different drawing phases.  

 

    /** 
    * @memberOf window.jQuery.ready
    * @method 
    * The draw method is invoked every 60ms by the setInterval function.  It is responsible 
* for creating the canvas drawing context, styling it, rotating it, translating
* its location for subsequent drawing of images, and finally drawing the images at their specified locations. */ function draw() { // The 2d context is all that is supported at this time for the canvas element. // var ctx = document.getElementById('canvas').getContext('2d'); // Compositing: there are twelve compositing operations which define how objects are stacked,
// their clipping regions, lightness and darkness of the image colors when overlapping, etc.
// A great reference can be found here: // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing. This particular
// operation forces new objects
to appear behind objects that previously existed within the canvas. // ctx.globalCompositeOperation = 'destination-over'; ctx.clearRect(0, 0, 1024, 768); // clear canvas ctx.fillStyle = 'rgba(0,0,0,0.4)'; ctx.strokeStyle = 'rgba(0,153,255,0.4)'; // Push the current drawing state, which is a snapshot of all the styles and transformations that have // been applied to this point in the current function, onto the context stack. // ctx.save(); // Move the canvas on the x/y plane 512 points on the x-axis and 385 points on the y-axis. // ctx.translate(512, 385); // Draw earth image. // var time = new Date(); ctx.rotate(((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds()); // Move the canvas again on the x/y plane. This translate operation starts where the last translate // operation left off. Excellent explanation of canvas translation:
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations
// ctx.translate(325, 0); // We'll need to return to this state to rotate the moon at a much slower pace. It takes the moon about
// 27.5 days to revolve around the earth, after all!
// ctx.save(); // We've placed the earth where it needs to go, now rotate it in place really fast since the earth's
// orbital period is about 365 days.
// ctx.rotate(((4 * Math.PI) / 1.001) * time.getSeconds() + ((4 * Math.PI) / 1.001) * time.getMilliseconds()); // ctx.fillRect(0, -25, 75, 60); // Shadow ctx.drawImage(earth, -25, -25); // return to the point in the animation prior to the last save operation ... // ctx.restore(); // Moon: before drawing the moon, save the state of the drawing context again. // ctx.save(); ctx.rotate(((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds()); ctx.translate(0, 80); // We've placed the moon where it needs to go, now rotate it in place. // ctx.rotate(((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds()); ctx.drawImage(moon, -10, -10); // pop a drawing state ... // ctx.restore(); // pop another drawing state ... // ctx.restore(); // Draw orbital path ... // ctx.beginPath(); ctx.arc(512, 385, 325, 0, (Math.PI * 2), false); // Earth orbit ctx.stroke(); // Draw sun image. // ctx.drawImage(sun, 412, 285); }

 

There is a combination of translating and rotating going on in the above function.  Note the rotate operation takes into account the current time so that the earth will take a total of 60 seconds to rotate 360 degrees.  The rotate function takes a value of radians as an argument.  The state of the canvas needs to be restored at times.  The restore operation returns the canvas to the last saved state.  Of course, the operations between save and restore are still executed.