Using d3 to shade area between two lines

99封情书 提交于 2019-11-27 13:43:34

Since you don't have datapoints at the intersections, the simplest solution is probably to get the areas above and below each line and use clipPaths to crop the difference.

I'll assume you're using d3.svg.line to draw the lines that the areas are based on. This way we'll be able to re-use the .x() and .y() accessor functions on the areas later:

var trafficLine = d3.svg.line()
  .x(function(d) { return x(d3.time.format("%m/%d/%Y").parse(d.original.date)); })
  .y(function(d) { return y(parseInt(d.original.traffic)); });

var rateLine = d3.svg.line()
  .x(trafficLine.x()) // reuse the traffic line's x
  .y(function(d) { return y(parseInt(d.original.rate)); })

You can create separate area functions for calculating the areas both above and below your two lines. The area below each line will be used for drawing the actual path, and the area above will be used as a clipping path. Now we can re-use the accessors from the lines:

var areaAboveTrafficLine = d3.svg.area()
  .x(trafficLine.x())
  .y0(trafficLine.y())
  .y1(0);
var areaBelowTrafficLine = d3.svg.area()
  .x(trafficLine.x())
  .y0(trafficLine.y())
  .y1(height);
var areaAboveRateLine = d3.svg.area()
  .x(rateLine.x())
  .y0(rateLine.y())
  .y1(0);
var areaBelowRateLine = d3.svg.area()
  .x(rateLine.x())
  .y0(rateLine.y())
  .y1(height);

...where height is the height of your chart, and assuming 0 is the y-coordinate of the top of the chart, otherwise adjust those values accordingly.

Now you can use the area-above functions to create clipping paths like this:

var defs = svg.append('defs');

defs.append('clipPath')
  .attr('id', 'clip-traffic')
  .append('path')
  .datum(YOUR_DATASET)
  .attr('d', areaAboveTrafficLine);

defs.append('clipPath')
  .attr('id', 'clip-rate')
  .append('path')
  .datum(YOUR_DATASET)
  .attr('d', areaAboveRateLine);

The id attributes are necessary because we need to refer to those definitions when actually clipping the paths.

Finally, use the area-below functions to draw paths to the svg. The important thing to remember here is that for each area-below, we need to clip to the opposite area-above, so the Rate area will be clipped based on #clip-traffic and vice versa:

// TRAFFIC IS ABOVE RATE
svg.append('path')
  .datum(YOUR_DATASET)
  .attr('d', areaBelowTrafficLine)
  .attr('clip-path', 'url(#clip-rate)')

// RATE IS ABOVE TRAFFIC
svg.append('path')
  .datum(YOUR_DATASET)
  .attr('d', areaBelowRateLine)
  .attr('clip-path', 'url(#clip-traffic)')

After that you'll just need to give the two regions different fill colors or whatever you want to do to distinguish them from one another. Hope that helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!