1

我有一个堆叠区域图,当数据发生变化时会显示动画。

数据显示给定日期范围(例如,12 月 10 日至 15 日)的值。当我添加扩展我的日期范围以包含更早的日期(例如,12 月 9 日至 15 日)时,数据数组的前面有附加数据。

但是,当路径动画时,效果非常奇怪且不可取。

看到这个 jsfiddle 显示效果(单击更新按钮):http: //jsfiddle.net/qprn9ta9/

这似乎是因为我在 SVG 区域的前面添加了新点,并且插值根据索引为它们设置了动画。

我怎样才能避免这种情况?D3 中是否有内置的东西可以提供帮助?我寻找某种与您一起使用的关键功能data(),但没有找到类似的东西。还有其他想法吗?

4

3 回答 3

0

所以,这个问题整晚都让我发疯。您是正确的,当从一条路径到另一条路径时,在数据前面添加新点会抛出d3s方法。interpolateString我能想到的最好的(hacky)修复是在过渡开始之前在路径中插入一个点:

// 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>

于 2016-01-07T16:38:31.127 回答
0

因此,事实证明,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();
于 2016-02-25T17:16:14.383 回答
0

如果您需要向其中一个 dataset0 添加点,但 dataset1 没有更改,请添加“间隔值”,重复 dataset1 的最后一个值。

数组长度需要匹配,否则动画会出现故障,因为 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/

于 2016-01-06T18:33:56.220 回答