Line

To create a line, we use the d3.line() generator and define the x- and y-accessor functions. Accessors tell the generator how to read the x and y coordinates from data points.

In D3 v3, these generators were found under the d3.svg namespace. In v4, they're all in the top-level namespace, or in d3-shape. If you get errors, such as Cannot read property 'line' of undefined when replicating an example you found online, the example quite possibly is still using D3 v3.

We begin by defining two scales. If you remember from Chapter 1, Getting Started with D3, ES2017, and Node.js, scales are functions that map from a domain to a range; we'll talk more about them in the next chapter:

const x = d3.scaleLinear() 
.range([
0,
(chart.width / 2) - (chart.margin.left + chart.margin.right),
])
.domain(d3.extent(sine, d => d[0]));

const y = d3.scaleLinear()
.range([
(chart.height / 2) - (chart.margin.top + chart.margin.bottom),
0,
])
.domain([-1, 1]);

With those in place, we now use them to define our path generator:

const line = d3.line() 
.x(d => x(d[0]))
.y(d => y(d[1]))

It is just a matter of taking the basic line generator and attaching some accessors to it. We told the generator to use our x scale on the first element and the y scale on the second element of every array. By default, it assumes our dataset is a collection of arrays defining points directly so that d[0] is x and d[1] is y.

All that's left now is drawing the actual line:

  const g = chart.container.append('g'); 
g.append('path')
.datum(sine)
.attr('d', line)
.attr('stroke', 'steelblue')
.attr('stroke-width', 2)
.attr('fill', 'none');

This creates a new group element, to which it appends a path, and adds the sine data using .datum(). Using this instead of .data() means that we can render the function as a single element instead of creating a new line for every point. We let our generator define the d attribute. The rest just makes things visible.

Our graph now looks as follows:

If you look at the resulting code in Chrome Dev Tools, you see something resembling the following gibberish:

<path d="M0,185L42.83333333333333,0L85.66666666666666,184.99999999999997L128.5,370L171.33333333333331,185.00000000000003L214.16666666666669,0L257,184.99999999999991L299.8333333333333,370L342.66666666666663,185.00000000000009L385.5,0" stroke="steelblue" stroke-width="2" fill="none"></path>

Although it's shorter than our JavaScript, our JavaScript is much more readable and much easier to reason about.

Our sine function is very jagged, nothing like what our math teachers used to draw during high school. We can make it better using interpolation.

Interpolation is the act of guessing where unspecified points of a line should appear, considering the points we do know. By default, we're using the linear interpolator that just draws straight lines between points.

Our linear interpolator is kind of boring. Let's fix that!

Add the following to our function:

g.append('path') 
.datum(sine)
.attr('d', line.curve(d3.curveStepBefore))
.attr('stroke', 'black')
.attr('stroke-width', 1)
.attr('fill', 'none');

It is the same code as before, but we used the d3.curveStepBefore interpolator and changed the styling to produce this:

All we've done is set the curve factory on our generator to one of D3's built-in interpolators. The .curve method of our line generator takes an interpolation function (here, we've supplied the step before curve method built into D3), and returns the line generator. This returned line generator is then supplied to the d function of the path, so we get a different sort of shape than we did before.

This is a very good example of the style of functional programming that D3 embraces, and you'll see it frequently throughout the book.

D3 offers 18 line interpolators in total, which are all listed with an example in the official wiki page for d3-shape, https://github.com/d3/d3-shape/blob/master/README.md#curves.

I suggest trying out all of them to get a feel of what they do.

New in D3 v4, line.interpolate has been renamed line.curve, and instead of supplying it a string, you supply it a function attached to either the d3 namespace or the d3-shape module, depending on which you're using. See the preceding URL for all available built-in interpolation functions.
..................Content has been hidden....................

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