Command Palette

Search for a command to run...

Hectal
PHASE 0Beginner ~22 min· topic 3 of 7

Topic 0.3

Two Ways to Draw: SVG and Canvas

In one line

The browser can draw in two ways. SVG keeps every shape as an element you can find, style and click. Canvas paints pixels and forgets the shapes. Each is best at different jobs, and good chart developers use both.

Think of it like this

A fridge door with magnets versus a painting. Each magnet is a separate thing: you can pick one up, move it, count them. In a painting, once the paint is down there are only colours; to move a shape you must paint the whole picture again. SVG is the magnets. Canvas is the painting.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

vector
A picture stored as shapes and coordinates (a circle at x = 30 with radius 20). It can be redrawn sharp at any size.
raster (bitmap)
A picture stored as a grid of coloured pixels, like a photo. Enlarging it makes the pixels visible.
pixel
One tiny coloured square of the screen or of an image.
DOM
Document Object Model: the tree of elements the browser builds from a page. SVG shapes are in it; canvas drawings are not.
drawing context
The object a canvas gives you (canvas.getContext("2d")) with the commands that paint on it: fillRect, arc, fill…
elementFromPoint
A browser method that tells you which element is at a given point on the screen.
RGBA
A colour as four numbers from 0 to 255: red, green, blue and alpha (opacity). [0, 0, 0, 0] is fully transparent.

Step by step

01Draw the same circle twice

The first example draws one green circle as an SVG <circle> and one with Canvas commands: beginPath(), arc(30, 30, 20, 0, Math.PI * 2) (centre x, centre y, radius, start and end angle) and fill().

Then it looks inside each. The SVG has one child element: circle. The canvas has zero children. The canvas circle exists only as coloured pixels.

02Read the pixels

getImageData(30, 30, 1, 1) reads one pixel of the canvas. At the centre it returns [42, 157, 143, 255]: red 42, green 157, blue 143, fully opaque. That is the colour #2a9d8f in numbers. In a corner it returns [0, 0, 0, 0]: nothing was painted there, so it is transparent.

03Zoom both

The CSS transform: scale(4) enlarges both drawings after they are drawn. The SVG circle stays perfectly smooth: the browser redraws the shape at the new size. The canvas circle gets soft, blurry edges: the browser can only stretch the 60 × 60 pixels it has. Topic 11.4 fixes canvas blur on sharp screens.

04Ask what is under a point

The second example asks document.elementFromPoint what lies at the circle's centre and at an empty corner of each drawing.

For SVG the answers differ: circle on the circle, svg on empty space. For the canvas both answers are CANVAS: the browser sees only the canvas. To know whether a point is inside the painted circle, the code measures the distance to the centre with Math.hypot and compares it with the radius.

Ask what is under a pointdiagram
Rendering diagram…

05Notice the tag names

The SVG answer is circle in lower case, while the canvas answer is CANVAS in capitals. HTML elements report their tagName in upper case; SVG elements keep the case they were written in, because SVG comes from XML, where case matters. Tests that compare tag names should use .toLowerCase().

Try it yourself

  1. 1

    Recolour the SVG circle with CSS

    In the first example, add circle { fill: orange; } to the CSS and press Run. The SVG circle turns orange: it is an element, so CSS can reach it. The canvas circle stays green: no CSS selector can reach pixels.

  2. 2

    Change a pixel

    In the first example, change getImageData(30, 30, …) to getImageData(10, 30, …). The point (10, 30) is exactly on the circle's edge (30 − 20 = 10), so you get a partly transparent pixel: the line still says "Pixel at the centre" but prints [ 41, 156, 142, 240 ]. The browser blends edge pixels to make the curve look smooth, so the fourth number (alpha) is 240, not 255.

  3. 3

    Grow the HTML bars

    In the third example, change .chart's width from 360px to 200px. Every bar keeps its share: Tuesday fills 200 pixels and Monday about 149. Percentages make HTML bars resize with their box for free.

Code & diagrams

The same circle as SVG and as Canvas New tab

Look closely at the edges of the two circles in the preview: sharp on the left, soft on the right.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Inside the SVG: 1 element -> circle
Inside the canvas: 0 elements
Pixel at the centre: [ 42, 157, 143, 255 ]
Pixel in a corner: [ 0, 0, 0, 0 ]
What is under the mouse? New tab

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

SVG, on the circle: circle
SVG, on empty space: svg
Canvas, on the circle: CANVAS
Canvas, on empty space: CANVAS
Is (40, 40) inside the canvas circle? true
Is (100, 10) inside the canvas circle? false
A third way: bars made of HTML and CSS New tab

CSS does the arithmetic: calc(2979 / 3992 * 100%) of 360 pixels is about 269 pixels.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Mon 269 px wide
Tue 360 px wide
Sat 272 px wide

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Look for the canvas circle like an SVG one

In the first example, add this line at the end: console.log(canvas.querySelector("circle").tagName);

