Chapter 58: Clock Hands
Clock Hands in the most detailed, clear, and patient way possible.
Imagine we’re sitting together at a desk. I’m your favorite teacher who wants you to really understand how the moving hands of an analog clock are drawn and animated — not just copy-paste a finished clock, but know exactly why every line is positioned, rotated, and styled the way it is.
Today we focus only on the hands (hour, minute, second) — the moving parts that show the time. We assume the clock face (background circle, ticks, numbers) is already drawn once (we covered that in the previous lesson).
We will build this step by step:
- Understand the math of angles
- Calculate hand positions every second
- Draw each hand with correct length, thickness, and style
- Animate them smoothly
- Add realistic details (tapered hands, center dot, shadows)
Clock Hands – Complete Explanation & Build-Along
1. The single most important mental model
Each hand is a straight line rotated around the center of the clock.
- The clock is a circle → 360°
- There are 12 hours → each hour mark is 30° apart (360 ÷ 12 = 30)
- In Canvas (and most graphics systems):
- 0° is at the right (3 o’clock)
- Angles increase clockwise
- But 12 o’clock is at the top → we subtract 90° (or Math.PI/2 radians) to make 0° point up
Key angle formulas (you will use these every time):
|
0 1 2 3 4 5 6 7 8 9 |
// All angles in radians const secondAngle = seconds * (Math.PI / 30) - Math.PI / 2; const minuteAngle = (minutes + seconds / 60) * (Math.PI / 30) - Math.PI / 2; const hourAngle = (hours % 12 + minutes / 60) * (Math.PI / 6) - Math.PI / 2; |
Why the numbers?
- Seconds: 60 seconds → 6° per second → Math.PI / 30 (since 360° = 2π radians)
- Minutes: 60 minutes → 6° per minute → same Math.PI / 30 + tiny second adjustment
- Hours: 12 hours → 30° per hour → Math.PI / 6
2. Three different hands — different lengths & thicknesses
| Hand | Length (from center) | Thickness (lineWidth) | Color (typical) | Speed / Update frequency |
|---|---|---|---|---|
| Second | longest (~80–90% of radius) | thinnest (4–6 px) | bright red | every second |
| Minute | medium (~65–75%) | medium (8–12 px) | white/silver | every second |
| Hour | shortest (~50–60%) | thickest (14–20 px) | white/silver | every second (smooth) |
3. Step-by-step: How to draw one hand (the pattern)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function drawHand(angle, length, width, color) { ctx.save(); // remember current state ctx.translate(cx, cy); // move origin to clock center ctx.rotate(angle); // rotate the coordinate system ctx.beginPath(); ctx.moveTo(0, -10); // start a bit above center (for taper) ctx.lineTo(0, -length); // draw to end of hand ctx.strokeStyle = color; ctx.lineWidth = width; ctx.lineCap = 'round'; ctx.stroke(); ctx.restore(); // go back to normal coordinates } |
Why this pattern?
- translate(cx, cy) → makes (0,0) the center — rotation is now around center
- rotate(angle) → rotates the whole paper
- We draw the hand straight up (negative y) → rotation makes it point correctly
- save() / restore() → protects the rest of the canvas from rotation
4. Full clock hands 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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas Clock – Hands Only</title> <style> body { margin: 0; height: 100vh; display: flex; justify-content: center; align-items: center; background: #0d1117; } canvas { border: 6px solid #30363d; border-radius: 50%; box-shadow: 0 0 80px rgba(0,0,0,0.9); } </style> </head> <body> <canvas id="clock" width="420" height="420"></canvas> <script> const canvas = document.getElementById('clock'); const ctx = canvas.getContext('2d'); const cx = canvas.width / 2; const cy = canvas.height / 2; const radius = canvas.width / 2 - 40; function drawHand(angle, length, width, color) { ctx.save(); ctx.translate(cx, cy); ctx.rotate(angle); ctx.beginPath(); ctx.moveTo(0, -10); // start slightly above center ctx.lineTo(0, -length); ctx.strokeStyle = color; ctx.lineWidth = width; ctx.lineCap = 'round'; ctx.stroke(); ctx.restore(); } function drawHands() { const now = new Date(); const seconds = now.getSeconds(); const minutes = now.getMinutes(); const hours = now.getHours() % 12; // Second hand const secAngle = seconds * (Math.PI / 30) - Math.PI / 2; drawHand(secAngle, radius - 40, 5, '#F44336'); // Minute hand const minAngle = (minutes + seconds / 60) * (Math.PI / 30) - Math.PI / 2; drawHand(minAngle, radius - 80, 10, '#c9d1d9'); // Hour hand const hrAngle = (hours + minutes / 60) * (Math.PI / 6) - Math.PI / 2; drawHand(hrAngle, radius - 140, 16, '#c9d1d9'); // Center dot ctx.beginPath(); ctx.arc(cx, cy, 12, 0, Math.PI * 2); ctx.fillStyle = '#c9d1d9'; ctx.fill(); } // Redraw hands every second setInterval(drawHands, 1000); // First draw drawHands(); </script> </body> </html> |
What you should see & remember forever:
- Red second hand moves fastest
- White minute & hour hands move slower
- All hands rotate around the center (not around (0,0))
- save() / restore() + translate + rotate pattern is the standard way
- Hands are just thick lines drawn from near-center to near-edge
5. Your mini homework (try tonight – 15–20 minutes)
- Make the second hand thinner and add a small counter-weight (short line on opposite side)
- Make the hour hand shorter and thicker than the minute hand
- Add a small white circle at the end of each hand (like a tip)
- (Bonus) Make the second hand smoothly animated instead of jumping every second (use requestAnimationFrame + milliseconds)
Paste your modified code here if you want feedback — I’ll review it like we’re pair-programming together 😄
Any part confusing?
- Why we subtract Math.PI / 2 from every angle?
- How the translate → rotate → translate back pattern works?
- Why different lengths & thicknesses for each hand?
- How to make smooth second-hand animation?
- Something else?
Tell me — we’ll zoom in until the clock hands feel perfect to you.
You just built the moving heart of a real analog clock — the face + hands together make a complete working clock! 🚀
