Lesson 10 of 11JavaScript
JavaScript · Lesson 10 · 35 minutes
Drawing with canvas
What you'll learn
- Paint rectangles and circles on a drawing area (canvas)
- Draw patterns with loops
- Change a drawing with a click
A canvas in the browser
With <canvas> your page gets a drawing area. You paint on it with JavaScript – pixel by pixel, like on paper. Lots of browser games work exactly like this.
First you get the pen: getContext("2d"). With it you choose a colour and paint. Just like the Codelix game module, (0, 0) is at the top left, and y points down:
<canvas id="picture" width="300" height="200"></canvas>
<script>
const pen = document.querySelector("#picture").getContext("2d");
pen.fillStyle = "skyblue";
pen.fillRect(0, 0, 300, 200); // sky
pen.fillStyle = "forestgreen";
pen.fillRect(0, 150, 300, 50); // meadow
pen.fillStyle = "gold";
pen.beginPath();
pen.arc(240, 50, 30, 0, Math.PI * 2);
pen.fill(); // sun
</script>| Command | What it does |
|---|---|
pen.fillStyle = "red" | choose a fill colour |
pen.fillRect(x, y, width, height) | filled rectangle |
pen.beginPath() … pen.fill() | start a shape and fill it |
pen.arc(x, y, radius, 0, Math.PI * 2) | circle (a full arc) |
pen.font = "24px sans-serif" | choose a font |
pen.fillText("Hello", x, y) | paint text |
Patterns with loops
A loop paints lots of shapes at once. Here you get a chessboard: with % you decide whether a square is light or dark:
<canvas id="board" width="240" height="240"></canvas>
<script>
const pen = document.querySelector("#board").getContext("2d");
for (let row = 0; row < 8; row++) {
for (let column = 0; column < 8; column++) {
pen.fillStyle = (row + column) % 2 === 0 ? "#eee" : "#555";
pen.fillRect(column * 30, row * 30, 30, 30);
}
}
</script>Painting with clicks
A canvas can react to clicks too. event.offsetX and event.offsetY tell you where someone clicked. Click the area in the preview several times:
<canvas id="area" width="300" height="200" style="border: 1px solid #ccc"></canvas>
<script>
const area = document.querySelector("#area");
const pen = area.getContext("2d");
const colours = ["tomato", "gold", "mediumseagreen", "royalblue", "orchid"];
let number = 0;
area.addEventListener("click", (event) => {
pen.fillStyle = colours[number % colours.length];
pen.beginPath();
pen.arc(event.offsetX, event.offsetY, 15, 0, Math.PI * 2);
pen.fill();
number++;
});
</script>Tip: For things you paint often, write your own function – for example
circle(x, y, colour). That saves lots of lines. In the task it helps you with the three traffic lights.
Your task
Your turn
Paint a traffic light on the drawing area #picture (200 × 300 pixels). First a black rectangle as the housing: from (50, 20), 100 wide and 260 tall. Inside it three circles with radius 35, all at x = 100: red at y = 70, yellow (gold) at y = 150 and green (limegreen) at y = 230.
<canvas id="picture" width="200" height="300"></canvas>
<script>
const pen = document.querySelector("#picture").getContext("2d");
// Housing
// Three lights
</script>- Something to think about
pen.fillStyle="black"; thenpen.fillRect(50, 20, 100, 260); - Which command helps?
A circle:
pen.beginPath();pen.arc(100, 70, 35, 0, Math.PI * 2);pen.fill(); – set fillStyle to"red"first.Write a function
circle(x, y, colour)– then you only need the three lines for a circle once.
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
<canvas id="picture" width="200" height="300"></canvas>
<script>
const pen = document.querySelector("#picture").getContext("2d");
function circle(x, y, colour) {
pen.fillStyle = colour;
pen.beginPath();
pen.arc(x, y, 35, 0, Math.PI * 2);
pen.fill();
}
pen.fillStyle = "black";
pen.fillRect(50, 20, 100, 260);
circle(100, 70, "red");
circle(100, 150, "gold");
circle(100, 230, "limegreen");
</script>