2013-03-08 42 views
6

當我使用D3繪製流圖非常類似官方例子http://bl.ocks.org/mbostock/4060954過渡添加新的數據D3 streamgraph

enter image description here

唯一不同的是我如何與新的數據更新它。我不僅想要垂直(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);}); 
} 
+0

jsfiddle不起作用... – 2013-03-08 14:59:20

+0

對不起,現在它 – dedan 2013-03-08 18:15:24

回答

9

迴避的事實這個問題圍繞,對於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函數將右下角的點數加倍。

無論如何,這個解決方案適用於你的例子。我希望這有幫助。

+0

非常感謝,這真的解決了我的問題。在開始時,我沒有明白你的意思是什麼_最高的路徑_。但是現在我發現你的意思是堆積圖中最高的一個。由於這個命令沒有改變,你完全解決了我的問題。也謝謝你的好解釋 – dedan 2013-03-12 15:04:31