Academic Block

Drawing Shapes with JavaScript Get Certified

The HTML5 Canvas API lets you draw shapes, lines, and paths directly with JavaScript. In the examples below you will see both the console messages and the actual coloured shapes below the text output.

Getting the Drawing Context

Before you can draw, you need a canvas and its 2D context. The context is the object that has all the drawing methods, and it uses a coordinate system whose origin is the top-left corner.

What this code does: Creates a 400×220 canvas, gets its 2D context and prints the size, which confirms everything is ready. It then draws a light grid with labelled lines every 100 pixels across and every 50 pixels down, so you can see the canvas coordinate system: (0, 0) is the top-left corner, x grows to the right and y grows downward. Keep this picture in mind for every shape in the lessons that follow.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 220;
const ctx = canvas.getContext("2d");

console.log("Canvas size:", canvas.width + " × " + canvas.height);
console.log("2D context is ready!");
console.log("Origin (0, 0) is the TOP-LEFT corner; y grows downward");

// A canvas starts transparent. Draw a coordinate grid so you can see the space.
ctx.strokeStyle = "#cbd5e1";
ctx.lineWidth = 1;
ctx.font = "11px sans-serif";
ctx.fillStyle = "#475569";

for (let x = 0; x <= 400; x += 100) {
    ctx.beginPath();
    ctx.moveTo(x, 0);
    ctx.lineTo(x, 220);
    ctx.stroke();
    ctx.fillText("x=" + x, x + 4, 12);
}

for (let y = 50; y <= 200; y += 50) {
    ctx.beginPath();
    ctx.moveTo(0, y);
    ctx.lineTo(400, y);
    ctx.stroke();
    ctx.fillText("y=" + y, 4, y + 12);
}

showCanvas("A 400x220 canvas with a coordinate grid", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}

Drawing Rectangles

Rectangles have two ready-made methods: fillRect() paints the inside and strokeRect() draws only the outline. Both take (x, y, width, height), where x and y are the top-left corner.

What this code does: Draws two rectangles of the same size side by side: a solid blue one with fillRect() and a red outlined one with strokeRect(), so the difference between fill and stroke is clear. The text output lists the coordinates each rectangle covers, and the picture shows the result.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 220;
const ctx = canvas.getContext("2d");

// Filled rectangle
ctx.fillStyle = "#3b82f6";
ctx.fillRect(40, 40, 150, 100);

// Stroked rectangle
ctx.strokeStyle = "#ef4444";
ctx.lineWidth = 5;
ctx.strokeRect(220, 40, 140, 100);

console.log("Blue filled rectangle: x 40-190, y 40-140");
console.log("Red stroked rectangle: x 220-360, y 40-140 (5px outline, centered on the edge)");

showCanvas("Filled rectangle (left) and stroked rectangle (right)", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}

Drawing Circles

There is no fillCircle() method. Circles are drawn as paths with arc(), then painted with fill() or stroke().

What this code does: Draws two circles with the same radius: a solid green one (a path painted with fill()) and a purple outline (the same kind of path painted with stroke()). Each circle starts with its own beginPath() so the two shapes stay separate. The text output gives the centre and radius of each circle, and the picture shows both.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 220;
const ctx = canvas.getContext("2d");

// Filled circle
ctx.beginPath();
ctx.arc(120, 110, 70, 0, Math.PI * 2);
ctx.fillStyle = "#22c55e";
ctx.fill();

// Stroked circle
ctx.beginPath();
ctx.arc(280, 110, 70, 0, Math.PI * 2);
ctx.strokeStyle = "#8b5cf6";
ctx.lineWidth = 8;
ctx.stroke();

console.log("Green filled circle: center (120, 110), radius 70");
console.log("Purple stroked circle: center (280, 110), radius 70");

showCanvas("Filled circle (left) and stroked circle (right)", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}

Drawing a Triangle

Anything that is not a rectangle or a circle is built as a path: move to a starting point, add lines to other points, close the shape, then fill or stroke it.

