2015-01-21 94 views
1

我寫了一個可重用的d3折線圖(代碼如下)。不幸的是,只有當傳遞給它的數據數據更新時它才能正確更新;如果它傳遞了一個新的數據數組,它根本不會更新 - 您可以在jsfiddle中看到它。d3線和麪積圖不用新的數據陣列更新

下面是HTML,其中大部分是嵌入式演示調用腳本:

<style> 
    path { stroke: purple; stroke-width: 2px; fill: none; } 
</style> 
<body> 
<div id="demo"></div> 
<script src="http://d3js.org/d3.v3.min.js"></script> 
<script src="demoChart.js"></script> 
<script> 
    var chart = demoChart(); 
    var pts = [[[0,0],[200,0.25],[500,1]]]; 

    d3.select("#demo").datum(pts).call(chart); 
    setTimeout(function() { 
    console.log("Modifying data array"); 
    pts[0][2][1] = 0.5; 
    d3.select("#demo").datum(pts).call(chart); 
    },1000); 

    setTimeout(function() { 
    console.log("Passing new data array"); 
    d3.select("#demo").datum([[[0,1],[200,0.45],[500,0]]]).call(chart); 
    },2000); 
</script> 

你可以看到它調用chart第二次直接更新單個點的數據陣列中(pts[0][3][1] = 0.5),以及圖表正確動畫。第三次它傳遞一個新的數據數組,並且圖表不會改變。

這裏是demoChart.js代碼(基於reusable charts模式):

function demoChart() { 

    function xs(d) { return xScale(d[0]) } 
    function ys(d) { return yScale(d[1]) } 

    var xScale = d3.scale.linear().domain([0, 500]).range([0, 400]), 
     yScale = d3.scale.linear().domain([0, 1]).range([400, 0]), 
     line = d3.svg.line().x(xs).y(ys); 

    function chart(selection) { 
     selection.each(function(data) { 
      console.log("passed data: ", data); 

      // Select the svg element, if it exists; otherwise create it 
      var svg = d3.select(this).selectAll("svg").data([1]); 
      var svgGEnter = svg.enter().append("svg").append("g"); 

      // Select/create/remove plots for each y, with the data 
      var plots = svg.select("g").selectAll(".plot").data(data); 
      plots.exit().remove(); 
      var plotsEnter = plots.enter().append("g").attr("class","plot"); 
      plotsEnter.append("path"); 

      // Update the line paths 
      plots.selectAll("path") 
       .transition() 
        .attr("d", function(d,i) { 
         console.log("transitioning line with data: ", d); 
         return line.apply(this, arguments); 
        }); 

      svg.attr("width", 400).attr("height", 400); 

     }); 
    } 

    return chart; 
} 

我懷疑我失去了一些東西根本如何D3的作品。

如何在新數據數組通過時正確更新圖表?

回答

4

當你更新行路徑,通過

plots.selectAll("path") 

它需要

plots.select("path") 

請參閱mbostock's explanation的微妙但cr意義上的差異。

這是一個working fiddle,它還添加了第二個路徑,以驗證它是否可以跨越繪圖。

+0

就是這樣!謝謝你,感謝這個工作例子和mbostock解釋的鏈接。我還沒有弄清楚如何在'select'和'selectAll'之間進行選擇,但是從現在開始我會留意它... – 2015-01-21 23:24:56

0

我今天真的有同樣的問題。所以我可以幫忙。我注意到你在調用setTimeout來更新你的html中的數據。

看來你是在setTimeout裏面調用chart()。 唯一的問題是你沒有重置你的範圍。相反,你應該嘗試調用demoChart(),或者在圖表()內添加新的範圍。你的範圍是:

function xs(d) { return xScale(d[0]) } 
function ys(d) { return yScale(d[1]) } 

var xScale = d3.scale.linear().domain([0, 500]).range([0, 400]), 
    yScale = d3.scale.linear().domain([0, 1]).range([400, 0]), 
    line = d3.svg.line().x(xs).y(ys); 

如果仍不能解決問題,則可能是因爲你有兩個一個定時器,同時啓動每一秒更新。因此,第二個數據被覆蓋第一個立即的位置:

setTimeout(function() { 
    console.log("Modifying data array"); 
    pts[0][2][1] = 0.5; 
    d3.select("#demo").datum(pts).call(chart); 
},1000); 

setTimeout(function() { 
    console.log("Passing new data array"); 
    d3.select("#demo").datum([[[0,1],[200,0.45],[500,0]]]).call(chart); 
},1000); 

這裏有一個文章,我發現有幫助:http://www.d3noob.org/2013/02/update-d3js-data-dynamically-button.html

+0

謝謝泰勒。是的,延遲1000秒的第二次超時很糟糕,應該是2000年(我現在編輯它) - 結果雖然是相同的。另外,我應該說,我在這裏使用setTimeout作爲例子,在我的真實應用程序中它是對事件的迴應。 meetamit的答案似乎解決了這個問題。 – 2015-01-21 23:27:38