Back

Transformations

So far, every shape you've drawn has been placed at exact pixel coordinates. That works fine for simple scenes, but it gets painful fast. What if you want to draw the same house in five different places? Or rotate a shape around its centre? Transformations let you move, rotate, and scale the entire coordinate system instead of recalculating every point by hand.

The coordinate system

By default, the canvas origin (0, 0) is in the top-left corner. X increases to the right, Y increases downward. Every transform you apply — translate, rotate, scale — modifies this coordinate system. You're not moving the shapes, you're moving the “grid paper” underneath them.

JavaScript

translate(x, y)

ctx.translate(x, y) shifts the origin of the coordinate system. After calling it, (0, 0) is no longer in the top-left — it's wherever you moved it to. This is incredibly useful when you have a drawing routine (like a house) and want to stamp it in multiple locations.

JavaScript

Notice that the second translate(120, 30) is relative to the already-shifted origin, not the top-left corner. Transforms are cumulative — they stack on top of each other.

rotate(angle)

ctx.rotate(angle) rotates the coordinate system around the current origin. The angle is in radians (not degrees). A key gotcha: rotation always happens around (0, 0) — so if you want to rotate a shape around its own centre, you need to translate to that centre first, then rotate, then draw the shape centred at the origin.

JavaScript

The left side rotates from the corner — notice how the rectangle drifts away. The right side translates to the centre first, so the rectangle spins in place. Try changing the angles or adding more steps to the array.

scale(x, y)

ctx.scale(sx, sy) multiplies all coordinates by the given factors. scale(2, 2) makes everything twice as big. scale(1, -1) flips vertically (mirrors). Like rotation, scaling happens relative to the current origin — so translate first if you want to scale from a specific point.

JavaScript

Negative scale values create mirror effects. Try scale(-1, -1) — it flips both axes, like rotating 180 degrees. Note that scaling also affects line widths and text size.

save() and restore()

Every transform you apply is permanent — they keep stacking. If you translate, rotate, translate again, your coordinate system is a mess. ctx.save() pushes the current state onto a stack, and ctx.restore() pops it back. Think of it like a bookmark: save before you start transforming, restore when you're done, and the canvas is back to where it was.

JavaScript

The top row drifts because each transform stacks. The bottom row stays in a neat line because each square starts from a clean saved state. When in doubt, wrap your drawing code in save() / restore().

Putting it all together

Let's combine everything into a flower pattern. Each petal is the same ellipse, just rotated around a centre point. save() and restore() keep each petal independent. A loop with incrementing hue gives us a colour wheel for free.

JavaScript

Try changing petalCount to 6 or 24. Adjust the scale(1, 0.4) to make fatter or thinner petals. Can you add a second ring of smaller petals at a different radius? What about animating the rotation by incrementing an offset angle?