Where a loop and a canvas together make something you could not draw by hand
← Back to Web CodingThere is no circle(). There is arc(), which draws a slice of a circle — and a whole circle is just a slice that goes all the way round.
const ctx = document.getElementById("board").getContext("2d");
ctx.fillStyle = "crimson";
ctx.beginPath();
ctx.arc(80, 120, 50, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = "#1a5490";
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc(220, 120, 50, 0, Math.PI * 2);
ctx.stroke();
Try it — this is live
80, 120the middle of the circle50the radius — half the width0, Math.PI * 2start angle, end angleMath.PI * 2 is a full turn, measured in radians. You do not have to understand radians to use it — 0, Math.PI * 2 means all the way round, and that is the only pair you need for a whole circle.
Try 0, Math.PI instead and you get half. 0, Math.PI / 2 gives you a quarter — a pie slice, once you fill() it.
Here is where drawing with code beats drawing by hand. You do not write a hundred shapes. You write one shape and a loop that moves it.
const ctx = document.getElementById("board").getContext("2d");
for (let i = 0; i < 10; i++) {
ctx.fillStyle = "#1a5490";
ctx.fillRect(10 + i * 30, 100, 20, 40);
}
Try it — this is live
The whole picture is 10 + i * 30. As i counts 0, 1, 2, the x jumps 10, 40, 70 — evenly spaced, for free. Change the 10 to 30 and every square moves at once.
const ctx = document.getElementById("board").getContext("2d");
for (let i = 0; i < 12; i++) {
ctx.fillStyle = `hsl(${i * 30}, 80%, 55%)`;
ctx.beginPath();
ctx.arc(30 + i * 22, 120, 10 + i * 2, 0, Math.PI * 2);
ctx.fill();
}
Try it — this is live
hsl(hue, saturation, lightness) — the hue is an angle round a colour wheel from 0 to 360. Multiply it by the loop counter and you get a rainbow without picking a single colour by hand.
One loop gives you a row. A loop inside a loop gives you a grid.
const ctx = document.getElementById("board").getContext("2d");
for (let row = 0; row < 6; row++) {
for (let col = 0; col < 8; col++) {
if ((row + col) % 2 === 0) {
ctx.fillStyle = "#2c3e50";
} else {
ctx.fillStyle = "#e8e8e8";
}
ctx.fillRect(col * 40, row * 40, 40, 40);
}
}
Try it — this is live
Forty-eight squares from eight lines. The chessboard pattern is the (row + col) % 2 — neighbouring squares always differ by one, so they always land on opposite colours.
const ctx = document.getElementById("board").getContext("2d");
for (let i = 0; i < 40; i++) {
const x = Math.random() * 320;
const y = Math.random() * 240;
const size = Math.random() * 20 + 4;
ctx.fillStyle = `hsl(${Math.random() * 360}, 70%, 60%)`;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
Try it — this is live
Math.random() gives a number from 0 up to 1. Multiply it to stretch it: Math.random() * 320 lands anywhere across the canvas.
Press Run again and you get a different picture from exactly the same code. Every run is a new one — which is how every starfield and every snowstorm in every game is made.
Once a shape has a name you can scatter it about without repeating yourself:
const ctx = document.getElementById("board").getContext("2d");
function star(x, y, size, colour) {
ctx.fillStyle = colour;
ctx.beginPath();
for (let i = 0; i < 10; i++) {
const angle = i * Math.PI / 5 - Math.PI / 2;
const reach = (i % 2 === 0) ? size : size / 2.4;
ctx.lineTo(x + Math.cos(angle) * reach, y + Math.sin(angle) * reach);
}
ctx.closePath();
ctx.fill();
}
star(70, 80, 40, "gold");
star(180, 140, 55, "crimson");
star(270, 60, 30, "#4a90d9");
Try it — this is live
Three stars, three sizes, three colours — and the shape itself is written once. That is the same idea as Lesson 5's functions, pointed at a picture.
arc(x, y, radius, 0, Math.PI * 2) is a whole circle — wrap it in beginPath and fill.i * spacing makes a row; a loop inside a loop makes a grid.hsl(hue, …) gives you a rainbow from the loop counter.Math.random() gives 0 to 1 — multiply to stretch it.