添加新的数据D3 streamgraph转型时(transition when adding new

2019-08-17 09:41发布

我用D3绘制流图非常类似官方例子http://bl.ocks.org/mbostock/4060954 :

唯一不同的是我如何与新的数据更新它。 我不只是想垂直(y值)过渡,同时也希望在右侧添加新的数据点。 整个图形应该成为在水平方向上压缩

这是没有问题的,以达到预期的效果,唯一的问题是,这两个状态之间的转换看起来并不如预期。

你可以找到对的jsfiddle奇怪的过渡效果AA小例子: http://jsfiddle.net/jaYJ9/4/

按更新按钮来查看效果

test_data0 = [{"0": 0.0, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.6, "-1": 0.0}, {"0": 0.0, "1": 0.3, "-1": 0.0}, {"0": 0.0, "1": 0.0, "-1": 0.6}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.3, "-1": 0.3}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.0, "-1": 0.0}]
test_data1 = [{"0": 0.0, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.6, "-1": 0.0}, {"0": 0.0, "1": 0.3, "-1": 0.0}, {"0": 0.0, "1": 0.0, "-1": 0.6}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.3, "-1": 0.3}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.3, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.0, "-1": 0.0}, {"0": 0.0, "1": 0.0, "-1": 0.0}]

$('#update').click(function(){
    streamed_history(test_data1)
});
var width = 300,
    height = 200,
    colors = {'0': '#6ff500', '1': '#ffad0a', '-1': '#f90035'},
    feedbacks = [-1, 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().interpolate("basis")
        .x(function(d) { return x(d.x); })
        .y0(function(d) { return y(d.y0); })
        .y1(function(d) { return y(d.y0 + d.y); });

    //enter
    svg.selectAll("path")
        .data(layers)
      .enter().append("path")
        .attr("d", function (d) {return area(d.layer);})
        .style("fill", function(d) { return d.color; });

    //update
    d3.selectAll("path")
      .data(layers)
    .transition()
      .duration(2000)
      .attr("d", function (d) {return area(d.layer);});
}

Answer 1:

这个问题围绕着的事实是,对于SVG动画,只能推到的点的路径的结束。

首先,修复(如果图形总是垂直密集,有一致的排序为这图是最高的,这只会工作):

...
var area = d3.svg.area().interpolate("basis")
    ...
    .y0(function(d) { return y(null); }) // The null here is super important!
    ...
...
// Add this function
function fixPath (path) {
    var Lidx = path.indexOf('L');
    var Cidx =  path.slice(Lidx).indexOf('C');
    var PCidx = path.slice(0,Lidx).lastIndexOf('C');

    var lp = path.substr(PCidx, Lidx-PCidx);
    var ss = path.substr(Lidx, Cidx);

    return (path.slice(0,Lidx) + lp + ss + path.slice(Lidx));
}
...
svg.selectAll("path")
    .data(layers.reverse()) // Gotta reverse the order!
    .attr("d", function (d) { return fixPath(area(d.layer)); }) // Have to double up the bottom right corner to avoid artifacts
    ...
...
d3.selectAll("path")
    .data(layers)
    .attr("d", function (d) { return fixPath(area(d.layer)); }) // When updating too!
    ...

工作示例这里: http://jsfiddle.net/f5JSR/2/

现在,解释...

每个图表中的颜色带的是一个封闭的路径,d3.js构建他们,让这些没有颜色带的相互重叠。 问题是,这意味着每个路径的开始在左下角和循环周围所有的方式回到本身。 当你在这些路径上添加一个新的点,你是在年底加入它,它是围绕推进道逆时针的其余部分(创建一个怪异的动画效果)。

我最初尝试解决这个使用SVG裁剪和fill-rule: evenodd财产,但似乎使用裁剪你必须创建复合路径,并添加新的点促使他们在这个复合路径的结束(你不能,例如,推点到化合物路径的第一路径),所以问题仍然存在。

取而代之的是,该解决方案摒弃了d3.js的聪明,而是让所有的颜色波段扩展到图形的底部(这是什么y(null);行正在做)。 然后,它命令路径,以便最高的人先绘制。 这种做法打破了,如果一个图形的高度低于另一个图形的高度。

最后,当点周围的右下角推到,可以有一些奇怪的伪像。 为了解决这个问题,我加倍点的数量在使用右下角fixPath功能。

不管怎么说,这个解决方案适用于你有例子的情况。 我希望这有帮助。



文章来源: transition when adding new data to d3 streamgraph