HTML5 Canvas [52]
Applying Rotation Transformations to an Image
In the previous section, we created an animation using tiles from a tile sheet. In this section, we will take it one step further and use the Canvas transformation matrix to rotate our image before drawing it to the canvas. This will allow us to use only a single set of animated tiles for all four (or more) rotated directions in which we would like to display our images. Before we write the code, let’s examine what it will take to rotate our tank animation from the previous section.
NOTE
In Chapter 2, we dove into applying basic transformations when drawing with paths. The same concepts apply to transforming images on the canvas. If you have not read the section Simple Canvas Transformations in Chapter 2, you might want to review it before reading on.
Canvas Transformation Basics
Although we covered basic Canvas transformations in detail in Chapter 2, let’s review what’s necessary to transform an individual object on the canvas. Remember, the canvas is a single immediate-mode drawing surface, so any transformations we make are applied to the entire canvas. In our example, we are drawing two objects. First, we draw a gray background rectangle, and then we copy the current tile from our tile sheet to the desired location. These are two discrete objects, but once they are on the canvas, they are both simply collections of pixels painted on the surface. Unlike Flash or other platforms that allow many separate sprites or “movie clips” to occupy the physical space, there is only one such object on Canvas: the context.
To compensate for this, we create logical display objects. Both the background and the tank are considered separate logical display objects. If we want to draw the tank but rotate it with a transformation matrix, we must separate the logical drawing operations by using the save() and restore() Canvas context functions.
Let’s look at an example where we rotate the tank 90 degrees so it is facing to the right rather than up.
Step 1: Save the current context to the stack
The save() context function will take the current contents of the canvas (in our case the gray background rectangle) and store it away for “safekeeping”:
context.save();
Once we have transformed the tank, we will replace it with the restore() function call.
Step 2: Reset the transformation matrix to identity
The next step in transforming an object is to clear the transformation matrix by passing it values that reset it to the identity values:
context.setTransform(1,0,0,1,0,0)
Step 3: Code the transform algorithm
Each transformation will be slightly different, but usually if you are rotating an object, you will want to translate the matrix to the center point of that object. Our tank will be positioned at 50,50 on the canvas, so we will translate it to 66,66. Since our tank is a 32×32 square tile, we simply add half of 32, or 16, to both the x and y location points:
context.translate(x+16, y+16);
Next, we need to find the angle in radians for the direction we want the tank to be rotated. For this example, we will choose 90 degrees:
var rotation = 90;
var angleInRadians = rotation * Math.PI / 180;
context.rotate(angleInRadians);
Step 4: Draw the image
When we draw the image, we must remember that the drawing’s point of origin is no longer the 50,50 point from previous examples. Once the transformation matrix has been applied to translate to a new point, that point is now considered the 0,0 origin point for drawing.
This can be confusing at first, but it becomes clear with practice. To draw our image with 50,50 as the top-left coordinate, we must subtract 16 from the current position in both the x and y directions:
context.drawImage(tileSheet, sourceX, sourceY,32,32,-16,-16,32,32);
Example 4-7 adds in this rotation code to Example 4-4. When you run the example now, you will see the tank facing to the right.
NOTE
Notice in Example 4-7 that we remove the original