两个折线图之间的 D3 区域

d3 area between two line graphs

本文关键字:之间 D3 区域 折线图 两个      更新时间:2023-09-26

我想填充下面定义的两个面积图之间的线条。我遇到了一点墙 - 我似乎遇到的问题是,我创建的每条路径都没有其他价值可以比较,而我寻找解决方法的努力似乎遇到了一点墙。

有什么提示吗?

jQuery(document).ready(function ($) {
  var margin = {top: 20, right: 30, bottom: 40, left: 24},
  width = 430 - margin.left - margin.right,
  height = 225 - margin.top - margin.bottom,
  dotRadius = function() { return 3 };
  var x = d3.time.scale()
    .range([0, width]);
  var y = d3.scale.linear()
    .range([height, 0]);
  var xAxis = d3.svg.axis()
    .scale(x)
    .orient('bottom')
    .tickFormat(d3.time.format('%b'));
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient('left');
  // This is a function that determines the colours of the lines drawn, up to 10.
  var color = d3.scale.category10();
  // This is used to format the time for our data.
  var formatTime = d3.time.format("%Y-%m-%d");
  var line = d3.svg.line()
    .x(function(d) { return x(d.Period); })
    .y(function(d) { return y(d.Value); })
  var areaBetweenGraphs = d3.svg.area()
  .x(function(d) { 
    console.log('ABG x is: ', d);
    return x(formatTime.parse(d.Time));
  })
  .y0(function(d) {
    console.log('ABG y0 is: ', d);
    return y(d.Quantity);
  })
  .y1(function(d) {
    console.log('ABG y1 is: ', d);
    return y(d.Amount);
  });
  var svg = d3.select("#pipeline-chart-render")
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
    .append('g')
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
  // This separates the data into the lines we want, although the data is stored
  // In the same original object.
  color.domain(d3.keys(data[0].values[0]).filter(function(key) { 
    if (key === 'Amount'
     || key === 'Quantity') {
        return key
    }
  }));
  // This returns the data into two separate objects which can be graphed.
  // In this case, Amount and Quantity.
  var datasets = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {
          Period: formatTime.parse(d.values[0].Time),
          Value: +d.values[0][name]};
      })
    };
  });
  console.log('datasets is: ', datasets);
  // set the minYDomainValue to zero instead of letting it be a lingering magic number.
  var minDomainValue = 0
  var minDate = d3.min(datasets, function(d0){
    return d3.min(d0.values, function(d1){
      return d1.Period;
    })
  }),
  maxDate = d3.max(datasets, function(d0){
    return d3.max(d0.values, function(d1){
      return d1.Period;
    })
  });
  x.domain([minDate, maxDate]);
  y.domain([
    minDomainValue,
    d3.max(datasets, function(c) { return d3.max(c.values, function(v) { return v.Value; }); })
  ])
  // Append the x-axis class and move axis around.
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis)
  // Append the y-axis class.
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
  svg.append('g')
  var pipeline = svg.selectAll('.pipeline')
    .data(datasets);
  pipeline.enter()
    .append('g')
    .attr('class', 'pipeline');

  pipeline.append('path')
    .attr('class', 'line')
    .attr('id', function(d, i) {
      return 'pipeline-'+(i+1);
    })
    .attr('d', function(d) { console.log('line d is: ', d); return line(d.values); })
    .attr("data-legend",function(d) { return d.name})
    .style("stroke", function(d) { return color(d.name); })
  pipeline.exit().remove()
  // Rendering the points on the graph.
  var points = svg.selectAll('.pipelinePoint')
    .data(datasets);
  points
    .enter()
    .append('g')
    .attr('class', 'pipelinePoint');
  points.selectAll('.point')
    .data(function(d) {
      return d.values;
    })
    .enter()
    .append('circle')
    .attr('circleId', function(d, i) { 
      return 'circleId-'+i;
      })
    .attr('cx', function(d) {
      return x(d.Period);
      })
    .attr('cy', function(d) {
      return y(d.Value);
    })
    .attr('r', function(d) { 
      return dotRadius()
    });
});
var data = [
  {
    key: 1,
    values: [
      {
        Amount: 33,
        Quantity: 22,
        Time: '2015-01-01'
      }
    ]
  },
  {
    key: 2,
    values: [
      {
        Amount: 52,
        Quantity: 20,
        Time: '2015-02-01'
      }
    ]
  },
  {
    key: 3,
    values: [
      {
        Amount: 63,
        Quantity: 30,
        Time: '2015-03-01'
      }
    ]
  },
  {
    key: 4,
    values: [
      {
        Amount: 92,
        Quantity: 60,
        Time: '2015-04-01'
      }
    ]
  },
  {
    key: 5,
    values: [
      {
        Amount: 50,
        Quantity: 29,
        Time: '2015-05-01'
      }
    ]
  },
  {
    key: 6,
    values: [
      {
        Amount: 53,
        Quantity: 25,
        Time: '2015-06-01'
      }
    ]
  },
  {
    key: 7,
    values: [
      {
        Amount: 46,
        Quantity: 12,
        Time: '2015-07-01'
      }
    ]
  },
  {
    key: 8,
    values: [
      {
        Amount: 52,
        Quantity: 15,
        Time: '2015-08-01'
      }
    ]
  },
  {
    key: 9,
    values: [
      {
        Amount: 55,
        Quantity: 20,
        Time: '2015-09-01'
      }
    ]
  },
  {
    key: 10,
    values: [
      {
        Amount: 35,
        Quantity: 17,
        Time: '2015-10-01'
      }
    ]
  },
  {
    key: 11,
    values: [
      {
        Amount: 80,
        Quantity: 45,
        Time: '2015-11-01'
      }
    ]
  },
  {
    key: 12,
    values: [
      {
        Amount: 64,
        Quantity: 24,
        Time: '2015-12-01'
      }
    ]
  }
]

