2013-08-02 45 views
5

我使用D3繪製HTML表格,並且輸入內容的效果很好。當我將新項目添加到我的數據收集時,它會正確添加新項目到表格中。通過D3繪製HTML表格不會更新現有數據

問題是每當我更新集合中的現有對象(下面的backgroundJobs集合中的對象)時。當我重新運行D3代碼來同步表格時,它不起作用。什麼都沒發生。

下面的代碼:

var visibleColumns = ['Name', 'Start', 'End', 'Status', 'Metadata', 'Errors']; 

var table = d3.select('#jobs').append('table'); 
var thead = table.append('thead'); 
var tbody = table.append('tbody'); 

thead.append("tr") 
    .selectAll("th") 
    .data(visibleColumns) 
    .enter() 
    .append("th") 
    .text(function (column) { return column; }); 

function tick() { 
    var rows = tbody.selectAll("tr") 
     .data(backgroundJobs, function(d) { 
      return d.name; 
     }) 
     .enter() 
     .append("tr"); 

    var cells = rows.selectAll("td") 
     .data(function(row) { 
      return [{column: 'Name', value: row.name}, 
        {column: 'Start', value: row.startedTimestamp}, 
        {column: 'End', value: row.endedTimestamp}, 
        {column: 'Status', value: row.isRunning}, 
        {column: 'Metadata', value: ''}, 
        {column: 'Errors', value: row.errorMsg}]; 
     }) 
     .enter() 
     .append("td") 
     .text(function(d) { return d.value; }); 
} 

setInterval(tick, 500); 

回答

7

請參考data joins的酷炫說明。

當你調用

tbody.selectAll("tr").data(some-new-data); 

你實際上得到3點的選擇:「輸入」(蒙山在DOM中不存在的新元素還),「退出」(那些存在於DOM,但不再存在於數據)和'更新',其中包含已經在DOM中的節點,並且仍然通過上面的.data調用將數據分配給它們。

一般來說,對於'輸入'選擇你創建新的節點,爲'退出'你需要刪除舊的,'更新'你只是改變屬性 - 可能有一些不錯的過渡效果。 請參閱更新的「打勾」功能代碼。

function tick() { 
    var rows = tbody.selectAll("tr") 
    .data(backgroundJobs, function(d) { 
     return d.name; 
    }); 

    rows.enter() 
     .append("tr"); 

    rows.order(); 

    var cells = rows.selectAll("td") 
     .data(function(row) { 
      return [{column: 'Name', value: row.name}, 
       {column: 'Start', value: row.startedTimestamp}, 
       {column: 'End', value: row.endedTimestamp}, 
       {column: 'Status', value: row.isRunning}, 
       {column: 'Metadata', value: ''}, 
       {column: 'Errors', value: row.errorMsg}]; 
     }); 

    cells.enter() 
     .append("td"); 

    cells.text(function(d) { return d.value;}); 

    cells.exit().remove(); 

    rows.exit().remove(); 
} 

參見Demo(backgroundJobs在兩個硬編碼數據集之間的接通定時器)。

+1

爲什麼包括呼叫「rows.order();」? – manu08

+0

以便錶行順序與backgroundJobs數組中的作業順序相匹配。 如果沒有顯式排序所有新作業(數據連接方面的'新' - 構成'輸入'選擇的那些)將附加到表的末尾。 – amakhrov

1

rows變量將是一個選擇,將只包含節點,如果enter()是不是空的。第二次,如果您沒有在backgroundJobs中添加任何新行,則數據綁定將更新現有節點,並且enter()將不包含任何節點(這意味着rows將不包含任何節點)。

您可以通過按住一個參考更新選擇服用的節點追加到輸入選擇被添加到幕後更新選擇的事實優勢,解決這個問題:

var rows = tbody.selectAll("tr") 
    .data(backgroundJobs, function(d) { 
     return d.name; 
    }); 

rows.enter() 
    .append("tr"); 

現在行會參考到包含所有先前存在的和新添加的節點的選擇。

0

爲了能夠動態添加和刪除行,這個戰略對我的作品:

// ROW MANAGEMENT 

// select all tr elements 
var tr = this.table.select("tbody").selectAll("tr").data(cur_data); 

// exit rows 
tr.exit().remove(); 

// enter rows 
var trEnter = tr.enter().append("tr"); 

// CELL MANAGEMENT 

trEnter.selectAll("td").data(function(d) { return d3.values(d); }).enter().append("td").text(function(d) { return d; }); 

// select all td elements 
var td = tr.selectAll("td").data(function(d) { return d3.values(d); }); 

// exit cells 
td.exit().remove(); 

// enter and update/add data to cells 
td.enter().append("td"); 
td.text(function(d) { return d; });