Learn how to draw lines and create paths on HTML5 Canvas
Activity: Connect-the-dots game
In this episode, we'll learn how to draw lines and create paths using the HTML5 Canvas API. You'll see how drawing on canvas is like giving your browser step-by-step instructions to create art – just like connect-the-dots puzzles!
Today's mission: Help the McTweak team understand path drawing as they create a connect-the-dots game.
TrashyMcTweak: *[gesturing wildly at the code]* Check out this Canvas drawing code our rookie dev submitted. It's like trying to read hieroglyphics written by a drunk octopus. No comments, no organization—just paths and coordinates floating around like trash in space. Kind of reminds me of your dating profile, Grumpy!
GrumpyMcTweak: This isn't a JOKE, you creative catastrophe! Uncommented Canvas code is a SECURITY NIGHTMARE! When SkyNet finally takes over, it won't be through sophisticated AI—it'll be because some idiot wrote incomprehensible drawing code that NOBODY COULD MAINTAIN! *[twitching]* Every uncommented path is practically INVITING malicious exploitation!
TrashyMcTweak: Oh please, not everything is a doomsday scenario waiting to—
*[The Norwegian Elkhound suddenly barks and stands up. Everyone turns to look as GarbageMcTweak's dog trots over to the keyboard, paws at it a few times, and somehow manages to display a perfectly commented version of the same code on the screen]*
Norwegian Elkhound: *[looks up, tilts head, and lets out a small "woof"]*
GarbageMcTweak: She says, "Even a dog can write better comments than both of you idiots. One of you won't comment code because you think your 'genius' is self-explanatory, and the other writes security warnings so paranoid they're longer than the actual code."
*[Brief silence as both Trashy and Grumpy stare at the dog]*
TrashyMcTweak: Did... did I just get owned by a DOG?
GrumpyMcTweak: *[nodding reluctantly]* The dog makes a valid security point.
Norwegian Elkhound: *[gives another small "woof" and wags tail]*
GarbageMcTweak: Now she's just laughing at you both. *[Turns to leave]* I'm going back to Elden Ring. The dog can teach this lesson better than any of us.
AllyMcTweak: *[looking at the dog's commented code]* Well, would you look at that! Seems like the elkhound is the only one here who understands the importance of human-readable code. Maybe we should put her in charge of code reviews!
CodyMcTweak: *[poking his head in]* So... um... are we going to help this rookie programmer learn about drawing paths on Canvas or what?
TrashyMcTweak: Fine! Let's teach these coding kindergartners how to draw lines properly. But I want it on record that I got schooled by a dog today, and I am NOT emotionally okay with that.
Norwegian Elkhound: *[gives a smug little "woof"]*
AllyMcTweak: Let's start with the basics. The HTML5 Canvas element gives us a blank drawing surface that we can control with JavaScript. Think of it like a digital drawing board where every line has to be precisely defined.
First, you need to set up your canvas element in HTML:
<!DOCTYPE html>
<html>
<head>
<title>Canvas Drawing Example</title>
<style>
canvas {
border: 1px solid black;
background-color: white;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="300"></canvas>
<script>
// JavaScript drawing code will go here
</script>
</body>
</html>
FattyMcTweak: Of course, you'll need to get the premium drawing context before you can do anything with the canvas. That's where the REAL power is!
The context is what gives you access to all the drawing methods. For 2D drawing, we use the '2d' context:
// Get reference to the canvas element
const canvas = document.getElementById('myCanvas');
// Get the drawing context
const ctx = canvas.getContext('2d');
// Now we can use ctx to draw on the canvas
TrashyMcTweak: Alright, pay attention because I'm only explaining this once! Drawing paths is like telling someone directions – "Go here, then here, then here" – except the "someone" is your browser and it's even worse at following directions than my GPS.
There are three essential methods you need to know:
beginPath() - Starts a new path (like picking up your pencil)moveTo(x, y) - Moves to a point without drawing (placing your pencil down)lineTo(x, y) - Draws a line to this point (dragging your pencil)
CodyMcTweak: Let me show you a simple example of drawing a triangle. It's the free version, but it still works!
// Clear any previous drawings
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Start a new path
ctx.beginPath();
// Move to the top point of our triangle
ctx.moveTo(200, 50);
// Draw line to bottom right
ctx.lineTo(300, 200);
// Draw line to bottom left
ctx.lineTo(100, 200);
// Close the path (draws back to starting point)
ctx.closePath();
// Set the color
ctx.strokeStyle = 'blue';
ctx.lineWidth = 3;
// Draw the outline
ctx.stroke();
Norwegian Elkhound: *[tilts head and gives an approving but expectant "woof"]*
GarbageMcTweak: She says, "That's fine for a start, but what about filling the shape? Also, that triangle is boring."
AllyMcTweak: Good point! After creating a path, you can either stroke it (outline) or fill it (color the inside), or both! Let's make a more interesting shape and fill it.
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Start a new path for a star
ctx.beginPath();
// Define our star center and size
const centerX = 200;
const centerY = 125;
const outerRadius = 80;
const innerRadius = 40;
const spikes = 5;
// Calculate the angle between each point
const rotation = Math.PI / spikes;
// Draw the star
for (let i = 0; i < spikes * 2; i++) {
const radius = i % 2 === 0 ? outerRadius : innerRadius;
const x = centerX + radius * Math.cos(i * rotation);
const y = centerY + radius * Math.sin(i * rotation);
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.closePath();
// Fill with color
ctx.fillStyle = '#00eeff';
ctx.fill();
// Add an outline
ctx.strokeStyle = '#0a1a3f';
ctx.lineWidth = 2;
ctx.stroke();
TrashyMcTweak: Drawing boring shapes is for kindergarteners. Let's do something actually cool - a connect-the-dots game! You'll connect points in sequence to reveal a hidden shape. Not as cool as the AI-powered shape recognition system I built last week, but at least it won't try to take over your toaster.
GrumpyMcTweak: WAIT! Before we implement ANY interactive elements, we need to establish STRICT security protocols! What if someone tries to connect the dots in the wrong order? What if they try a denial-of-service attack by clicking too many dots at once? WHAT IF—
Norwegian Elkhound: *[lets out a sharp bark and gives Grumpy a stern look]*
GrumpyMcTweak: Fine. I'll... prepare a security audit report for later review.
AllyMcTweak: Let's build our game! We'll create numbered dots that you connect in order by clicking them. The game will use all the path drawing concepts we just learned.
Here's how we'll do it:
CodyMcTweak: I'll handle the basic setup code - that's about all I can do with my limited credits:
<!DOCTYPE html>
<html>
<head>
<title>Connect-the-Dots Game</title>
<style>
#gameCanvas {
border: 2px solid #0c7cd5;
background-color: #111;
display: block;
margin: 0 auto;
box-shadow: 0 0 10px #00eeff;
}
.game-container {
text-align: center;
padding: 20px;
}
button {
margin: 10px;
padding: 8px 15px;
background: #0a1a3f;
color: #00eeff;
border: 1px solid #0c7cd5;
border-radius: 5px;
cursor: pointer;
}
button:hover {
box-shadow: 0 0 8px #00eeff;
}
</style>
</head>
<body>
<div class="game-container">
<h1>Connect the Dots</h1>
<canvas id="gameCanvas" width="500" height="400"></canvas>
<br>
<button id="resetBtn">Reset Game</button>
</div>
<script>
// Game JavaScript will go here
</script>
</body>
</html>
FattyMcTweak: My premium solution adds the dot creation and drawing logic. Remember, quality code costs resources!
// Get the canvas and its context
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const resetBtn = document.getElementById('resetBtn');
// Define the dots for our game
const dots = [
{ x: 100, y: 50, num: 1 },
{ x: 400, y: 80, num: 2 },
{ x: 450, y: 200, num: 3 },
{ x: 380, y: 320, num: 4 },
{ x: 250, y: 350, num: 5 },
{ x: 120, y: 320, num: 6 },
{ x: 50, y: 200, num: 7 },
{ x: 250, y: 180, num: 8 }
];
// Game variables
let currentDotIndex = 0;
const connectedDots = [];
let gameCompleted = false;
// Draw a single dot
function drawDot(dot, isConnected) {
ctx.beginPath();
ctx.fillStyle = isConnected ? '#00ff66' : '#00eeff';
ctx.arc(dot.x, dot.y, 15, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#111';
ctx.font = 'bold 14px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(dot.num, dot.x, dot.y);
}
// Draw the lines between connected dots
function drawConnections() {
if (connectedDots.length < 2) return;
ctx.beginPath();
ctx.strokeStyle = '#00ff66';
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.moveTo(connectedDots[0].x, connectedDots[0].y);
for (let i = 1; i < connectedDots.length; i++) {
ctx.lineTo(connectedDots[i].x, connectedDots[i].y);
}
ctx.stroke();
// If game is completed, close the shape and fill it
if (gameCompleted) {
ctx.closePath();
ctx.fillStyle = 'rgba(0, 255, 102, 0.2)';
ctx.fill();
// Display completion message
ctx.fillStyle = '#00eeff';
ctx.font = 'bold 30px Arial';
ctx.fillText('Great Job!', canvas.width/2, canvas.height/2);
}
}
// Draw the entire game
function drawGame() {
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw connections first (so they appear behind the dots)
drawConnections();
// Draw all dots
dots.forEach((dot) => {
const isConnected = connectedDots.includes(dot);
drawDot(dot, isConnected);
});
}
// Handle dot clicking
function handleCanvasClick(event) {
if (gameCompleted) return;
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// Check if we clicked on the next dot in sequence
const nextDot = dots[currentDotIndex];
const distance = Math.sqrt((x - nextDot.x)**2 + (y - nextDot.y)**2);
if (distance <= 20) { // If within 20px of the dot center
connectedDots.push(nextDot);
currentDotIndex++;
// Check if game is completed
if (currentDotIndex >= dots.length) {
gameCompleted = true;
}
drawGame();
}
}
// Reset the game
function resetGame() {
currentDotIndex = 0;
connectedDots.length = 0;
gameCompleted = false;
drawGame();
}
// Event listeners
canvas.addEventListener('click', handleCanvasClick);
resetBtn.addEventListener('click', resetGame);
// Initialize the game
drawGame();
Click the dots in numerical order (1, 2, 3...) to connect them and complete the shape.
Norwegian Elkhound: *[happily barks and wags tail enthusiastically]*
GarbageMcTweak: She says, "Now THAT'S a proper way to teach path drawing. Simple, interactive, and no security issues that will summon the robot apocalypse." *[Looks at Grumpy]* Those were her words, not mine.
<canvas> element with id, width, and heightgetContext('2d')beginPath() - Start a new pathmoveTo(x, y) - Move to starting positionlineTo(x, y) - Create line to this positionclosePath() - Close path (to starting point)stroke() - Draw the path outlinefill() - Fill the path with colorstrokeStyle and fillStyle properties before renderinglineWidth to control stroke thicknesslineCap - End cap style (butt, round, square)lineJoin - Corner join style (miter, round, bevel)lineWidth - Line thickness in pixelsmiterLimit - Controls spike length at cornersNow that you've learned how to draw paths on the canvas, try these challenges to practice your skills:
SnowzieMcTweak approves these challenges!
In this episode, we learned:
Next up: We'll explore drawing circles and arcs on the Canvas!