Using paths

In Chapter 2, A Primer on DOM, SVG, and CSS, we created a few sundry shapes with a maximum of four points. Although those will get you pretty far drawing basic charts, for complex shapes we'll need to draw paths. Path elements define outlines of shapes that can be filled, stroked, and so on. They are generalizations of all other shapes and can be used to draw nearly anything.

Wait: what about polyline and polygon? While those are also multipoint SVG primitives, they're really pretty much identical to path.

Most of the path's magic stems from the d attribute; it uses a mini language (in programming terms, a domain-specific language, or DSL) of three basic commands:

  • M, meaning moveto
  • L, meaning lineto
  • Z, meaning closepath

To create a path, we might write something like the following:

Create a new folder in lib/ called chapter3/ and put an index.js in it. In lib/main.js, change the following line:

import './chapter2/index';

Change it to read:

import './chapter3/index';

Then, create a new function like so:

export function yayPaths() { 
const path = chart.container.append('path')
.attr('d', 'M 10 500 L 300 100 L 300 500 M 300 100 l 100 0 M 155 300 l 245 0 M 300 500 l 100 0')
.attr('stroke', 'black')
.attr('stroke-width', 2)
.attr('fill', 'transparent');
}
yayPaths();

We appended a new element to our SVG and then defined some attributes. The interesting bit is the d attribute:

M 10 500 L 300 100 L 300 500 M 300 100 l 100 0 M 155 300 l 245 0  M 300 500 l 100 0

What's going on here? SVG path directions always start with a capital M, meaning move the pen here--in this case, (10, 500). Then, we draw a line using capital L to (300, 100), then again to (300, 500). We then move the pen to (300, 100), and draw a line using a lowercase l--lowercase letters mean to use relative values; in this case, draw 100 pixels horizontally to the right so that the pen rests at (400, 100). We then move the pen to (155, 300), draw a 245 pixel-length line to the right, then move to (300, 500) and draw another 100-pixel line.

Reload your browser to see what we drew. Hmm, this looks familiar:

The power of paths doesn't stop there, though. Commands beyond the M, L, l combination give us tools to create curves and arcs. As you now know, creating complex shapes by hand is incredibly tedious.

Fortunately, D3 comes with some helpful path generator functions that take JavaScript and turn it into path definitions. We'll be looking at those next.

Let's get rid of that glorious diphthong you just drew by replacing all the code inside chapter3.js with the following:

import * as d3 from 'd3'; 
import chartFactory from '../common/index';
export function yayPaths() {
const chart = chartFactory();
}

yayPaths();

This instantiates our new function, which generates a new chart using our factory; we've done this before.

To start things off, we'll draw the humble sine function. First, we need some data, which we'll generate using the built-in JavaScript sine function, Math.sin:

  const sine = d3.range(0, 10) 
.map(k => [0.5 * k * Math.PI, Math.sin(0.5 * k * Math.PI)]);

Using d3.range(0,10) gives us a list of integers from zero to nine. We map over them and turn each into a 2-length array representing the maxima and minima of the curve. You might remember from your math class that sine starts at (0,0), then goes to (Pi/2, 1), (Pi, 0), (3Pi/2, -1), and so on.

We'll feed these as data into a path generator.

Path generators are really the meat of D3's magic. They're a big topic, and we will discuss them in more detail in Chapter 6, Hierarchical Layouts of D3. They are essentially a function that takes some data (joined to elements) and produces a path definition in SVG's path mini language. All path generators can be told how to use our data. We also get to play with the final output a great deal.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset