Ad

Choose The Right Interpolation In D3 To Center A Path (line) Inside A Path (area)

- 1 answer

By way of example, consider the following D3 code (only the relevant part, the complete - but only less than a dozen lines longer - code is on JSFiddle) which draws a line inside a band.

    var points = [
    [200, 100],
    [200, 200],
    [100, 300],
    [100, 400]
    ];

    var areaGenerator=d3.area()
    .curve(d3.curveMonotoneY)
    .x0(function(d){return d[0]-20})
    .x1(function(d){return d[0]+20})
    .y0(function(d,i){return d[1]})
    .y1(function(d,i){return d[1]})
    ;
    var area = areaGenerator(points);

    svg.append('path')
    .attr('d', area);

    svg.append("path")
    .data([points])
    .attr("d", d3.line()
    .curve(d3.curveCardinal
    .tension(0.8)))
    .attr("id","line")

Here is an image of the resulting svg object:

enter image description here

I've tried several value for .tension() but I'm unable to find the right interpolation function to make the line to lie (approximately) in the middle of the band for its whole flow, subjected to the constraint that the first and the last sections of both the line and the band should be exactly vertical and they cannot "enlarge" to the left or to the right.

This is what I want to obtain, approximately:

enter image description here

Ad

Answer

My original answer wasn't thought through. You can simply apply the same curve property to the black path as you do to your red path: https://jsfiddle.net/s5o4hp3z/

Simply change the black path to this:

svg.append("path")
  .data([points])
  .attr("d", d3.line().curve(d3.curveMonotoneY))
  .attr("id","line")

------- Original answer -------

You can use an area generator similar to the one you use for your red area, but with width properties making it look like a line.

I've modified your JSFiddle to showcase this: https://jsfiddle.net/6e03o42f/3/

What I've done is to change the path creation to this:

var lineAreaGenerator = d3.area()
  .curve(d3.curveMonotoneY)
  .x0(function(d){return d[0]-0.5})
  .x1(function(d){return d[0]+0.5})
  .y0(function(d,i){return d[1]})
  .y1(function(d,i){return d[1]});

var lineArea = lineAreaGenerator(points);

svg.append("path")
  .attr("d", lineArea)
  .attr("id","line")

If this is indeed the approach you choose, then one would want to seperate the area generator code into a function. I've shown how do this in this JSFiddle: https://jsfiddle.net/6e03o42f/4/

Hope this helps!

Ad
source: stackoverflow.com
Ad