Using paths in Canvas


We've seen how powerful D3 is for transforming a dataset into an SVG path. For example, give it a radius and angle, and it can easily generate an arc path.

But how can we use this same data to draw the shape with canvas? Let’s explore.

Free
4 minutes read

Remember the area chart?

Before we start using canvas, let's remind quickly how to build an area chart with react and d3.

Everything starts with a dataset.

const data = [
  {x:1, y: 90},
  {x: 2, y: 12},
  {x: 3, y: 34},
  {x: 4, y: 53},
  {x: 5, y: 98},
]

Then, d3.area() is used to create an area generator. This generator (called areaBuilder below) transforms a blob of data into a string that can be used as the d argument of a path SVG shape.

// create a shape generator.
// areaBuilder will be a function that takes data as input and returns a SVG path
const areaBuilder = d3
  .area()
  .x(d => xScale(d.x))
  .y1(d => yScale(d.y))
  .y0(yScale(0));

// call the function with the dataset
const areaPath = areaBuilder(data);
// M0,0 L57.778,277.333 L115.556,199.111 ... Z

The output areaPath can now be passed to a path SVG element!

<path d={areaPath} fill="#9a6fb0" />

It results in a cool area chart:

A very basic area chart made using react and the area() function of d3.js

😞 The Problem

D3 does an amazing job here! It transforms our dataset into a string like M0,0 L57,277 L115,199 ... Z, which we can directly pass to an SVG path element. πŸ‘

But how can we use this path data to draw on a canvas instead of SVG?

Path2D to the rescue! 🍾

Luckily, there's a lifesaving feature in the Canvas API: Path2D.

Path2D allows you to take any SVG path string and easily draw it on the canvas. It simplifies the process considerably:

// areaPath is computed with d3: M0,0 L57.778,277.333 L115.556,199.111 ... Z

// Then in the useEffect:
const ctx = canvas.getContext('2d');
const path = new Path2D(areaPath); // Convert to Path2D
ctx.fill(path); // Now you can fill or stroke the path

Let's see it in action on a full chart:

A minimal area chart made in canvas thanks to d3.area() and Path2D

Too easy!

That makes it a breeze!

Let's try on a donut chart to see if it works the same:

A minimal donut chart made in canvas