6

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

3 回答 3

9

参考数据连接的酷解释。

你打电话时

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

请参阅演示(backgroundJobs 在两个硬编码数据集之间打开计时器)。

于 2013-08-03T11:12:55.687 回答
1

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

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

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

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

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

于 2013-08-02T19:52:42.027 回答
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; });
于 2016-11-28T17:54:52.403 回答