Skip to content

Clock Intro

In this tutorial series, we’ll build an analog clock using the HTML5 Canvas API and modern JavaScript. We’ll cover setting up the canvas, drawing the clock face, adding numbers, and finally, drawing and animating the clock hands.

Part I: Creating the Canvas and Basic Clock Face

Section titled “Part I: Creating the Canvas and Basic Clock Face”

The first step is to set up our HTML page with a <canvas> element. This element will be our drawing surface. We’ll then use JavaScript to get a reference to this canvas and its 2D rendering context, which provides the methods for drawing.

Here’s a complete HTML structure with a 300x300 pixel canvas. The JavaScript initializes the canvas, sets its origin to the center, and draws a simple white circle for the clock face.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Clock - Part 1: Face</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f0f0f0; /* Light gray background for the page */
}
canvas {
background-color: #333; /* Dark background for the canvas itself */
border-radius: 50%; /* Make the canvas element appear round */
}
</style>
</head>
<body>
<canvas id="canvas" width="300" height="300">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let radius = canvas.height / 2; // Calculate radius based on canvas height
// Move the drawing context's origin (0,0) to the center of the canvas
ctx.translate(radius, radius);
// Reduce the clock radius slightly to ensure it fits well within the canvas bounds
radius *= 0.90;
// Function to draw the clock face
function drawFace(context, r) {
// Begin a new path for the main circle
context.beginPath();
// Draw the outer circle for the clock face
context.arc(0, 0, r, 0, 2 * Math.PI); // x, y, radius, startAngle, endAngle
context.fillStyle = "white";
context.fill();
// Add a border to the clock face
context.strokeStyle = '#333'; // Color for the border
context.lineWidth = r * 0.1; // Border width relative to radius
context.stroke();
// Add a center dot (pivot for hands)
context.beginPath(); // Start a new path for the center dot
context.arc(0, 0, r * 0.05, 0, 2 * Math.PI);
context.fillStyle = '#333'; // Color for the center dot
context.fill();
}
// Draw the clock face
drawFace(ctx, radius);
</script>
</body>
</html>

const canvas = document.getElementById(“canvas”); const ctx = canvas.getContext(“2d”); let radius = canvas.height / 2; ctx.translate(radius, radius); radius *= 0.90;

function drawFace(context, r) { context.beginPath(); context.arc(0, 0, r, 0, 2 * Math.PI); context.fillStyle = “white”; context.fill();

// Modern addition: Clock border context.strokeStyle = ‘#333’; context.lineWidth = r * 0.1; context.stroke();

// Modern addition: Center dot context.beginPath(); context.arc(0, 0, r * 0.05, 0, 2 * Math.PI); context.fillStyle = ‘#333’; context.fill(); }

drawFace(ctx, radius);

  1. HTML Setup:
    • <canvas id="canvas" width="300" height="300">: This creates the canvas element with a unique ID and specified dimensions. The text inside is a fallback for older browsers.
    • Basic CSS is added in <style> for better page presentation and to give the canvas itself a dark background and rounded appearance matching the clock face.
<canvas id="canvas" width="300" height="300">
Your browser does not support the HTML5 canvas tag.
</canvas>
  1. JavaScript Initialization:
    • const canvas = document.getElementById("canvas");: Gets a reference to the <canvas> DOM element using its ID.
    • const ctx = canvas.getContext("2d");: Retrieves the 2D rendering context, which is the object used for all drawing operations.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
  1. Radius and Origin Translation:
    • let radius = canvas.height / 2;: Calculates the initial radius of the clock based on the canvas height. Using let as radius will be modified.
    • ctx.translate(radius, radius);: This is a key step. It moves the (0,0) coordinate origin of the canvas from the top-left corner to the center of the canvas. This simplifies all subsequent drawing calculations, as we can now draw relative to the clock’s center.
let radius = canvas.height / 2;
ctx.translate(radius, radius);
Using the canvas dimensions (e.g., canvas.height) to calculate the clock radius allows the clock to scale appropriately if the canvas size changes.
  1. Adjusting Radius for Padding:
    • radius *= 0.90;: Reduces the clock radius to 90% of its initial value. This creates a small padding, ensuring the clock face doesn’t touch the edges of the canvas element, which looks aesthetically better.
radius *= 0.90; // equivalent to radius = radius * 0.90;
  1. drawFace(context, r) Function:
    • This function encapsulates the logic for drawing the clock’s face.
    • context.beginPath(): It’s good practice to call this before starting a new shape or path to avoid unintended connections to previous drawings.
    • context.arc(0, 0, r, 0, 2 * Math.PI);: Draws a full circle. (0,0) is the center (due to translate), r is the radius, 0 is the start angle, and 2 * Math.PI is the end angle (a full circle in radians).
    • context.fillStyle = "white"; context.fill();: Sets the fill color to white and fills the circle.
    • Enhancements: The updated function also draws a border around the clock face (strokeStyle, lineWidth, stroke()) and a small central dot, which serves as the pivot point for the clock hands. These are common features in analog clocks.
function drawFace(context, r) {
// Main circle
context.beginPath();
context.arc(0, 0, r, 0, 2 * Math.PI);
context.fillStyle = "white";
context.fill();
// Border
context.strokeStyle = '#333';
context.lineWidth = r * 0.1;
context.stroke();
// Center dot
context.beginPath();
context.arc(0, 0, r * 0.05, 0, 2 * Math.PI);
context.fillStyle = '#333';
context.fill();
}

Finally, drawFace(ctx, radius); is called to actually draw the clock face on the canvas.

This establishes the foundation for our clock. In the next parts, we’ll add numbers and the clock hands.