Skip to content
BetaDE
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>
CommandWhat 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>

Solve it without hints to earn a ⭐ on your progress page.

Show solution

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>