2013-06-29 87 views
15

根據我的理解,更新d3數據的正確方法是將其傳遞到選擇的.data()在D3數據中保留訂單

我獲得的數據沒有排序,或者與此相關。所以我非常需要使用更新/添加/刪除邏輯。所以在d3中.data().enter().exit()(對吧?)。

所以我想要做的是使用一個JavaScript字典,而不是一個數組,其中的關鍵是我的唯一標識符。但我似乎無法做到這一點。一個假例如:

data_one[0] = 'Dogs'; 
data_one[1] = 'Cats'; 

d3.selectAll('circle').data(data_one).enter().attr(...) 

我第二次運行此我的數據可能是相同的,但在不同的順序。我想用與以前相同的屬性來表示它。我不想複製我的代碼,但是如果我只是執行.data(data_two),那麼錯誤的圈子將更新新數據。

任何方法?

回答

49

這是鍵功能,第二個參數selection.data的目的:它可以讓你通過控制數據被綁定到哪個元素保持object constancy。例如,假設你有對象的數組代表水果:

var fruits = [ 
    {name: "orange", value: 200}, 
    {name: "apple", value: 124}, 
    {name: "banana", value: 32} 
]; 

當你第一次創建的元素,你並不需要的關鍵功能,因爲沒有任何現有的元素,所以你可以使用標準的全選,數據輸入,追加模式:

var div = d3.select("body").selectAll(".fruit") 
    .data(fruits) 
    .enter().append("div") 
    .attr("class", "fruit") 
    .text(function(d) { return d.name + ": " + d.value; }); 

這種操作的結果是:

<body> 
    <div class="fruit">orange: 200</div> 
    <div class="fruit">apple: 124</div> 
    <div class="fruit">banana: 32</div> 
</body> 

但是,現在讓我們假設你的數據的變化,並且要更新到refle新數據。這一新數據可能會以不同的順序,並且一些元素可以添加或刪除:

var fruits2 = [ 
    {name: "apple", value: 124}, 
    {name: "lemon", value: 17}, 
    {name: "banana", value: 32}, 
    {name: "strawberry", value: 1465} 
]; 

蘋果和香蕉分別在原始數據,所以我們想留住他們。這被稱爲更新選擇。草莓和檸檬是新的;這是輸入的選擇。最後橘子走開了,形成了退出的選擇。

使用引用數據的name屬性的鍵函數,我們可以按照預期將新數據分配給舊元素。然後,我們可以創建進入水果和刪除退出的水果:

var div = d3.select("body").selectAll(".fruit") 
    .data(fruits2, function(d) { return d.name; }); 

div.enter().append("div") 
    .attr("class", "fruit") 
    .text(function(d) { return d.name + ": " + d.value; }); 

div.exit().remove(); 

這就是所謂的general update pattern。 (你可有周圍做這個的第一次;它的全選,數據輸入,追加模式的更一般的形式)的結果是:

<body> 
    <div class="fruit">apple: 124</div> 
    <div class="fruit">banana: 32</div> 
    <div class="fruit">lemon: 17</div> 
    <div class="fruit">strawberry: 1465</div> 
</body> 

雖然選擇div順序的數據相匹配fruit2 ,DOM中的順序不是而是,因爲輸入元素被添加到主體的末尾。 (選擇。追加沒有任何花哨的邏輯來保證排序;它只是將新元素添加到父項的最後)。使用SVG時,我們通常不關心DOM元素的順序,因爲所有元素都是絕對定位的。如果您做一下順序護理,你可以使用selection.order進入後修復:

div.order(); // make the DOM element order match the selection 

而且,在這個例子中,我們不需要做出更新選擇的任何變化,因爲這些值對於蘋果和香蕉沒有改變。如果更新數據也發生變化,您可以直接調用selection.attr和selection.text來調用上面的selection.data調用。

+1

謝謝邁克!!!! – ehsan

+0

THx的答案。我在兩個準相同的情況下使用selection.order(),一次它工作,一次它不。選擇的順序究竟是什麼?它取決於給數據功能的關鍵嗎? – JulienFr

+0

我想答案是基於「[enter.append有一個方便的副作用:它用更新選擇中的新元素替換了輸入選擇中新創建的元素。因此,在enter.append之後,更新選擇是修改爲包含輸入和更新元素。](https://bost.ocks.org/mike/selection/#enter-update)「。但是,我的[測試](https://gist.github.com/an0/a924bf0d25e43d71584402dff6e28344)似乎並非如此。更新選擇仍然只包含enter.append後的更新。必須在'update'和'enter'的'merge'上調用'order'使其工作。爲什麼? – an0