Chapter 49: Canvas Images
Canvas Images (how to load, draw, position, scale, clip, rotate, and animate images in <canvas>) in the clearest, most patient, step-by-step way possible.
Imagine I’m sitting right next to you with my screen 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, just plain English explanations, visual thinking, common beginner traps, and repeated patterns until drawing and controlling images on Canvas feels completely natural and easy.
Canvas Images – From Zero to Confident
1. The single most important sentence about images in Canvas
Images in Canvas are not automatically displayed like <img> tags. You have to:
- Load the image (create an Image object and wait for it to finish loading)
- Draw it manually with ctx.drawImage() whenever you want it to appear
- Redraw it every frame if you want to move, scale, rotate, or animate it
Once drawn, the image becomes just pixels on the canvas bitmap — there is no “image object” you can later say “move this photo 50px right”. You have to erase the old pixels (usually with clearRect) and draw the image again at the new position/scale/rotation.
2. The only command you need to draw images: drawImage()
There are five main overloads of drawImage() — but you will use these three most often:
| Overload (most common first) | What it does | When to use it |
|---|---|---|
| drawImage(img, dx, dy) | Draw full image at position (dx, dy) with its natural size | Quick “paste image here” |
| drawImage(img, dx, dy, dWidth, dHeight) | Draw image at (dx, dy) and force it to this size (scales) | Resize / stretch image |
| drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) | Crop part of source image (sx,sy → sWidth,sHeight) and draw it at (dx,dy) with size dWidth×dHeight | Sprite sheets, cropping, zooming in |
Important rule: drawImage() does NOT wait for the image to load. If you call it before the image is ready → nothing appears (silent failure).
You must wait for img.onload before drawing.
3. Minimal complete image 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 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas – First Image</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> // Step 1: Create an Image object const img = new Image(); img.crossOrigin = 'anonymous'; // needed for external images (CORS) // Step 2: Wait for it to load img.onload = function() { const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); // Step 3: Draw it three different ways // a) Full image at natural size ctx.drawImage(img, 40, 40); // b) Scaled down to 200×150 at position (300,40) ctx.drawImage(img, 300, 40, 200, 150); // c) Cropped: take 300×300 pixels from top-left of source image // and draw it stretched to 250×250 at (40,220) ctx.drawImage(img, 0, 0, 300, 300, // source rectangle (sx,sy, sWidth, sHeight) 40, 220, 250, 250 // destination rectangle (dx,dy, dWidth, dHeight) ); // Label ctx.font = 'bold 20px Arial'; ctx.fillStyle = '#333'; ctx.textAlign = 'center'; ctx.fillText('a) natural size', 140, 30); ctx.fillText('b) scaled', 400, 30); ctx.fillText('c) cropped + stretched', 165, 480); }; // Step 4: Tell the image where to load from img.src = 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=800&auto=format&fit=crop&q=80'; // Optional: show loading message const ctx = document.getElementById('c').getContext('2d'); ctx.font = '24px Arial'; ctx.fillStyle = '#666'; ctx.textAlign = 'center'; ctx.fillText('Loading image...', 300, 200); </script> </body> </html> |
What you should see & remember forever:
- Image appears only afteronload fires
- drawImage(img, dx, dy) → natural size at position
- drawImage(img, dx, dy, dW, dH) → forced size (can stretch/distort)
- 9-argument version → crop source + resize destination (most powerful)
4. Common real-world patterns you’ll reuse
Pattern 1 – Center image perfectly
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
const imgWidth = img.naturalWidth; const imgHeight = img.naturalHeight; const dx = (canvas.width - imgWidth) / 2; const dy = (canvas.height - imgHeight) / 2; ctx.drawImage(img, dx, dy); |
Pattern 2 – Scale to fit canvas while keeping aspect ratio
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const scale = Math.min( canvas.width / img.naturalWidth, canvas.height / img.naturalHeight ); const w = img.naturalWidth * scale; const h = img.naturalHeight * scale; const dx = (canvas.width - w) / 2; const dy = (canvas.height - h) / 2; ctx.drawImage(img, dx, dy, w, h); |
Pattern 3 – Sprite sheet frame (crop one frame)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Assume sprite sheet is 4×4 grid, each frame 64×64 const frameX = 2; // third column const frameY = 1; // second row ctx.drawImage( spritesheet, frameX * 64, frameY * 64, // source top-left 64, 64, // source size 200, 200, 128, 128 // destination position & size ); |
5. Your three tiny practice tasks (10–15 min each)
Task 1 – Centered photo Load any online image Draw it perfectly centered (natural size or scaled to fit)
Task 2 – Photo frame Draw a thick black rounded rectangle Draw the same image inside it (scaled + centered)
Task 3 – Crop zoom Draw the same image three times:
- full image scaled small
- cropped center 50% of image scaled larger
- cropped top-left quarter scaled even larger
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 we must wait for img.onload?
- Difference between 3-arg vs 5-arg vs 9-arg drawImage?
- How to center an image perfectly?
- Keeping aspect ratio when scaling?
- Cropping from sprite sheets?
- Something else?
Tell me — we’ll stay on images until you feel super confident loading, positioning, scaling, and cropping any picture you want.
You’re doing really well — images are one of the most powerful things you can do in Canvas! 🚀