terminal
$ Console
── what you'll see ──
Inside the SVG: 1 element -> circle
Inside the canvas: 0 elements
Pixel at the centre: [ 42, 157, 143, 255 ]
Pixel in a corner: [ 0, 0, 0, 0 ]
Uncaught TypeError: Cannot read properties of null (reading 'tagName')

Myth vs fact

Myth

Canvas is always faster than SVG.

Fact

For a few hundred shapes, both are fast, and SVG is simpler. Canvas gets ahead when there are many thousands of marks, or many redraws per second. Measure (Topic 12.1) before switching.

Myth

SVG is an image file format, like PNG.

Fact

SVG can be saved as a .svg file, but inside a web page it is live markup: elements in the DOM that JavaScript and CSS can change, like HTML.

Myth

Canvas drawings can't be made accessible.

Fact

A canvas is a single image to a screen reader, so you must add the information yourself: a label, a description, a data table (Topics 11.6 and 15.3). It takes more work than SVG, but it is possible.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    SVG elements cost what DOM nodes cost: style resolution, layout of the SVG box, painting, and memory per node (attributes, event listeners, __data__ once D3 binds data). Canvas costs are per pixel and per draw call, independent of how many shapes you've drawn before. That is why the crossover depends on mark count and redraw frequency, not on chart type.

  • ▸

    Canvas edge pixels are anti-aliased: a pixel half-covered by the circle gets about half the alpha. getImageData therefore returns intermediate values on edges, and pixel-exact tests should sample shape interiors, never edges.

  • ▸

    document.elementFromPoint respects pointer-events: an SVG shape with pointer-events: none is skipped, and the element behind it is returned. Charts use this to put thin lines on top without blocking hover on the shapes below (Topic 8.1).

Remember this

  1. 1

    The problem this solves: choosing the wrong one costs you later. An SVG chart with 200,000 dots becomes slow; a Canvas chart can't tell you which dot was clicked without extra work. Knowing how each one works lets you choose before you build.

  2. 2

    SVG keeps shapes. SVG (Scalable Vector Graphics) describes shapes as tags: <circle cx="30" cy="30" r="20">. Each one is an element in the page's DOM (the tree of elements the browser keeps for the page), just like a <p> or a <button>. You can find it with querySelector, style it with CSS, read its attributes, and listen for clicks on it. The browser redraws it for you whenever something changes, and draws it sharp at any zoom, because it keeps the shape, not the pixels.

  3. 3

    Canvas keeps pixels. A <canvas> is a grid of pixels, like a photo. Your JavaScript gets a drawing context (getContext("2d")) and calls commands such as arc() and fill(), which colour pixels. Afterwards the browser remembers only the colours. There is no circle element inside the canvas. Zoom in and you see blurry pixel edges. To change a shape, you clear and repaint.

  4. 4

    What "what is under the mouse" means for each. On an SVG chart, the browser knows each shape, so a click lands on the exact <circle>. On a canvas, every click lands on the canvas itself, and your code must work out which shape (if any) was at that point. The second example asks the browser directly with document.elementFromPoint, and the answers show the difference.

  5. 5

    When each wins. SVG is ideal for most charts: a few hundred to a few thousand marks, sharp text, easy interaction and accessibility. Canvas wins when there are tens or hundreds of thousands of marks (every trip in a year, every point of a sensor), because pixels cost the same however many shapes made them. Topic 12.1 measures the crossover on your own device. Beyond that sits WebGL, which draws with the graphics card (a later Hectal course).

  6. 6

    A third way: HTML and CSS. Simple bar charts can be plain <div>s whose width comes from a CSS variable. They are accessible and short to write, but limited to boxes: no lines, curves or maps. The third example builds one. Topic 3.1 shows when it's enough.

Explain it without notes

01

Explain the difference between SVG and Canvas to someone who has never coded.

02

Why does the canvas circle look blurry when zoomed, but the SVG one doesn't?

03

You need a chart of 300 stations that people can click. Which would you choose, and why?

04

You need to draw every trip of a year (about 300,000 lines) and redraw it while panning. Which would you choose, and why?

Practice

01

Add a second circle to both drawings in the first example (SVG: a new <circle> tag; Canvas: another beginPath/arc/fill). Then log how many elements each contains.

02

In the second example, write insideRect(x, y) for a rectangle drawn with ctx.fillRect(70, 20, 30, 40), and test (80, 30) and (60, 30).

Trade-offs

  • ↔

    SVG: easy to style, inspect, click and make accessible, but each shape is a DOM node, so very large counts get slow.

  • ↔

    Canvas: fast for huge numbers of marks and constant redraws, but you rebuild interaction, text quality and accessibility yourself.

  • ↔

    HTML/CSS bars: the simplest and most accessible for a few bars, but only boxes.

Done when you can

  • I can explain SVG and Canvas with the magnets and painting picture.

  • I can show that an SVG shape is an element and a canvas shape is only pixels.

  • I can read a canvas pixel with getImageData and explain the four numbers.

  • I can choose between SVG and Canvas for a given chart and say why.