HTML5 Canvas [19]
In the next section, we will look at some transformations that affect the entire canvas. As a result, if we want to transform only the newly drawn shape, we will have to use the save() and restore() functions.
Simple Canvas Transformations
Transformations on the canvas refer to the mathematical adjustment of physical properties of drawn shapes. The two most commonly used shape transformations are scale and rotate, which we will focus on in this section.
Under the hood, a mathematical matrix operation applies to all transformations. Luckily, you do not need to understand this to use simple Canvas transformations. We will discuss how to apply rotation, translation, and scale transformations by changing simple Canvas properties.
Rotation and Translation Transformations
An object on the canvas is said to be at the 0 angle rotation when it is facing to the left (this is important if an object has a facing; otherwise, we will use this as a guide). Consequently, if we draw an equilateral box (all four sides are the same length), it doesn’t have an initial facing other than one of the flat sides facing to the left. Let’s draw that box for reference:
//now draw a red square
context.fillStyle = "red";
context.fillRect(100,100,50,50);
Now, if we want to rotate the entire canvas 45 degrees, we need to do a couple simple steps. First, we always set the current Canvas transformation to the “identity” (or “reset”) matrix:
context.setTransform(1,0,0,1,0,0);
Because Canvas uses radians, not degrees, to specify its transformations, we need to convert our 45-degree angle into radians:
var angleInRadians = 45 * Math.PI / 180;
context.rotate(angleInRadians);
Lesson 1: Transformations are applied to shapes and paths drawn after the setTransform() or other transformation function is called
If you use this code verbatim, you will see a funny result…nothing! This is because the setTransform() function call only affects shapes drawn to the canvas after it is applied. We drew our square first, then set the transformation properties. This resulted in no change (or transform) to the drawn square. Example 2-7 gives the code in the correct order to produce the expected result, as illustrated in Figure 2-12.
Example 2-7. Simple rotation transformation
function drawScreen() {
//now draw a red square
context.setTransform(1,0,0,1,0,0);
var angleInRadians = 45 * Math.PI / 180;
context.rotate(angleInRadians);
context.fillStyle = "red";
context.fillRect(100,100,50,50);
}
Figure 2-12. Simple rotation transformation
We get a result this time, but it will probably differ from what you expect. The red box is rotated, but it looks like the canvas was rotated with it. The entire canvas did not rotate, only the portion drawn after the context.rotate() function was called. So, why did our square both rotate and move off to the left of the screen? The origin of the rotation was set at the “nontranslated” 0,0 position, resulting in the square rotating from the top left of the entire canvas.
Example 2-8 offers a slightly different scenario: draw a black box first, then set the rotation transform, and finally draw the red box again. See the results in Figure 2-13.
Example 2-8. Rotation and the Canvas state
function drawScreen() {
//draw black square
context.fillStyle = "black";
context.fillRect(20,20,25,25);
//now draw a red square
context.setTransform(1,0,0,1,0,0);
var angleInRadians = 45 * Math.PI / 180;
context.rotate(angleInRadians);
context.fillStyle = "red";
context.fillRect(100,100,50,50);
}
Figure 2-13. Rotation and the Canvas state
The small black square was unaffected by the rotation, so you can see that only the shapes drawn after the context.rotate() function was called were affected.
Again, the red box was moved far off to the