DEV Community

Cover image for Freehand drawing with the Canvas API
Arman Eousuf
Arman Eousuf

Posted on

Freehand drawing with the Canvas API

When I was trying Canvas, I was completely puzzled. It felt so frustrating; I felt like I was writing in a completely different language instead of my usual JavaScript. But after reading the MDN doc and watching some videos...it still feels difficult and frustrating. But despite everything, let's try to build something. Polishing can come later.

First, we need to select the ID from HTML

const canvas = document.querySelector("#draw");
Enter fullscreen mode Exit fullscreen mode

We need canvas.getContext here to tell the browser what type of drawing we are going to do. For now, the screen is blank, so we need to tell it what we are going to do. The <canvas> element has a method called getContext. That's the one we are targeting here

const ctx = canvas.getContext("2d");
Enter fullscreen mode Exit fullscreen mode

We are going to draw on the whole window, so we need to target the whole window. But we can't just let HTML decide the window. We need to overwrite it, and JavaScript can help here with its innerHeight and innerWidth properties

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Enter fullscreen mode Exit fullscreen mode

That's a lot. I know. So, let's slow down and draw our first rectangle.

function draw() {
  const canvas = document.querySelector("#draw");
  const ctx = canvas.getContext("2d");

  ctx.fillStyle = "rgb(200 0 0 / 50%)"; // setting the rect color with the fillStyle property
  ctx.fillRect(10, 10, 50, 50); // drawing the rectangle using the fillRect canvas api's method
}
draw();
Enter fullscreen mode Exit fullscreen mode

That was easy, but we are not going to draw shapes. Our goal is to use freehand. Comment out or delete the previous draw function.

For now, we need four things before going forward. Set the color of the pen, how we want our pen to be, how the ends of lines look, and the size of the pen.

ctx.strokeStyle = "rgb(200 135 90)";
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.lineWidth = 5;
Enter fullscreen mode Exit fullscreen mode

Here we can set the pen color with strokeStyle, how corners between connected lines look with lineJoin, the ending of the lines with lineCap (default to butt), and the size with lineWidth.

We don't want to draw with every movement our mouse do. Only when we click the mouse and move it. So here it is

let isDrawing = false;
Enter fullscreen mode Exit fullscreen mode
let lastX = 0;
let lastY = 0;
Enter fullscreen mode Exit fullscreen mode

lastX/Y start at 0 as a placeholder. Later, they get replaced by the real mouse X/Y position from e.offsetX/Y.

Let's draw it now:

function draw(e) {
  if (!isDrawing) return;
  console.log(e);
  ctx.beginPath();
  ctx.moveTo(lastX, lastY);
  ctx.lineTo(e.offsetX, e.offsetY);
  ctx.stroke();
  [lastX, lastY] = [e.offsetX, e.offsetY];
}
Enter fullscreen mode Exit fullscreen mode

The condition prevents drawing when the mouse button is not being held down
beginPath() starts a new path every time
moveTo() sets the starting point of the line
lineTo() draws a line from the current point to the current mouse position
stroke() draws the path onto the canvas using the current stroke settings
[lastX, lastY] = [e.offsetX, e.offsetY] updates to the current mouse position by destructuring

// Mouse button pressed down β†’ start drawing
canvas.addEventListener("mousedown", (e) => {
  isDrawing = true;
  [lastX, lastY] = [e.offsetX, e.offsetY];
});

// Mouse button released β†’ stop drawing
canvas.addEventListener("mouseup", () => {
  isDrawing = false;
});

// Mouse leaves canvas β†’ also stop
canvas.addEventListener("mouseout", () => {
  isDrawing = false;
});

// Mouse moves β†’ only draw if the flag is true
canvas.addEventListener("mousemove", draw);
Enter fullscreen mode Exit fullscreen mode

That's it for today. Tada! Leave a comment if you want to.

Further reading:

  1. Drawing shapes with canvas
  2. Canvas tutorial
  3. HTML Canvas

Top comments (0)