Chapter 50: Canvas Transformations
Canvas Transformations in the clearest, most patient, step-by-step way possible.
Imagine I’m sitting right next to you with my laptop open. We’re going to build every concept together — slowly, with tiny complete runnable examples you can copy-paste immediately. No skipping steps, no magic formulas you don’t understand, just plain English explanations, visual thinking, common beginner traps, and repeated patterns until transformations feel completely natural and easy to control.
Canvas Transformations – From Zero to Confident
1. The single most important sentence about transformations in Canvas
Transformations in Canvas do NOT change the coordinates you already wrote in your code. They change how the painter interprets future coordinates — they move, rotate, scale, or skew the entire coordinate system from that moment onward.
In other words:
- You don’t rewrite x=100 to x=200 to move something right.
- You tell the painter: “From now on, move your whole paper 100 pixels right — so when I say x=100, you actually paint at 200.”
This is very powerful — but also very confusing at first because the order matters a lot, and changes are cumulative until you reset them.
2. The four most important transformation commands (you will use these 95% of the time)
| Command | What it does to the coordinate system | Syntax example | Most common use case |
|---|---|---|---|
| translate(x, y) | Moves origin (0,0) by x right and y down | ctx.translate(150, 80) | Shift everything without changing coordinates |
| rotate(angle) | Rotates the whole canvas around current origin | ctx.rotate(Math.PI / 4) (45°) | Rotate shapes, text, icons |
| scale(sx, sy) | Scales everything horizontally (sx) and vertically (sy) | ctx.scale(2, 2) (double size) | Zoom in/out, stretch, mirror |
| save() + restore() | Remembers current transformation state | ctx.save(); … ctx.restore(); | Apply temporary changes, then go back |
Very important rule (write this down):
Transformations are cumulative and applied in reverse order of how you write them.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
ctx.translate(100, 50); // first move ctx.rotate(Math.PI / 4); // then rotate ctx.scale(1.5, 1.5); // then scale // When you draw at (0,0), Canvas actually: // 1. scales it (last transformation) // 2. rotates it // 3. translates it (first transformation) |
3. Minimal complete transformation example (copy → run)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas – First Transformations</title> <style> canvas { border: 1px solid #ccc; background: #f8f9fa; display: block; margin: 40px auto; } </style> </head> <body> <canvas id="c" width="600" height="400"></canvas> <script> const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); // Original shape – no transformation ctx.fillStyle = '#4CAF50'; ctx.fillRect(0, 0, 100, 60); ctx.fillStyle = '#333'; ctx.font = '16px Arial'; ctx.fillText('Original (0,0)', 50, 80); // Save state before we start transforming ctx.save(); // Apply transformations ctx.translate(250, 150); // move origin to (250,150) ctx.rotate(Math.PI / 6); // rotate 30° clockwise ctx.scale(1.8, 1.8); // make 1.8× bigger // Draw the same rectangle — but now transformed ctx.fillStyle = '#2196F3'; ctx.fillRect(0, 0, 100, 60); // ← still written as (0,0) ! // Restore original state (very important!) ctx.restore(); // Label the transformed one ctx.fillStyle = '#333'; ctx.font = '16px Arial'; ctx.fillText('Translated → Rotated → Scaled', 250, 260); </script> </body> </html> |
What you should see & remember forever:
- Green rectangle → drawn at original (0,0) → top-left corner
- Blue rectangle → same code (0,0) → but appears moved, rotated, and scaled → because the coordinate system was transformed before drawing
Key rule: You write coordinates as if nothing changed — transformations affect how the painter interprets those numbers.
4. Example 2 – Rotate around center (most common real-world pattern)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<canvas id="c2" width="600" height="400"></canvas> <script> const canvas = document.getElementById('c2'); const ctx = canvas.getContext('2d'); const cx = 300; const cy = 200; // Draw center cross ctx.strokeStyle = '#999'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(cx, 0); ctx.lineTo(cx, canvas.height); ctx.moveTo(0, cy); ctx.lineTo(canvas.width, cy); ctx.stroke(); // Save state ctx.save(); // Move origin to center → rotate around center → move back ctx.translate(cx, cy); ctx.rotate(Math.PI / 4); // 45° ctx.translate(-cx, -cy); ctx.fillStyle = '#F44336'; ctx.fillRect(cx - 100, cy - 30, 200, 60); ctx.restore(); ctx.fillStyle = '#333'; ctx.font = '20px Arial'; ctx.textAlign = 'center'; ctx.fillText('Rotated 45° around center', cx, cy + 120); </script> |
Key pattern for rotation around any point (memorize this):
|
0 1 2 3 4 5 6 7 8 9 10 11 |
ctx.save(); ctx.translate(pointX, pointY); // move origin to rotation center ctx.rotate(angle); // rotate ctx.translate(-pointX, -pointY); // move origin back // now draw normally ctx.restore(); |
5. Your three tiny practice tasks (10–15 min each)
Task 1 – Simple moved & scaled box Draw a red rectangle at (0,0) 100×60 Then draw the same rectangle code again after translating 200 right and scaling 1.5×
Task 2 – Rotated text around center Draw “Canvas” centered in the canvas Then draw the same text code again after rotating 90° around the canvas center
Task 3 – Spinning wheel illusion Draw a black circle at center Draw 8 thin white rectangles around it (like spokes) Rotate the whole group by 45° → you’ll see the wheel look rotated
Paste any of them here when you finish — I’ll review it like we’re pair-programming together.
Which part still feels a little slippery?
- Why transformations affect future drawings, not past ones?
- The order of translate → rotate → translate back for center rotation?
- Why save() and restore() are so important?
- How scale affects position (not just size)?
- Something else?
Tell me — we’ll stay on transformations until you feel super confident moving, rotating, and scaling anything you draw.
You’re doing really well — transformations are one of the most powerful (and most confusing at first) parts of Canvas — but once it clicks, you can make incredibly dynamic graphics! 🚀
