JavaScript30 - Day 8 (Draw on the HTML5 Canvas)

This is day 8 in my #javascript30 journey. This is the free course from Wes Bos that lets you brush up on your JavaScript skills via 30 projects.

Yesterday we did some epic Array Cardio. You can keep track of all the projects we're building here.

Today we're having some fun with HTML5 Canvas.


Day 8 - Fun with HTML5 Canvas

Today we're going to create a drawing game using the HTML5 canvas element. The drawing pad game itself might seem basic but it will get us familiar with the Canvas element.

Let's get into it.

The only HTML element on the page is our canvas element:

<canvas id="draw" width="800" height="800"></canvas>  

To play our game we are going to need our JS to select this element:

const canvas = document.querySelector('#draw')  

From there we can make the magic happen.

Our users won't be drawing directly onto the canvas element. Instead, they will be interacting with the canvas context. We can access this with a getContext call. We're interested only in 2d context at the moment so this is what we specify.

const ctx = canvas.getContext('2d')  

We will also need to:

  • Stretch the canvas to fill the window height and width.
  • Set the base settings of the strokeStyle, lineJoin & lineCap.
  • Set default drawing variables (to control so the drawing only happens when the mouse is down - not just when the mouse moves).
  • Set default variables to hold the beginning & ending coordinates for drawing lines.
//Stretch the canvas to fill the window
canvas.width = window.innerWidth  
canvas.height = window.innerHeight  
//Set the base settings
ctx.strokeStyle = '#BADA55'  
ctx.lineJoin = 'round'  
ctx.lineCap = 'round'  
ctx.lineWidth = 20  
//Set default drawing variables
let isDrawing = false  
//default coordinates for line end/start points
let lastX = 0  
let lastY = 0  

Finally in our preparation phase we will need to create some event listeners and a function to handle drawing.

function draw(e) {  
  if (!isDrawing) return
  //Only runs when the mouse is down
  console.log(e)
  ctx.beginPath()
  ctx.moveTo(lastX, lastY)
  ctx.lineTo(e.offsetX, e.offsetY)
  ctx.stroke()
  lastX = e.offsetX
  lastY = e.offsetY
}
//when mouse is down set the starting point & toggle isDrawing
canvas.addEventListener('mousedown', (e) => {  
  isDrawing = true
  lastX = e.offsetX
  lastY = e.offsetY
})

canvas.addEventListener('mousemove', draw)  
canvas.addEventListener('mouseup', () => (isDrawing = false))  
canvas.addEventListener('mouseout', () => (isDrawing = false))  

MAGIC!

We have canvas drawing

Mothereffing HSL

What the heck is Mother-effing HSL? It's an awesome tool that helps calculate the HSL (Hue, Saturation, Lightness) of every colour.

It also shows that the Hue element in HSL goes through every colour in the rainbow starting and ending with red. This is a handy point as it means we can cycle through all of the colours by incrementing the H variable in an HSL colour from 0 - 360 and repeating for every single draw element.

This can be achieved by first initialising hue and then setting the strokeStyle to an hsl colour that references it before iterating it:

let hue = 0

function draw(e) {  
  if (!isDrawing) return
  ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`
  ctx.beginPath()
  ctx.moveTo(lastX, lastY)
  ctx.lineTo(e.offsetX, e.offsetY)
  ctx.stroke()
  lastX = e.offsetX
  lastY = e.offsetY
  hue++;
}

This gives us a rainbow styled stroke. Isn't it beautiful.

Rainbow pride!

Wes went further into using Global Composite Operators to modify the canvas but this wasn't something I wanted in the final product.

Today was a lot of fun. Now that everything has been done I have pushed this project live to a Firebase project. You can view it live here.

You can keep track of all the projects in this JavaScript30 challenge here.