Canvas Shapes
Canvas paths are the building blocks behind every shape you draw — this lesson shows how beginPath() and closePath() control where a shape starts, stops, and connects.
What Is a Path in Canvas?
A path in the Canvas API is an internal list of points and the straight or curved segments that connect them. You build a path with drawing commands such as moveTo() and lineTo(), then make it visible by calling stroke() to draw its outline or fill() to paint its interior. Until one of those rendering calls runs, nothing appears on screen — the path exists only as data inside the 2D rendering context.
Starting Fresh with beginPath()
Calling beginPath() clears the list of sub-paths the context is currently tracking and resets the current point. You should call it at the start of every shape that is not meant to connect to the previous one. If you skip beginPath(), the next moveTo() or lineTo() call continues appending to whatever path segments already exist, which can silently reintroduce old geometry into your next stroke() or fill().
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('scene');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(50, 140); // starting point, nothing drawn yet
ctx.lineTo(150, 140); // bottom edge of the triangle
ctx.lineTo(100, 40); // up to the peak
ctx.closePath(); // straight line back to (50, 140)
ctx.strokeStyle = '#2563eb';
ctx.lineWidth = 3;
ctx.stroke();
</script>
</body>
</html>Closing the Loop with closePath()
closePath() draws a straight line from the current point back to the first point of the active sub-path and marks that sub-path as closed. This matters most when you stroke a shape: without it, the final edge is simply never drawn, leaving a visible gap, and the corner where the shape should meet stays two separate open ends instead of a joined corner. fill() is more forgiving — it always treats an open sub-path as implicitly closed for the purpose of coloring its interior — which is why a shape can look filled correctly but stroke with a missing edge if you forget closePath().
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
// First shape: a small square
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(80, 20);
ctx.lineTo(80, 80);
ctx.lineTo(20, 80);
ctx.closePath();
ctx.fillStyle = '#16a34a';
ctx.fill();
// Second shape: an unrelated triangle
ctx.beginPath();
ctx.moveTo(150, 80);
ctx.lineTo(220, 80);
ctx.lineTo(185, 20);
ctx.closePath();
ctx.fillStyle = '#f97316';
ctx.fill();
</script>
</body>
</html>- moveTo(x, y) repositions the current point without drawing anything
- lineTo(x, y) draws a straight segment from the current point to (x, y)
- closePath() adds a line back to the sub-path's starting point and closes it
- beginPath() clears all existing sub-paths so the next shape starts clean
- stroke() outlines the current path; fill() paints its interior
- A path can contain multiple sub-paths, each started by its own moveTo()
Example
<!DOCTYPE html>
<html>
<body>
<canvas id="scene" width="300" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const ctx = document.getElementById('scene').getContext('2d');
ctx.beginPath();
ctx.moveTo(100, 20);
ctx.lineTo(140, 90);
ctx.lineTo(180, 40);
ctx.lineTo(160, 110);
ctx.lineTo(60, 110);
ctx.lineTo(40, 40);
ctx.lineTo(80, 90);
ctx.closePath();
ctx.fillStyle = 'rgba(147, 51, 234, 0.7)';
ctx.fill();
ctx.strokeStyle = '#4c1d95';
ctx.lineWidth = 2;
ctx.stroke();
</script>
</body>
</html>Exercise: Canvas Shapes
Does the Canvas 2D API provide a built-in method to draw a triangle directly?