HTML Canvas

HTML Canvas allows us to draw graphics (using JavaScript). We can create a canvas element and use a WebGL API to draw lines, fill rectangles etc.

Let’s demonstrate some of the canvas and drawing functionality by creating a simple Tic-Tac-Toe UI. Start of by creating a HTML file and within that we add a canvas element, for example

<canvas id="tic-tac-toe-board"></canvas>

Now in our JavaScript (or in my case I’m going to use TypeScript) we can get the element using the id and then start interacting with the canvas using WebGL, for for example here’s a “main” method which we’d run in the HTML body’s onload event. The first thing we need to do is get the canvas element using

const board = <HTMLCanvasElement> document.getElementById('tic-tac-toe-board');

Next up we need to get the element’s context using

const ctx = board.getContext('2d');  
if(ctx != null) {
}

Once we have the context we can use methods, such as fillRect, moveTo, lineTo etc. as well as set properties on the context, for example

const ctx = board.getContext('2d');  
if(ctx != null) {
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, board.clientWidth, board.clientHeight);
}

Below is an example of an implementation of code to draw a Tic-Tac-Toe board and handle click events.

function main() {
  const board = <HTMLCanvasElement> document.getElementById('tic-tac-toe-board');

  const size = 500;
  const lineColour = "#ddd";
  const lineStart = 4;
  const lineLength = size - 5;
  const sectionSize = size / 3;

  board.width = size;
  board.height = size;

  const elemLeft = board.offsetLeft + board.clientLeft;
  const elemTop = board.offsetTop + board.clientTop;
  const elemWidth = board.clientWidth;
  const elemHeight = board.clientHeight;

  // example of handling click event
  board.addEventListener('click', ev => {
     const x = ev.pageX - elemLeft;
     const y = ev.pageY - elemTop;

     console.log(`X: ${x}, Y: ${y}`);
  });

  const ctx = board.getContext('2d');  
  if(ctx != null) {
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, elemWidth, elemHeight);

    ctx.lineWidth = 10;
    ctx.lineCap = 'round';
    ctx.strokeStyle = lineColour;
    ctx.beginPath();

    for (let y = 1; y <= 2; y++) {  
      ctx.moveTo(lineStart, y * sectionSize);
      ctx.lineTo(lineLength, y * sectionSize);
    }
      
    for (let x = 1; x <= 2; x++) {
      ctx.moveTo(x * sectionSize, lineStart);
      ctx.lineTo(x * sectionSize, lineLength);
    }
      
    ctx.stroke();
  }
}

Source code for this post is available on github