Creating a Paint Application with HTML5 Canvas

Let’s build a simple painting (or sketching) application using HTML5 <canvas> element along with its Javascript API. Although the app will be small, there’s going to be quite a bit of information for intake. So I’ll break the entire process into different tutorials (posts).

Features

A quick look at the features that we want in our little app:

  1. Multiple tools to draw different shapes like a rectangle, circle or just a line.
  2. Multiple sizes for each tool.
  3. Multiple color choices.

The Markup

HTML code is going to be super simple.

[html]
<div id="sketch">
<canvas id="paint"></canvas>
</div>
[/html]

The Scripting

Onto the real part now, the Javascript coding. We’ll first set the height and width of the canvas and also get its 2D context.

[js]
var canvas = document.querySelector(‘#paint’);
var ctx = canvas.getContext(‘2d’);

var sketch = document.querySelector(‘#sketch’);
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue(‘width’));
canvas.height = parseInt(sketch_style.getPropertyValue(‘height’));
[/js]

We used window.getComputedStyle() along with getPropertyValue() to get the width and height of div#sketch. After applying parseInt() on the values, we set the width and height of the canvas to the same values. Neat approach towards a dynamic size!

Next up, we need to write the code for one of the most fundamental part of the app, i.e., mouse interaction.

[js]
var mouse = {x: 0, y: 0};

/* Mouse Capturing Work */
canvas.addEventListener(‘mousemove’, function(e) {
mouse.x = e.pageX – this.offsetLeft;
mouse.y = e.pageY – this.offsetTop;
}, false);
[/js]

So we have an object called mouse now that’ll hold the x and y co-ordinates of the mouse’s position relative to the canvas. e.pageX holds the position of the mouse relative to the document while this.offsetLeft holds the distance of the canvas’s upper left corner from the closest “positioned” parent. If none exists, then the closest positioned parent will default to body.

Subtracting offsetLeft/offsetTop from pageX/pageY helps us get the mouse positions relative to the canvas. At this point, it is important to note that this solution works in our case, but if your markup and styling is a bit more complex then try using some framework like jQuery to solve the problem of getting the left/top offset or check this stackoverflow thread for a pure JS solution.

Now the core part, that’ll do the drawing. It’s really simple, check out:

[js]
/* Drawing on Paint App */
ctx.lineWidth = 5;
ctx.lineJoin = ’round’;
ctx.lineCap = ’round’;
ctx.strokeStyle = ‘blue’;

canvas.addEventListener(‘mousedown’, function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);

canvas.addEventListener(‘mousemove’, onPaint, false);
}, false);

canvas.addEventListener(‘mouseup’, function() {
canvas.removeEventListener(‘mousemove’, onPaint, false);
}, false);

var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
[/js]

On every mousedown event we begin a path and move the path to the mouse’s x/y points. We also bind a mousemove event at the same time, where the handler calls lineTo to draw lines on every x/y point through which the mouse passes. As soon as the mouse click is release, i.e., on mouseup, the event that’s attached to mousemove is detached. Simple enough!

Final Result

This is the demo of all the code that we discussed (when combined). Just drag your mouse on the canvas to draw random lines/shapes.


I definitely know that we’re not finished yet. But I think that’s a lot of information to digest for now. When you draw circles or lines, do you see the edges are not smooth, rather jagged ? That’s the exact problem we’re going to solve in the next part.

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.