This week, we will complete the simple drawing grid by adding support for mobile browsers. Support for mobile browsers consists of enabling interaction with the canvas with touch events rather than the mouse events that are currently used. We will not need to modify any HTML or CSS code, only our JavaScript implementation.
Touch interactions on mobile devices use three main events:
touchstart: Triggered when a touch point is placed on the screen.
touchmove: Triggered when a touch point is moved across the screen.
touchend: Triggered when a touch point is removed from the screen.
We’ll use these events to track touch positions and allow drawing on the canvas.
The following steps explain all required changes
We’ll create unified handlers for startDrawing, stopDrawing, and draw to ensure both touch and mouse inputs can share the same logic.
Here’s how the unified handlers look:
const startDrawing = (x, y) => {
mouseDown = true;
draw(x, y);
};
const stopDrawing = () => {
mouseDown = false;
};
const draw = (x, y) => {
if (mouseDown) {
const adjustedX = Math.floor((x - xOffset) / penWeight);
const adjustedY = Math.floor((y - yOffset) / penWeight);
ctx.fillStyle = penColor;
ctx.fillRect(adjustedX * penWeight, adjustedY * penWeight, penWeight, penWeight);
}
};
These functions abstract the drawing logic, so we can use them for both mouse and touch inputs.
Next, we add touch event listeners (touchstart
, touchmove
, touchend
) to the canvas. These events detect touch gestures and pass the touch coordinates to the unified handlers.
gridCanvas.addEventListener("touchstart", (e) => {
e.preventDefault(); // Prevent scrolling on touch devices
const touch = e.touches[0];
startDrawing(touch.pageX, touch.pageY);
});
gridCanvas.addEventListener("touchend", (e) => {
e.preventDefault();
stopDrawing();
});
gridCanvas.addEventListener("touchmove", (e) => {
e.preventDefault();
const touch = e.touches[0];
draw(touch.pageX, touch.pageY);
});
e.touches[0] gives the first touch point’s pageX and pageY coordinates.
e.preventDefault() stops the default browser behavior (e.g., scrolling).
Ensure mouse events (mousedown, mouseup, mousemove) continue to work using the same unified handlers.
gridCanvas.onmousedown = (e) => startDrawing(e.pageX, e.pageY);
gridCanvas.onmouseup = stopDrawing;
gridCanvas.onmousemove = (e) => draw(e.pageX, e.pageY);
When the canvas is reset, all event listeners must be reattached. Update the initializeCanvas() function to include the setup for both mouse and touch handlers.
function initializeCanvas() {
gridCanvas = document.getElementById("grid");
ctx = gridCanvas.getContext("2d");
// Set canvas dimensions
const viewWidth = window.innerWidth * 0.9;
const viewHeight = window.innerHeight * 0.7;
gridCanvas.width = viewWidth;
gridCanvas.height = viewHeight;
// Clear and fill the canvas
ctx.clearRect(0, 0, viewWidth, viewHeight);
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, viewWidth, viewHeight);
// Reattach event handlers
setupMouseAndTouchHandlers();
}
Here’s the complete updated JavaScript code, combining all the changes:
function initializeCanvas() {
gridCanvas = document.getElementById("grid");
ctx = gridCanvas.getContext("2d");
const viewWidth = window.innerWidth * 0.9;
const viewHeight = window.innerHeight * 0.7;
gridCanvas.width = viewWidth;
gridCanvas.height = viewHeight;
ctx.clearRect(0, 0, viewWidth, viewHeight);
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, viewWidth, viewHeight);
setupMouseAndTouchHandlers();
}
function setupMouseAndTouchHandlers() {
const rect = gridCanvas.getBoundingClientRect();
const xOffset = rect.left + window.scrollX;
const yOffset = rect.top + window.scrollY;
const startDrawing = (x, y) => {
mouseDown = true;
draw(x, y);
};
const stopDrawing = () => {
mouseDown = false;
};
const draw = (x, y) => {
if (mouseDown) {
const adjustedX = Math.floor((x - xOffset) / penWeight);
const adjustedY = Math.floor((y - yOffset) / penWeight);
ctx.fillStyle = penColor;
ctx.fillRect(adjustedX * penWeight, adjustedY * penWeight, penWeight, penWeight);
}
};
gridCanvas.onmousedown = (e) => startDrawing(e.pageX, e.pageY);
gridCanvas.onmouseup = stopDrawing;
gridCanvas.onmousemove = (e) => draw(e.pageX, e.pageY);
gridCanvas.addEventListener("touchstart", (e) => {
e.preventDefault();
const touch = e.touches[0];
startDrawing(touch.pageX, touch.pageY);
});
gridCanvas.addEventListener("touchend", (e) => {
e.preventDefault();
stopDrawing();
});
gridCanvas.addEventListener("touchmove", (e) => {
e.preventDefault();
const touch = e.touches[0];
draw(touch.pageX, touch.pageY);
});
}
window.onload = initializeCanvas;
Now drawing should work on mobile devices. As an exercise you can play with the styling of controls for optimal use on a mobile devices.
Final version is located here. Note that the font awesome link was moved to the Resources area of JSFiddle.