如何在没有奇怪的动画故障的情况下将数据准备到D3堆叠区域图
How can I prepend data to a D3 stacked area graph without weird animation glitches?
我有一个堆叠区域图,当数据发生变化时,它会设置动画。
该数据显示了给定日期范围(例如,12月10-15日)的值。当我添加并扩展我的日期范围以包括更早的日期(例如,12月9日至15日)时,数据数组会在前面预先准备额外的数据。
不过,当路径设置动画时,效果会非常奇怪且不受欢迎。
请参阅显示效果的jsfiddle(单击"更新"按钮):http://jsfiddle.net/qprn9ta9/
这似乎是因为我在SVG区域的前面添加了新的点,并且插值是基于索引来设置它们的动画。
我该如何避免这种情况?D3中有什么可以帮助的东西吗?我找了一些类似于data()
的键函数,但没有找到类似的函数。还有其他想法吗?
如果您需要向其中一个数据集0添加点,但数据集1没有更改,请添加一个"间隔值";,重复数据集1的最后一个值。
数组长度需要匹配,否则动画会出现故障,因为SVG的标记结构需要更改以适应数据,所以随着时间的推移,您不会只更改位置。
之前(数据集的长度不同):
test_data0 = [{"0": 0.1, "1": 0.1}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}]
test_data1 = [{"0": 0.2, "1": 0.2}, {"0": 0.0, "1": 0.0}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}]
之后(两个数据集的长度相同):
test_data0 = [{"0": 0.1, "1": 0.1}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}, {"0": 0.2, "1": 0.3}]
test_data1 = [{"0": 0.2, "1": 0.2}, {"0": 0.0, "1": 0.0}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}]
因此,该解决方案迫使您提前更加小心地处理数据集。
jsfiddle:
http://jsfiddle.net/2o372wu3/
所以,这个问题整晚都让我抓狂。从一条路径到另一条路径时,在数据前面添加新点会抛出d3
的interpolateString
方法,这是正确的。我能想到的最好的(黑客)修复方法是在转换开始前在路径中插入一个点:
// enter
var mp = svg.selectAll("path")
.data(layers);
mp
.enter().append("path")
.style("fill", function(d) { return d.color; });
//update
mp
.transition()
.duration(2000)
.tween("path", function(d) {
var self = d3.select(this),
cP = self.attr("d"),
i = null;
if (!cP){
i = d3.interpolateString("", area(d.layer));
} else {
var idx = cP.indexOf("L"),
fP = cP.substring(0, idx),
lP = cP.substring(idx);
cP = fP + "L" + fP.slice(1) + lP;
i = d3.interpolateString(cP, area(d.layer));
}
return function(t) {
self.attr("d", i(t));
};
});
完整代码:
test_data0 = [{"0": 0.1, "1": 0.1}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}]
test_data1 = [{"0": 0.2, "1": 0.2}, {"0": 0.1, "1": 0.1}, {"0": 0.2, "1": 0.6}, {"0": 0.3, "1": 0.4}, {"0": 0.1, "1": 0.6}, {"0": 0.3, "1": 0.1}, {"0": 0.0, "1": 0.3}, {"0": 0.3, "1": 0.1}, {"0": 0.3, "1": 0.2}, {"0": 0.2, "1": 0.3}]
$('#update').click(function(){
console.log('test')
streamed_history(test_data1)
});
var width = 300,
height = 200,
colors = {'0': '#6ff500', '1': '#ffad0a'},
feedbacks = [0, 1],
stack = d3.layout.stack();
var svg = d3.select("#timeline").append("svg")
.attr("width", width)
.attr("height", height);
var y = d3.scale.linear()
.domain([0, 1])
.range([height, 0]);
streamed_history(test_data0)
function streamed_history(data) {
data_array = feedbacks.map(function (f) {
return data.map(function(element, i) { return {x: i, y: element[f]}; })
}),
layers = stack(data_array)
layers = feedbacks.map(function (f, i) {
return {layer: layers[i], feedback: f, color: colors[f]}
})
var x = d3.scale.linear()
.domain([0, data.length - 1])
.range([0, width]);
var area = d3.svg.area()
.x(function(d) { return x(d.x); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
//enter
var mp = svg.selectAll("path")
.data(layers);
mp
.enter().append("path")
.style("fill", function(d) { return d.color; });
//update
mp
.transition()
.duration(2000)
.tween("path", function(d) {
var self = d3.select(this),
cP = self.attr("d"),
i = null;
if (!cP){
i = d3.interpolateString("", area(d.layer));
} else {
var idx = cP.indexOf("L"),
fP = cP.substring(0, idx),
lP = cP.substring(idx);
cP = fP + "L" + fP.slice(1) + lP;
i = d3.interpolateString(cP, area(d.layer));
}
return function(t) {
self.attr("d", i(t));
};
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="timeline"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<button id='update'>Update</button>
因此,正如经常发生的那样,Mike Bostock已经在这里解决了这个问题:
https://bost.ocks.org/mike/path/
他只说明了追加到末尾的情况,但预处理的情况可以通过类似于以下的一些调整来完成:
// push a new data point onto the front
data.unshift(random());
// redraw the line shifted to the left by one data point, and then slide it to the right
path
.attr("d", line)
.attr("transform", 'translate(" + x(-1) + ")')
.transition()
.attr("transform", null);
// pop the old data point off the back
data.pop();
相关文章:
- d3.hexbin插件-动态定义颜色域以适应数据
- 如何为d3.js图表输出组织/嵌套数据
- 添加新数据时D3.JS条形图列偏移量
- 将基本CSV数据加载到D3
- 具有关联数组数据集的D3.js表
- d3在数据更新时错误地附加了dom元素
- d3.csv有很多数据,只画了一个月
- 基本D3.js:使用数据键
- 基本D3.js:如何将具有其他属性的数据绑定到元素
- 如何在D3.js中绘制地图投影上的点,并使用范围滑块过滤数据
- 通过内部数组将JSON数据导入D3.js+Google Map
- 具有多个数据集的分组散点图D3
- 如何使用D3.js根据json中给出的数据在Heatmap中创建可变大小的矩形
- 基于数据d3.js绑定svg梯度
- 其中存储有数据d3
- 如何动态更改力布局图中的数据?D3.
- 将 MySQL 查询结果转换为分层数据 - D3
- 使用复选框过滤数据- D3
- 更新enter().append()块中的数据d3.js
- 同时转换xAxis和数据- D3.js