CSS如果你想让它成为一个不那么丑陋的渲染:

/* Line Chart CSS */
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  stroke-width: 3px;
  shape-rendering: crispEdges;
}
#pipeline-1,
#pipeline-2 {
  fill: none;
  stroke-width: 1.5px;
  stroke-linecap: round;
  transition: stroke-width 250ms linear;
  -moz-transition: stroke-width 250ms linear;
  -webkit-transition: stroke-width 250ms linear;
  transition-delay: 250ms
  -moz-transition-delay: 250ms;
  -webkit-transition-delay: 250ms;
}
.x.axis path {
/* Uncomment below if I want to remove x-axis line */
/*  display: none;*/
}
.line.hover path {
  stroke-width: 6px;
}
#pipeline-chart-render {
  padding-left: -50px;
}
.area {
  fill: steelblue;
}

这最终奏效了。

  // The following is for defining the area BETWEEN graphs.  
  var areaAboveQuantity = d3.svg.area()
    .x(line.x())
    .y0(line.y())
    .y1(0);
  var areaBelowQuantity = d3.svg.area()
    .x(line.x())
    .y0(line.y())
    .y1(height);
  var areaAboveAmount = d3.svg.area()
    .x(line.x())
    .y0(line.y())
    .y1(0);
  var areaBelowAmount = d3.svg.area()
    .x(line.x())
    .y0(line.y())
    .y1(height);
  var defs = svg.append('defs');
  defs.append('clipPath')
    .attr('id', 'clip-quantity')
    .append('path')
    .datum(datasets)
    .attr('d', function(d) {
       return areaAboveQuantity(d[1].values);
    });
  defs.append('clipPath')
    .attr('id', 'clip-amount')
    .append('path')
    .datum(datasets)
    .attr('d', function(d) {
      return areaAboveAmount(d[0].values);
    });

  svg.append('path')
    .datum(datasets)
    .attr('class', 'area')
    .attr('d', function(d) {
      return areaBelowQuantity(d[1].values)
    });
  // Quantity IS ABOVE Amount
  svg.append('path')
    .datum(datasets)
    .attr('d', function(d) {
      areaBelowQuantity(d[1].values);
    })
    .attr('clip-path', 'url(#clip-amount)')
    .style('fill', 'steelblue')
    .style('opacity', '0.2');

  // Amount IS ABOVE Quanity
  svg.append('path')
    .datum(datasets)
    .attr('d', function(d) {
      return areaBelowAmount(d[0].values);
    })
    .attr('clip-path', 'url(#clip-quantity)')
    .style('fill', 'steelblue')
    .style('opacity', '0.2');