Chapter 54: Canvas Clock
What is a “Canvas Clock”?
A Canvas Clock means using the HTML <canvas> element + JavaScript to draw a classic analog clock (round face, hour/minute/second hands, numbers, ticks) that updates in real time every second, just like a real wall clock.
Why do we build this?
- It is one of the most asked Canvas projects in college (BCA/B.Tech/MCA), interviews, and portfolio work.
- It teaches almost everything important in Canvas: shapes (circle, lines, arcs), text, transformations (rotate), time/date handling, animation loop (requestAnimationFrame), clearing & redrawing, math (angles, trigonometry), shadows, gradients, etc.
- Once you finish this, you can easily make digital clocks, countdown timers, progress clocks, world clocks, etc.
We will build it step by step, from empty canvas → final working clock.
Step 1 – Basic Canvas Setup (Copy-Paste & Run)
Create a file called canvas-clock.html and paste this:
|
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 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas Analog Clock – Step by Step</title> <style> body { background: #f0f4f8; font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; } canvas { border: 6px solid #2c3e50; border-radius: 50%; background: #ffffff; box-shadow: 0 10px 30px rgba(0,0,0,0.3); } h1 { color: #34495e; margin-bottom: 10px; } p { color: #7f8c8d; text-align: center; max-width: 600px; } </style> </head> <body> <h1>Building an Analog Clock with Canvas</h1> <p>We will draw this clock step by step — run the code after each section to see progress.</p> <canvas id="clock" width="400" height="400"></canvas> <script> const canvas = document.getElementById('clock'); const ctx = canvas.getContext('2d'); // Center point of clock const centerX = canvas.width / 2; const centerY = canvas.height / 2; const radius = 180; // clock face radius // Helper function to draw the clock face (we'll fill this later) function drawClockFace() { // Background circle ctx.beginPath(); ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); ctx.fillStyle = '#ffffff'; ctx.fill(); // Outer border ctx.strokeStyle = '#2c3e50'; ctx.lineWidth = 12; ctx.stroke(); // Inner light border ctx.beginPath(); ctx.arc(centerX, centerY, radius - 6, 0, Math.PI * 2); ctx.strokeStyle = '#bdc3c7'; ctx.lineWidth = 4; ctx.stroke(); } // Draw initial face drawClockFace(); </script> </body> </html> |
What you see so far:
- Nice round white clock face with thick dark border + thin inner border
- Centered on page with shadow
This is our base clock face — we will add numbers, ticks, hands, and animation on top.
Step 2 – Draw Clock Numbers (12, 3, 6, 9, etc.)
Add this function below drawClockFace() and call it after:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function drawNumbers() { ctx.font = 'bold 28px Arial'; ctx.fillStyle = '#2c3e50'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; for (let i = 1; i <= 12; i++) { const angle = (i * 30 - 90) * Math.PI / 180; // -90 to start at 12 o'clock const x = centerX + (radius - 40) * Math.cos(angle); const y = centerY + (radius - 40) * Math.sin(angle); ctx.fillText(i.toString(), x, y); } } // Add this line after drawClockFace() in the script: drawNumbers(); |
Explanation:
- 12 numbers × 30° = 360° (full circle)
- -90 shifts so 12 is at top (0° is right in math, but clocks start at top)
- radius – 40 places numbers inside the outer rim
Refresh → you now see numbers 1 to 12!
Step 3 – Draw Minute & Hour Ticks
Add this function:
|
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 |
function drawTicks() { for (let i = 0; i < 60; i++) { const angle = (i * 6 - 90) * Math.PI / 180; // 6° per minute const isHour = i % 5 === 0; // every 5 minutes = hour mark const innerRadius = radius - (isHour ? 30 : 15); const outerRadius = radius - 5; const x1 = centerX + innerRadius * Math.cos(angle); const y1 = centerY + innerRadius * Math.sin(angle); const x2 = centerX + outerRadius * Math.cos(angle); const y2 = centerY + outerRadius * Math.sin(angle); ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.strokeStyle = isHour ? '#2c3e50' : '#7f8c8d'; ctx.lineWidth = isHour ? 6 : 3; ctx.stroke(); } } // Add this after drawNumbers(): drawTicks(); |
Refresh → now you have 60 minute ticks (longer & thicker every 5 minutes for hours)
Step 4 – Draw Clock Hands (Hour, Minute, Second)
Add this function:
|
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 |
function drawHands() { const now = new Date(); const seconds = now.getSeconds(); const minutes = now.getMinutes(); const hours = now.getHours() % 12; // 12-hour format // Second hand (thin & red) let angle = (seconds * 6 - 90) * Math.PI / 180; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo( centerX + 160 * Math.cos(angle), centerY + 160 * Math.sin(angle) ); ctx.strokeStyle = '#e74c3c'; ctx.lineWidth = 4; ctx.lineCap = 'round'; ctx.stroke(); // Minute hand (thicker & dark) angle = (minutes * 6 + seconds * 0.1 - 90) * Math.PI / 180; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo( centerX + 130 * Math.cos(angle), centerY + 130 * Math.sin(angle) ); ctx.strokeStyle = '#2c3e50'; ctx.lineWidth = 10; ctx.stroke(); // Hour hand (short & thickest) angle = (hours * 30 + minutes * 0.5 + seconds * 0.0083 - 90) * Math.PI / 180; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo( centerX + 80 * Math.cos(angle), centerY + 80 * Math.sin(angle) ); ctx.strokeStyle = '#2c3e50'; ctx.lineWidth = 16; ctx.stroke(); // Center dot (cover hand origins) ctx.beginPath(); ctx.arc(centerX, centerY, 12, 0, Math.PI * 2); ctx.fillStyle = '#2c3e50'; ctx.fill(); } |
Step 5 – Make it Live (Animation Loop)
Replace the initial drawing calls at the bottom with this:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function drawClock() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawClockFace(); drawTicks(); drawNumbers(); drawHands(); } drawClock(); // first draw setInterval(drawClock, 1000); // update every second |
Refresh → now you have a live, ticking analog clock!
6. Teacher’s Quick Tips (Hyderabad Student Style 😄)
- Angles: -90 * Math.PI / 180 to start at 12 o’clock (math 0° is right, clock 0 is top)
- Hands length: hour shortest, minute longer, second longest
- clearRect() every frame — otherwise old hands stay visible
- Common mistake #1: Forget clearRect() → hands leave trails
- Common mistake #2: Wrong angle calculation → hands point wrong direction
- Pro tip: Add smooth second hand motion with requestAnimationFrame instead of setInterval for silky animation
- Pro tip 2: Use Date.now() instead of new Date() for sub-second precision
Understood how to build a Canvas Clock fully now? This project teaches almost everything important in Canvas: shapes, arcs, text, transformations (rotate), animation loop, time handling, math (trigonometry), clearing & redrawing.
Tell me what you want next — we can build on this:
- Add digital time display below?
- Make second hand smooth (requestAnimationFrame)?
- Add date & day of week?
- World clock (multiple time zones)?
- Animated clock with ticking sound?
- Or 15-question Canvas clock quiz?
Just say — we can make it even better together! 🚀
