D3:数据点数量更改时的过渡路径

时间:2019-07-16 09:28:45

标签: d3.js

每当数据更新时,我都试图为D3(v5)中的路径设置动画。多亏了this的示例,我设法实现了转换。

但是,当新数据集包含的数据点多于前一个数据点时,该行为很奇怪。数据更新后,现有路径会挤到图表的左侧,而新数据点将立即显示(不显示动画)。这会导致非常混乱和混乱的结果,尤其是如果图表中有多条线(以下示例已简化)。

enter image description here

有没有办法改善这一点?理想情况下,路径不应向左挤压,而只需在其当前位置更新数据点即可。另外,我们可以为任何“新”点设置动画,以便它们从底部向上移动,这在眼睛上会更柔和,但我还没有找到一种方法来仅对新点设置动画。

// Create 2 datasets
var data1 = [{
    ser1: 0.3,
    ser2: 4
  },
  {
    ser1: 2,
    ser2: 16
  },
  {
    ser1: 3,
    ser2: 8
  },
  {
    ser1: 4,
    ser2: 6
  },
  {
    ser1: 5,
    ser2: 8
  },
  {
    ser1: 6,
    ser2: 10
  },
  {
    ser1: 7,
    ser2: 6
  }
];

var data2 = [{
    ser1: 1,
    ser2: 7
  },
  {
    ser1: 4,
    ser2: 1
  },
  {
    ser1: 6,
    ser2: 8
  }
];

// set the dimensions and margins of the graph
var margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 50
  },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")");

// Initialise a X axis:
var x = d3.scaleLinear().range([0, width]);
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .attr("class", "myXaxis")

// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
  .attr("class", "myYaxis")

// Create a function that takes a dataset as input and update the plot:
function update(data) {

  // Create the X axis:
  x.domain([0, d3.max(data, function(d) {
    return d.ser1
  })]);
  svg.selectAll(".myXaxis").transition()
    .duration(1000)
    .call(xAxis);

  // create the Y axis
  y.domain([0, d3.max(data, function(d) {
    return d.ser2
  })]);
  svg.selectAll(".myYaxis")
    .transition()
    .duration(1000)
    .call(yAxis);

  // Create a update selection: bind to the new data
  var u = svg.selectAll(".lineTest")
    .data([data], function(d) {
      return d.ser1
    });

  // Updata the line
  u
    .enter()
    .append("path")
    .attr("class", "lineTest")
    .merge(u)
    .transition()
    .duration(1000)
    .attr("d", d3.line()
      .x(function(d) {
        return x(d.ser1);
      })
      .y(function(d) {
        return y(d.ser2);
      })
      .curve(d3.curveMonotoneX))
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 2.5)
}

// At the beginning, I run the update function on the first dataset:
update(data1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button onclick="update(data1)">Dataset 1</button>
<button onclick="update(data2)">Dataset 2</button>
<div id="my_dataviz"></div>

0 个答案:

没有答案