How To Draw with Javascript & HTML Canvas

In this article, I'm going to explain how to create a different kind of Hello, World! Instead of merely printing the value to the screen, we're going to draw it using Javascript and HTML5. Let's get started. The end result will look like this: 

Ok, hopefully your mouse handwriting is better than mine.

To kick things off, we'll need just a single line of HTML code and a bit of clean CSS. This will enable the HTML5 canvas. Later on, we'll use a querySelector to grab the element based on its ID, so don't forget to include id="draw".

<canvas id="draw" width="800" height="800"></canvas>
<style>
  html, body {
    margin:0;
  }
</style>

Next, we'll start our javascript by getting the element and defining a canvas object (ctx). We'll also grab the same height and width using the window property. 

const canvas = document.querySelector('#draw');
// could be 3d, if you want to make a video game
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

In order to shape the line, we'll use two canvas methods: lineCap and lineJoin. Without these two properties, the elements will appear disjointed.

Two more canvas methods apply the style. You can adjust the lineWidth as you see fit, creating a thinner or thicker final product. The color can be updated using hex values and can even change depending on various other attributes of the page. 

ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.lineWidth = 20;
ctx.strokeStyle = "#000000";

Next, let's get into the meat of our Javascript code: the draw functionality. We'll begin by establishing four event listeners. We need to know when the mouse is pressed down, up, moved, or clicked off the page. 

In order to keep track of our mouse movements, we need a boolean variable. I'll call it isDrawing and begin by setting it to false. Now let's talk about tracking movements. 

let isDrawing = false;
canvas.addEventListener('mousedown', () => isDrawing = true);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);

Finally, we'll need a function named draw. In this function, we'll pass through an event listener. Let's start by logging the output in the console. It will end up looking something like this. 

Screenshot 2017-09-01 19.49.17.png

So we have a bunch of MouseEvents, but no output on the screen. We can rectify that by drawing from the point at which our mouse is lifted. 

Most importantly, at the end of the method we have to set a new X, Y coordinate as the last X and last Y. Finally, I had to update the MouseDown event listener to handle these X and Y coordinates. Without these offsets, the line will always connect from the ending point of the previous MouseUp event.

In totality, the script ended up looking like this: 

<script>
  const canvas = document.querySelector('#draw');
  // could be 3d, if you want to make a video game
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  ctx.lineJoin = 'round';
  ctx.lineCap = 'round';
  ctx.lineWidth = 20;
  ctx.strokeStyle = '#ac0000';

  let isDrawing = false;
  let lastX = 0;
  let lastY = 0;

  function draw(e) {
    // stop the function if they are not mouse down
    if(!isDrawing) return;
    //listen for mouse move event
    console.log(e);
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [lastX, lastY] = [e.offsetX, e.offsetY];
  }

  canvas.addEventListener('mousedown', (e) => {
    isDrawing = true;
    [lastX, lastY] = [e.offsetX, e.offsetY];
  });

  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', () => isDrawing = false);
  canvas.addEventListener('mouseout', () => isDrawing = false);
</script>

Do you have any questions? Something that could be improved? Please feel free to let me know in the comments below!