What this code does: Builds a triangle from three points with moveTo(), lineTo() and closePath(), fills it with orange, then outlines it in dark brown. The text output lists the three corner points and the picture shows the result. Filling first and stroking second means the outline sits on top of the fill.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 220;
const ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.moveTo(200, 30);      // top
ctx.lineTo(70, 180);      // bottom-left
ctx.lineTo(330, 180);     // bottom-right
ctx.closePath();

ctx.fillStyle = "#f97316";
ctx.fill();
ctx.strokeStyle = "#9a3412";
ctx.lineWidth = 5;
ctx.stroke();

console.log("Corners: (200, 30), (70, 180), (330, 180)");
console.log("Orange fill + dark outline drawn");

showCanvas("A triangle built from three points", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}

Combining Shapes – Simple House

Complex pictures are built from simple shapes. Shapes drawn later are painted on top of shapes drawn earlier, so the order matters.

What this code does: Draws a house from three simple shapes: a yellow rectangle for the walls, a red triangle for the roof and a brown rectangle for the door. The roof is wider than the walls and its base sits exactly on the top edge of the walls. The text output explains the layering and the picture shows the finished house.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 260;
const ctx = canvas.getContext("2d");

// House body
ctx.fillStyle = "#fbbf24";
ctx.fillRect(110, 120, 180, 120);

// Roof
ctx.beginPath();
ctx.moveTo(90, 120);
ctx.lineTo(200, 40);
ctx.lineTo(310, 120);
ctx.closePath();
ctx.fillStyle = "#dc2626";
ctx.fill();

// Door
ctx.fillStyle = "#78350f";
ctx.fillRect(175, 160, 50, 80);

console.log("Layers drawn in order: body, roof, door");
console.log("Simple house drawn successfully!");

showCanvas("A house made of a rectangle, a triangle and a door", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}

Practice: Traffic Light

Put it all together: a body rectangle and three circles, each with its own path. Try changing the colours so only one light is bright.

What this code does: Draws a traffic light from a dark gray rectangle and three circles (red, yellow and green) stacked 80 pixels apart. Each circle has its own beginPath() so each gets its own colour. The text output lists the light positions and the picture shows the finished signal. Practice idea: change two of the colours to a dull gray so only one light is on.

const canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 300;
const ctx = canvas.getContext("2d");

// Body
ctx.fillStyle = "#1f2937";
ctx.fillRect(160, 20, 80, 260);

// Red light
ctx.beginPath();
ctx.arc(200, 70, 28, 0, Math.PI * 2);
ctx.fillStyle = "#ef4444";
ctx.fill();

// Yellow light
ctx.beginPath();
ctx.arc(200, 150, 28, 0, Math.PI * 2);
ctx.fillStyle = "#eab308";
ctx.fill();

// Green light
ctx.beginPath();
ctx.arc(200, 230, 28, 0, Math.PI * 2);
ctx.fillStyle = "#22c55e";
ctx.fill();

console.log("Lights at y = 70 (red), 150 (yellow), 230 (green); all at x = 200");
console.log("Traffic light drawn!");

showCanvas("A traffic light", canvas);

// ===== Helper below is not part of the lesson =====
function showCanvas(label, source) {
    const copy = document.createElement("canvas");
    copy.width = source.width;
    copy.height = source.height;
    copy.getContext("2d").drawImage(source, 0, 0);
    copy.style.maxWidth = "100%";
    setTimeout(() => {
        const box = document.createElement("div");
        box.className = "demo-canvas-box";
        box.innerHTML = "<p class='demo-canvas-label'>" + label + "</p>";
        box.appendChild(copy);
        document.getElementById("previewContent").appendChild(box);
    }, 0);
}
Tip: Click “Test My Code” and look at the picture while you read the numbers: every coordinate in the code can be found in the drawing. Change a number, run it again, and see what moves.

🧪 Test Your JavaScript Code

Edit the code on the left and click “Run Code” to see the console output on the right.

📝 JavaScript Code
👁 Console Output

Click “Run Code” to see the output here.

Ctrl + Enter to run code Esc to close