JavaScript Canvas Transformations
Written by Ian Elliot
Monday, 02 March 2020
Article Index
JavaScript Canvas Transformations
Active Transformations

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 co-ordinate 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 co-ordinate system this affects anything you subsequently draw. The solution is to return the co-ordinate system back to what it was before you changed it.

In this case it is simple as we are using the default co-ordinate system and we can set the default co-ordinate 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 co-ordinate 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 Transforms

Transformations 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:

• Do everything you would have done to the geometric shape using active transformations in the reverse order when changing the co‑ordinate system.

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 co-ordinate 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

• Plotting A Graph
• Stack of States
• Active Transformations and State

## Summary

• Transformations include rotation, scaling and translation.

• You can write all three as a simple matrix if you use homogeneous co-ordinates (x,y,1)

• You can set the transform matrix directly or use one of the utility methods to set scaling, rotation and translation.

• The order in which you apply transformations makes a difference.

• You can think of transformations as actively moving something or just changing the co-ordinates. Canvas transforms change the co-ordinate system.

• If you want to think “actively” then think of the transformations you want to perform on a shape and then apply them in the reverse order before drawing the shape.

• One approach to organizing graphics is to draw everything centered on the origin and at unit scale and then use transformations to size, rotation and position where you really want to draw the shape.

• You can change the co-ordinate system in use to anything that suits the current drawing task.

• You can save the drawing state before changing the co-ordinate system so that it can be restored.

• The drawing state includes the current transformation matrix, clipping region and all drawing attributes.

## JavaScript Bitmap GraphicsWith Canvas

#### Contents

1. JavaScript Graphics
2. Getting Started With Canvas
3. Drawing Paths
Extract: Basic Paths
Extract: Bezier Curves
4. Stroke and Fill
Extract: Stroke Properties
Extract: Fill and Holes
5. Transformations
Extract: Transformations
Extract: Custom Coordinates
Extract  Graphics State
6. Text
Extract: Text, Typography & SVG
Extract: Unicode
7. Clipping, Compositing and Effects
Extract: Clipping & Basic Compositing
8. Generating Bitmaps
Extract:  Introduction To Bitmaps
Extract :  Animation
9. WebWorkers & OffscreenCanvas
Extract: Web Workers **NEW!
Extract: OffscreenCanvas
10. Bit Manipulation In JavaScript
Extract: Bit Manipulation
11. Typed Arrays
12. Files, blobs, URLs & Fetch
Extract: Blobs & Files
13. Image Processing
Extract: ImageData
Extract: The Filter API
14. 3D WebGL
Extract: WebGL 3D
15. 2D WebGL
Extract: WebGL Convolutions

<ASIN:1871962625>

<ASIN:B07XJQDS4Z>

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>