【问题标题】:Drawing an HTML table via D3 doesn't update existing data通过 D3 绘制 HTML 表格不会更新现有数据
【发布时间】:2016-11-29 02:28:58
【问题描述】:

我正在使用 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);

【问题讨论】:

    标签: javascript d3.js html-table


    【解决方案1】:

    请参考data joins的酷解释。

    当你打电话时

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

    您实际上有 3 个选择:“进入”(DOM 中尚未出现新元素)、“退出”(DOM 中出现但不再出现在数据中的元素)和“更新”,其中包含的节点已经在 DOM 中,并且仍然通过上面的 .data 调用分配给它们的数据。

    一般来说,对于“进入”选择,您需要创建新节点,对于“退出”,您需要删除旧节点,而对于“更新”,您只需更改属性 - 可能会有一些不错的过渡效果。 查看更新的“tick”功能代码。

    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 在两个硬编码数据集之间打开计时器)。

    【讨论】:

    • 为什么要包含调用'rows.order();'?
    • 使表格行顺序与 backgroundJobs 数组中作业的顺序相匹配。如果没有显式排序,所有新作业(数据连接方面的“新” - 形成“输入”选择的那些)都将附加到表的末尾。
    【解决方案2】:

    rows 变量将是一个仅在enter() 不为空时才包含节点的选择。第二次,如果您没有在backgroundJobs 中添加任何新行,数据绑定将更新现有节点并且enter() 将不包含任何节点(意味着rows 将不包含任何节点)。

    您可以通过持有对更新选择的引用来解决此问题,利用附加到输入选择的节点在幕后添加到更新选择的事实:

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

    现在行将引用包含所有先前存在和新添加的节点的选择。

    【讨论】:

      【解决方案3】:

      为了能够动态添加和删除行,这个策略适合我:

      // 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; });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多