transition when adding new data to d3 streamgraph

时光毁灭记忆、已成空白 提交于 2019-12-03 14:28:02

This problem revolves around the fact that, for SVG animations, you can only push points onto the end of a path.

First, the fix (this will only work if the graphics are always vertically dense and have consistent ordering for which graph is highest):

...
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!
    ...

Working example here: http://jsfiddle.net/f5JSR/2/

Now, the explanation...

Each of the color bands in your graph is a closed path, and d3.js constructs them so that none of these color bands overlaps with each other. The problem is, this means each of these paths starts at the bottom left corner, and loops around all the way back to itself. When you add a new point on these paths, you are adding it at the end, and it is pushing the rest of the path counter-clockwise around (creating that weird animation effect).

I initially tried solving this using SVG clipping and the fill-rule: evenodd property, but it seems that to use clipping you have to create compound paths, and adding new points pushes them on the end of this compound path (you can't, for example, push a point onto the first path of the compound path), so the problem persists.

Instead, this solution does away with d3.js's cleverness and instead makes all of your color bands expand to the bottom of the graph (that's what the y(null); line is doing). It then orders the paths so the highest ones are drawn first. This approach breaks down if one graph's height falls below another graph's height.

Finally, to when points are pushed around the bottom right corner, there can be some weird artifacting. To fix that, I double up the number of points at the bottom right corner using the fixPath function.

Anyways, this solution works for the example case you had. I hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!