JavaScript Canvas Transformations 
Written by Ian Elliot  
Monday, 02 March 2020  
Page 2 of 2
If you want to draw the second rectangle at 200,50 in the original co‑ordinate system you have to use a more complicated algorithm. First move the origin of the coordinate system to 200,50, rotate 45 degrees, then draw the second rectangle at 0,0. ctx.setTransform(1,0,0,1,0,0); ctx.fillRect (0, 0, 50, 50); ctx.translate(200,50); ctx.rotate(Math.PI/4); ctx.fillRect (0, 0, 50, 50); Notice that the second rectangle is rotated about its top left corner. Of course as you have changed the coordinate system this affects anything you subsequently draw. The solution is to return the coordinate system back to what it was before you changed it. In this case it is simple as we are using the default coordinate system and we can set the default coordinate system simply by setting the transformation matrix back to the identity using: ctx.setTransform(1,0,0,1,0,0); If you aren’t using the default coordinate system then you can save and restore the current transform matrix using the save and restore functions, see later. There is a currentTransform property which can be read and written to access the current transform matrix. The only problem is that this isn’t well supported at the time of writing and is best avoided. A Logical Approach to TransformsTransformations are key to making drawing on Canvas easy, but if you think about things in the wrong way it is very easy to make mistakes. There are two ways to think about transformations – active and passive – and humans tend to prefer thinking about active transformations. An active transformation is one that actually changes what you have already drawn. Unfortunately, Canvas transformations are passive and change the co‑ordinate system so that what is drawn next is changed and what is already drawn is unchanged. As already mentioned, in general we find it easier to imagine what happens with active transformations. For example, one approach to working with transformations is to draw everything centered on the origin, and then translate, scale and rotate it to its final position. This is a good approach, but if you think of it as an active transformation then it doesn’t work with Canvas. For example, to draw the rectangle: ctx.fillRect (200,350,160,160); rotated through 45 degrees you would first draw a unit square centered on the origin, then you would then scale it to its desired size, rotate it about the origin and finally you would move it to its correct location: ctx.fillRect (0.5, 0.5, 1, 1); ctx.scale(160,160); ctx.rotate(Math.PI/4); ctx.translate(200,350); These are imagined to be active transformations and of course they don’t work as imagined. The reason is that we have been transforming the object: draw a square, scale the square, rotate it and move it to the desired location. However, Canvas transformations don't transform objects but the co‑ordinate system. You can immediately see that this means you should draw the square last after you have performed all of the transformations. Indeed this is the rule:
So the correct transformation sequence is: ctx.translate(200,350); ctx.rotate(Math.PI/4); ctx.scale(160,160); ctx.fillRect (0.5, 0.5, 1, 1); Notice that when you do a scale this applies to any strokeWidth you may set, i.e. double the scale and a strokeWidth of 1 becomes an effective strokeWidth of 2. To set it you need to use an explicit setting of lineWidth and you also need to remember that you are working in the current coordinate system. For example to set a line width of 1 pixel in the previous example after a scaling of 160 you would need to use: ctx.lineWidth=1/160; You can always work out the transformation sequence you need by considering the graphical object, working out the transforms needed to change it to what you want and applying them in the reverse order. This leads to the approach where every object is drawn centered on the origin at unit size and in a “normal” orientation. The object is then transformed into the size, location and orientation you need. Some programmers take to this idea and think it is the best and only way to do logical systematic graphics, some adopt it a little bit, and others draw things where they are needed in the size and orientation needed. Included in book but not in this extract
Summary
Now available as a paperback or ebook from Amazon.JavaScript Bitmap Graphics


Last Updated ( Monday, 02 March 2020 ) 