DEV Community

Cover image for JavaScript mouse drawing on the canvas 👨‍🎨
Chris Bongers
Chris Bongers

Posted on • Originally published at daily-dev-tips.com

JavaScript mouse drawing on the canvas 👨‍🎨

Today I wanted to continue canvas explorations by checking out how to draw on the canvas with our mouse.

It turns out it's actually fairly simple and easy to implement!

We'll be building this cool drawing app. (Have a play around!)

HTML Structure

The HTML could not be simpler, all we need is one big canvas.

<canvas id="canvas"></canvas>
Enter fullscreen mode Exit fullscreen mode

Styling our app

As for our styling, all we need to do is remove our default margin, create a cool emoji cursor, and set the width/height to be the same size as the viewport.

* {
  margin: 0;
  padding: 0;
cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'  width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>✍️</text></svg>") 16 0,auto;
}
canvas {
  width: 100vw;
  height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

Drawing on canvas with JavaScript mouse

Now on to the fun part, the JavaScript to connect our mouse movements to the canvas.

Let's start by defining our variables.

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let coord = { x: 0, y: 0 };
Enter fullscreen mode Exit fullscreen mode

We need the canvas, and retrieve it based on it's ID.
Then we get the context (where we actually draw on)

Then we define our base coordinates.

Now let's attach listeners for:

  • mousedown (start registering our drawing
  • mouseup (stop the drawing)
  • resize (resize the canvas)
document.addEventListener("mousedown", start);
document.addEventListener("mouseup", stop);
window.addEventListener("resize", resize);
Enter fullscreen mode Exit fullscreen mode

Let's start with the resize function, this function will resize the canvas based on our viewport. It will make the canvas 100% or the width and height.

We also call this function right away.

function resize() {
  ctx.canvas.width = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
}

resize();
Enter fullscreen mode Exit fullscreen mode

Let's define our mousedown (start) function.

function start(event) {
  document.addEventListener("mousemove", draw);
  reposition(event);
}
Enter fullscreen mode Exit fullscreen mode

This function will invoke the listener for mousemove, so we don't have to keep listening to it.
Then we call our reposition function, which will register our mouse position.

The reposition function will look like this:

function reposition(event) {
  coord.x = event.clientX - canvas.offsetLeft;
  coord.y = event.clientY - canvas.offsetTop;
}
Enter fullscreen mode Exit fullscreen mode

On to the stop function.

function stop() {
  document.removeEventListener("mousemove", draw);
}
Enter fullscreen mode Exit fullscreen mode

We only need to stop listening to our register mousemove function.

The last function we will make is the draw. This actually will create lines on the canvas.

function draw(event) {
  ctx.beginPath();
  ctx.lineWidth = 5;
  ctx.lineCap = "round";
  ctx.strokeStyle = "#ACD3ED";
  ctx.moveTo(coord.x, coord.y);
  reposition(event);
  ctx.lineTo(coord.x, coord.y);
  ctx.stroke();
}
Enter fullscreen mode Exit fullscreen mode

In order:

  • We begin a new path.
  • We set the line width to 5 pixels.
  • We change the line endings to round.
  • We set the color to blue.
  • We change our position to the initial position and move the canvas point to the moved position.
  • Then we draw a line between these two points.
  • Last we call the stroke to colour it.

That's it. We can now draw lines on the canvas.

If you want to read more about canvas, check out these articles.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Top comments (8)

Collapse
 
rzeczuchy profile image
rzeczuchy

That's a really cool sample :)

I know that this is beyond the scope of this short article, but one thing that is worth looking into for anyone wanting to build a drawing app like this is Bresenham's line algorithm.

Drawing lines with paths is OK as long as you are using a round brush (lineCap = "round"), but if you use a large square brush, you're going to see significant tearing when drawing an irregular line. Bresenham's algo lets you avoid that problem - it's a great and cheap way to approximate lines.

Collapse
 
krhoyt profile image
Kevin Hoyt

Just wanted to second on using a line algorithm. If you draw with the mouse quickly, you will also see that the event does not fire with every pixel, so you get gaps in the data points. A line algorithm solves that, and can perform better depending on the algorithm and number of data points. Also consider pointer events or detecting touch for mobile support.

Collapse
 
dailydevtips1 profile image
Chris Bongers

Yes touch was indeed on the list still, but probably be a separate one, I like to keep the articles short so people will actually try them.
The line algorithm is a good one, I need to do some research on that.

Collapse
 
dailydevtips1 profile image
Chris Bongers

Oh nice addition, good read!

Collapse
 
soniarpit profile image
Arpit

wow

Collapse
 
dailydevtips1 profile image
Chris Bongers

Thank you Arpit

Collapse
 
youpiwaza profile image
max

Pretty neat. I used to teach a similar exercice.

I'd recommand using lowdash.debounce or throttle to optimize events (limit the drawing, as JS basic event system is consuming hard ^^')

Collapse
 
dailydevtips1 profile image
Chris Bongers

Good advice, but I wanted to showcase it in plain javascript, without using any packages.
Generally tracking mousemove fulltime is pretty hard yes, for some reason, this doesn't seem to spike CPU much.