This is the first post of Drawing on the Web
Remember when you were a kid and discovered that you could draw on foggy car windows? Well, today we’re going to recreate that magical feeling, but digitally! We’re building a tiny drawing app using nothing but vanilla JavaScript and the HTML5 <canvas> element.
No fancy frameworks, no npm packages that require a PhD to understand – just good old-fashioned web fundamentals. By the end of this series, you’ll have a working drawing app that would make MS Paint jealous (okay, maybe that’s overselling it, but it’ll be pretty cool).
What We’re Building Today
In this first post, we’re keeping things simple. We’ll create a canvas that you can draw on with your mouse. Think of it as laying the foundation – no bells, no whistles, just pure drawing goodness.
Setting Up the HTML Structure
Let’s start with the bare minimum HTML. We need a canvas element and that’s about it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tiny Drawing App</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
#drawingCanvas {
border: 2px solid #333;
cursor: crosshair;
background-color: white;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<h1>Tiny Drawing App</h1>
<canvas id="drawingCanvas"></canvas>
<script src="script.js"></script>
</body>
</html>
Notice that crosshair cursor? It’s a small touch that makes the canvas feel more like a drawing surface. These little details matter!
The JavaScript Magic
Now for the fun part. Let’s create our script.js file and bring this canvas to life:
// Get the canvas and its 2D context
const canvas = document.getElementById('drawingCanvas');
const ctx = canvas.getContext('2d');
// Set canvas size
canvas.width = 800;
canvas.height = 600;
// Drawing state
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// Set up the drawing context
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.strokeStyle = '#000000';
ctx.lineWidth = 5;
function startDrawing(e) {
isDrawing = true;
// Get mouse position relative to canvas
const rect = canvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
}
function draw(e) {
if (!isDrawing) return;
// Get current mouse position
const rect = canvas.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
// Draw line from last position to current position
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
// Update last position
lastX = currentX;
lastY = currentY;
}
function stopDrawing() {
isDrawing = false;
}
// Event listeners
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
Breaking Down the Code
Let’s walk through what’s happening here:
Canvas Setup: We grab the canvas element and get its 2D rendering context. Think of the context as your paintbrush – it’s what actually does the drawing.
Drawing State: We track whether the user is currently drawing with isDrawing, and remember the last mouse position with lastX and lastY. This is crucial for creating smooth lines.
Drawing Properties: We set lineCap to ‘round’ for nice rounded line ends, and lineJoin to ‘round’ for smooth connections between line segments. It’s like choosing between a marker and a calligraphy pen.
Mouse Position Calculation: Here’s where it gets slightly tricky. e.clientX and e.clientY give us the mouse position relative to the entire viewport, but we need the position relative to our canvas. That’s why we use getBoundingClientRect() to get the canvas’s position and subtract it.
The Drawing Logic: When the mouse moves while drawing, we create a line from the last position to the current position. It’s like connect-the-dots, but with really tiny dots!
Why This Approach Works
You might wonder why we’re drawing lines between points instead of just placing dots wherever the mouse goes. Try moving your mouse really fast across the screen – if we only drew dots, you’d get a dotted line with gaps. By connecting the dots, we get smooth, continuous lines even with fast mouse movements.
The mouseout event listener is a nice touch too. It stops drawing when the mouse leaves the canvas, preventing those awkward situations where you accidentally drag outside the canvas and then drag back in, creating unexpected lines.
What’s Next?
Right now, our drawing app is pretty basic – you can draw with a black brush of fixed size. In the next post, we’ll add some personality by implementing brush size selection and color options. Because let’s face it, everything is better in color!
Try playing around with the current version. Draw some shapes, test the smoothness of the lines, and maybe try to recreate the Mona Lisa (results may vary). The foundation is solid, and now we’re ready to build some exciting features on top of it.
Next up: Adding brush sizes and color selection to make our drawing app more versatile!