This week, we will build a simple drawing grid using HTML5 and javascript. In the coming weeks we will transform this simple example into a fully functional drawing application. For this demo, the entire browser window will be a canvas and resizing or reloading the window will clear it. The first step is to define our canvas and add some css that will set the size of the canvas to the size of the browser window.
<!DOCTYPE HTML>
<html>
<style type="text/css">
html, body { width: 100%; height: 100%; margin: 0px; }
</style>
<body>
<canvas id="grid">
<p>Your browser does not support HTML5 canvas</p>
</canvas>
</body>
</html>
This is all that is required to create a canvas that consumes the entire browser window. The next step is to add javascript to the page so we can have an interactive drawing surface. We will be using jquery and loading a script named grid.js; which will perform the canvas updates.
<!DOCTYPE HTML>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
</head>
<style type="text/css">
html, body { width: 100%; height: 100%; margin: 0px; }
</style>
<body>
<canvas id="grid">
<p>Your browser does not support HTML5 canvas</p>
</canvas>
<script type="text/javascript" src="scripts/grid.js"></script>
</body>
</html>
The next step is to create a folder named “scripts” and within it create a text file called grid.js using your favorite editor. The grid.js script will be responsible for all of the canvas updating. For starters, we will need to define the callbacks for window events in order to initialize the canvas data. “window.onresize” will be used so that the canvas can be cleared when the window is resized.
function setupCanvas() {
const gridCanvas = document.getElementById("grid");
const ctx = gridCanvas.getContext("2d");
// Get viewport dimensions
const viewWidth = window.innerWidth;
const viewHeight = window.innerHeight;
// Background color for the canvas
const backgroundColor = "rgb(0, 0, 255)";
// Configure canvas size and position
gridCanvas.style.position = "fixed";
gridCanvas.style.top = "0";
gridCanvas.style.left = "0";
gridCanvas.setAttribute("width", viewWidth);
gridCanvas.setAttribute("height", viewHeight);
// Clear and fill the canvas with background color
ctx.clearRect(0, 0, viewWidth, viewHeight);
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, viewWidth, viewHeight);
// We will use these later
return { gridCanvas, ctx };
}
// Main initialization function
function initialize() {
// Set up canvas and get drawing context
const { gridCanvas, ctx } = setupCanvas();
// We will use gridCanvas and ctx later
}
// Initialize canvas and event listeners on load and resize
window.onload = window.onresize = initialize;
At this point, the canvas is created, but isn’t very interesting. To draw on the canvas, we will rely on mouse events. In this demo, holding down the left mouse button and dragging will fill in cells of the grid that the mouse is hovering over. Holding any other mouse button down and dragging will be used for an “erase” function. It’s not actually erasing, but coloring the cells in with the defined background color. The following should be added before the initialize function
// State variables
let mouseDown = false;
let mouseButton = 0;
const penColor = "rgb(255, 255, 255)";
const penWeight = 5;
// Event handlers for mouse interactions
function setupMouseHandlers(gridCanvas, ctx) {
// Get canvas position offsets
const rect = gridCanvas.getBoundingClientRect();
const xOffset = rect.left + window.scrollX;
const yOffset = rect.top + window.scrollY;
// Mouse down event
gridCanvas.addEventListener("mousedown", (e) => {
mouseDown = true;
mouseButton = e.button; // Updated to use `e.button` (modern standard)
});
// Mouse up event
gridCanvas.addEventListener("mouseup", () => {
mouseDown = false;
});
// Mouse move event
gridCanvas.addEventListener("mousemove", (e) => {
if (mouseDown) {
const x = Math.floor((e.pageX - xOffset) / penWeight);
const y = Math.floor((e.pageY - yOffset) / penWeight);
ctx.fillStyle = mouseButton === 0 ? penColor : "rgb(0, 0, 255)"; // Left click: penColor; Right click: background
ctx.fillRect(x * penWeight, y * penWeight, penWeight, penWeight);
}
});
}
Update the initialize function to setup mouseh handlers
function initialize() {
// Set up canvas and get drawing context
const { gridCanvas, ctx } = setupCanvas();
// Set up mouse handlers
setupMouseHandlers(gridCanvas, ctx);
}
Loading the page now should result in a functional drawing application. Changing the “penWeight” variable will alter the cell sizes on the hidden grid. As a small optimization, you may consider storing the last cell that was drawn to and skipping a redraw (included in the source example) if the user is still moving with the cell. At smaller cell sizes, this becomes less important.
You can play with this code here.