How to Create a Simple Paint Tool with Canvas API
Online drawing tools are very popular due to their no-installation requirement, lightweight nature, and accessibility from anywhere. The JavaScript Canvas API provides a range of features for developing this type of online drawing app, from basic to advanced. In this article, we will explore how to develop a simple drawing app with a pencil tool using the Canvas API.
Look at the following example. Select a color and drag on the canvas space to start drawing.
First, we need to create a canvas element. Provide a specific width and
height.
<canvas width="240" height="180"></canvas>
Then add the following CSS to the canvas. Avoiding touch actions is very important for mobile devices;
otherwise, dragging on the canvas will start to scroll the web page. Also, you can set a background color and a
suitable cursor for a better user experience.
canvas {
/* avoid mobile device scrolling */
touch-action: none;
/* default background color */
background-color: #fff;
/* cursor to display */
cursor: crosshair;
}
In JavaScript, you can get the canvas element and its 2D context. This context provides all the
rendering interface to our canvas, such as drawing shapes, images, reading pixel data, and clearing content.
// get canvas element
const canvas = document.querySelector("#canvas")
// get canvas context
const context = canvas.getContext("2d")
Then define the global data states and values that are required during the drawing. Since JavaScript has no direct
way of detecting the pointer drag event, first we detect the pointer down action and remember that the
pointer is down in a boolean variable. While listening to the pointer move action, we check if that
boolean value is set to true and determine if the cursor is dragging or not. When the pointer is up or
exits the canvas, we can set the boolean back to false.
// drawing active state
let isActive = false
// set as active on pointer down
canvas.addEventListener("pointerdown", () => isActive = true)
// listen to pointer move event
canvas.addEventListener("pointermove", event => {
// return if not active
if (!isActive) { return }
// HERE: user is drawing
})
// set as inactive on pointer out
canvas.addEventListener("pointerout", () => isActive = false)
// set as inactive on pointer up
canvas.addEventListener("pointerup", () => isActive = false)
While dragging on the canvas, we are going to draw lines for each cursor move point. To do this, we need the
previous cursor point and the current cursor point. Therefore, while the pointer is
setting down, we have to remember that point as the line's starting position.
// last drawn coordinates
let lastX = 0
let lastY = 0
// listen to pointer down event
canvas.addEventListener("pointerdown", event => {
// set as active
isActive = true
// remember as starting point
lastX = event.offsetX
lastY = event.offsetY
})
Now we can use that starting point and the current point to draw the line during dragging. Here you can set a
color to the strokeStyle before drawing the line. And at the end of line drawing, store
the current point as the last point so each line user draws will be connected as a drawing path while
dragging on the canvas.
// listen to pointer move event
canvas.addEventListener("pointermove", event => {
// return if not active
if (!isActive) { return }
// set a line color
context.strokeStyle = "red"
// set drawing style
context.lineWidth = 2
context.lineCap = "round"
// get current pointer coordinates
const x = event.offsetX
const y = event.offsetY
// draw line
context.beginPath()
context.moveTo(lastX, lastY)
context.lineTo(x, y)
context.stroke()
// remember last coordinates
lastX = x
lastY = y
})
To clear the entire canvas, you can use the following method and provide the exact canvas size. You can
bind this with a button click with a user confirmation, so the canvas will not be cleared without user intention.
// clear canvas by its dimensions
context.clearRect(0, 0, canvas.width, canvas.height)