Chapter 36: Canvas Lines
Canvas Lines.
I’m going to explain this the way a patient, slightly excited teacher would: slowly, clearly, with small complete examples, visual thinking, common mistakes highlighted, and lots of copy-paste code you can run immediately.
We will build from the tiniest line to more interesting patterns — no skipping steps.
Canvas Lines – Complete Beginner-to-Confident Guide
1. The absolute most important mental model about lines in Canvas
A line in Canvas is not an object that lives forever (like in SVG).
It is a path instruction you give to the painter:
- You tell him: “pick up the pen, move to this point, draw to that point”
- He paints the pixels immediately when you say stroke()
- After that the pixels are just pixels — there is no “line object” you can move or click later
That is why almost every line-drawing code follows this exact 4-step pattern:
|
0 1 2 3 4 5 6 7 8 9 |
ctx.beginPath(); // ← very important – forget it and lines connect to previous paths ctx.moveTo(x1, y1); // pen up + jump to start ctx.lineTo(x2, y2); // draw line to end point ctx.stroke(); // ← actually paint the pixels |
2. Minimal complete line example (copy → run)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas – First Line</title> <style> canvas { border: 1px solid #ccc; background: #f8f9fa; display: block; margin: 40px auto; } </style> </head> <body> <canvas id="c" width="600" height="400"></canvas> <script> const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); // Basic black line from top-left to bottom-right ctx.beginPath(); ctx.moveTo(50, 50); // start point ctx.lineTo(550, 350); // end point ctx.strokeStyle = '#333'; ctx.lineWidth = 6; ctx.stroke(); // ← this actually draws it </script> </body> </html> |
What we just learned in plain English:
- beginPath() → tells Canvas “forget any previous unfinished path — start fresh”
- moveTo(x, y) → lift pen and jump to starting point (no line drawn yet)
- lineTo(x, y) → draw a straight line to this new point
- stroke() → paint the line using current strokeStyle and lineWidth
3. Most important line properties (copy these cheats)
| Property | What it controls | Common values | Default | Very useful? |
|---|---|---|---|---|
| strokeStyle | Color of the line | ‘#2196F3’, ‘rgba(33,150,243,0.7)’, ‘red’ | black | ★★★★★ |
| lineWidth | Thickness in pixels | 1, 4, 12, 0.5 | 1 | ★★★★★ |
| lineCap | Shape at line ends | ‘butt’ / ’round’ / ‘square’ | ‘butt’ | ★★★★☆ |
| lineJoin | Shape at corners / joins | ‘miter’ / ’round’ / ‘bevel’ | ‘miter’ | ★★★★☆ |
| setLineDash([a,b]) | Creates dashed / dotted pattern | [10,5], [2,8], [20,10,5,10] | solid | ★★★★★ |
| lineDashOffset | Shifts where dash pattern starts | number (positive or negative) | 0 | ★★★☆☆ |
4. Example 2 – Different line endings (lineCap)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<canvas id="c2" width="600" height="300"></canvas> <script> const canvas = document.getElementById('c2'); const ctx = canvas.getContext('2d'); ctx.lineWidth = 30; // butt (default – flat cut) ctx.beginPath(); ctx.moveTo(100, 80); ctx.lineTo(500, 80); ctx.lineCap = 'butt'; ctx.strokeStyle = '#333'; ctx.stroke(); // round (nice half-circle caps) ctx.beginPath(); ctx.moveTo(100, 150); ctx.lineTo(500, 150); ctx.lineCap = 'round'; ctx.strokeStyle = '#2196F3'; ctx.stroke(); // square (extends half lineWidth beyond end) ctx.beginPath(); ctx.moveTo(100, 220); ctx.lineTo(500, 220); ctx.lineCap = 'square'; ctx.strokeStyle = '#4CAF50'; ctx.stroke(); // Labels ctx.font = '20px Arial'; ctx.fillStyle = '#333'; ctx.textAlign = 'center'; ctx.fillText('butt (default)', 300, 60); ctx.fillText('round (best for dots)', 300, 130); ctx.fillText('square', 300, 200); </script> |
Quick tip: lineCap = ’round’ is very popular for dotted lines and organic feel.
5. Example 3 – Dashed & dotted lines (setLineDash)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<canvas id="c3" width="600" height="300"></canvas> <script> const canvas = document.getElementById('c3'); const ctx = canvas.getContext('2d'); ctx.lineWidth = 8; // Long dashes ctx.setLineDash([15, 10]); // dash 15px, gap 10px ctx.beginPath(); ctx.moveTo(50, 60); ctx.lineTo(550, 60); ctx.strokeStyle = '#673AB7'; ctx.stroke(); // Dotted ctx.setLineDash([2, 8]); // tiny dash, long gap ctx.lineCap = 'round'; // makes dots look nice ctx.beginPath(); ctx.moveTo(50, 140); ctx.lineTo(550, 140); ctx.strokeStyle = '#F44336'; ctx.stroke(); // Dash – dot – long dash pattern ctx.setLineDash([20, 5, 5, 5]); ctx.beginPath(); ctx.moveTo(50, 220); ctx.lineTo(550, 220); ctx.strokeStyle = '#009688'; ctx.stroke(); // Reset to solid line ctx.setLineDash([]); </script> |
Tip: To make marching-ants selection effect, animate lineDashOffset.
6. Example 4 – Multiple connected lines (polyline style)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<canvas id="c4" width="600" height="300"></canvas> <script> const canvas = document.getElementById('c4'); const ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(80, 200); ctx.lineTo(180, 80); ctx.lineTo(280, 220); ctx.lineTo(380, 100); ctx.lineTo(480, 180); ctx.lineTo(580, 120); ctx.strokeStyle = '#FF5722'; ctx.lineWidth = 10; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.stroke(); </script> |
Note: This is exactly how you draw polylines / connected line charts in Canvas.
Your three tiny practice tasks (10–15 min each)
Task 1 – Traffic lines Draw three horizontal lines across the canvas:
- thick solid black at y=100
- medium dashed blue at y=200
- thin dotted red at y=300 (use round caps)
Task 2 – Zigzag lightning Start at (100,50), draw a zigzag down to (500,350) with 6–8 sharp turns, thick orange line, round caps.
Task 3 – Coordinate cross Draw a thin gray cross through the center + label the center point “(300,200)” with text.
Paste any of them here when you’re done — I’ll review them like we’re sitting together debugging.
Which part still feels a little slippery?
- Why we need beginPath() every time?
- Difference between stroke() and fill()?
- How lineCap and lineJoin actually look?
- Making nice dashed lines?
- Something else?
Tell me — we’ll stay on lines until you feel 100% comfortable drawing anything with them.
You’re doing really well — lines are the foundation of almost every interesting Canvas drawing. 🚀
