每当数据更新时,我都试图为D3
(v5)中的路径设置动画。多亏了this的示例,我设法实现了转换。
但是,当新数据集包含的数据点多于前一个数据点时,该行为很奇怪。数据更新后,现有路径会挤到图表的左侧,而新数据点将立即显示(不显示动画)。这会导致非常混乱和混乱的结果,尤其是如果图表中有多条线(以下示例已简化)。
有没有办法改善这一点?理想情况下,路径不应向左挤压,而只需在其当前位置更新数据点即可。另外,我们可以为任何“新”点设置动画,以便它们从底部向上移动,这在眼睛上会更柔和,但我还没有找到一种方法来仅对新点设置动画。
// 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>