A canvas path represents a sequence of points cnonected by lines and curves. The Canvas 2D API provides methods to build and render these paths, giving you fine-grained control over complex shapes.
Core Drawing Commands
Paths rely on a small set of commands:
moveTo(x, y)– lifts the pen and sets a new starting point.lineTo(x, y)– draws a straight line from the current position to(x, y).arc(x, y, radius, startAngle, endAngle, anticlockwise)– traces a circular arc.arcTo(x1, y1, x2, y2, radius)– creates an arc based on two tangent lines.quadraticCurveTo(cpx, cpy, x, y)– a quadratic Bézier curve with one control point.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)– a cubic Bézier curve with two control points.closePath()– draws a straight line back to the start of the current sub‑path.beginPath()– starts a fresh path, discarding any previously defined path data.
Once a path is defined, you can fill it with fill() or outline it with stroke().
Typical Workflow
- Obtain a reference to the
<canvas>element. - Get the 2D rendering context via
canvas.getContext('2d'). - Call
beginPath()to reset the path. - Build the shape with commands like
moveTo,lineTo,arc, etc. - Optionally set style propreties (e.g.,
fillStyle,strokeStyle,lineWidth). - Render the path with
fill()and/orstroke().
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(30, 30);
ctx.lineTo(150, 30);
ctx.lineTo(90, 120);
ctx.closePath();
ctx.fillStyle = '#ffcc66';
ctx.fill();
ctx.strokeStyle = '#444';
ctx.lineWidth = 2;
ctx.stroke();
Advanced: Animating a Shape Along a Path
Paths are16 often the foundation for animation. The example below draws a sinusoidal curve and moves a red circle along it. Each frame clears the cenvas, redraws the curve, and repositions the circle based on a sine calculation.
const canvas = document.getElementById('waveCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
const centerY = height / 2;
const amplitude = 90;
const frequency = 0.02;
function drawWave() {
ctx.beginPath();
ctx.moveTo(0, centerY + amplitude * Math.sin(0));
for (let x = 0; x <= width; x++) {
const y = centerY + amplitude * Math.sin(frequency * x);
ctx.lineTo(x, y);
}
ctx.strokeStyle = '#2a7ae2';
ctx.lineWidth = 2;
ctx.stroke();
}
let ballX = 0;
const ballRadius = 10;
function animate() {
ctx.clearRect(0, 0, width, height);
drawWave();
const ballY = centerY + amplitude * Math.sin(frequency * ballX);
ctx.beginPath();
ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = '#e63946';
ctx.fill();
ballX += 1;
if (ballX > width) {
ballX = 0;
}
requestAnimationFrame(animate);
}
animate();
Variations of this technique can drive data visualizations, game physics, or interactive UI elements by replacing the mathematical function with any path definition.