D3 - 更新时元素的正确数量,但值错误

D3 - Correct number of elements on update, but wrong values

我正在用包含数组值的子 div 填充 div。第一次通过时,数组如下所示:

arr_subpop_unique = ["CPL", "NAP", "NPL", "SAP", "SPL", "TPL", "UMW", "WMT", "XER"]

我的选择 enter/update/exit 看起来像这样:

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
        .data(arr_subpop_unique)

    sizemapHeader.enter().append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
        .html(function(d,i){ return d; });

    sizemapHeader.exit().remove();

这很好用,每个包含字符串的元素都给我一个 div。

当我再次 运行 函数时,我的数据数组更新为:

    arr_subpop_unique = ["MAN_MADE", "NATURAL"]

更新returns两个div,然而,它们包含"CPL"和"NAP"(索引值0和1)。有人可以解释为什么这不会用 "MAN_MADE" 和 "NATURAL" 替换前两个指标吗?

感谢您的帮助...正在尝试了解 enter/update/exit D3 中的数据连接!

看看"General update pattern"
我认为你没有触发 d3 的更新选择

var sizemapHeader =
d3.select("#d3-sizemap-hr").selectAll("div")
  .data(arr_subpop_unique)

sizemapHeader
.enter()
  .append("div")
    .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

sizemapHeader
    .html(function(d,i){ return d; });

sizemapHeader
.exit()
  .remove();

只是对@Plato 提供的答案提供不同的看法...

在某些情况下,您可能希望将更改的数据识别为 "new",即。成为 enter 选择的一部分,而不仅仅是 update 的一部分。在您的示例中,它被视为 update 选择的一部分,因为您的数据被绑定到基于索引的 DOM 元素(这是默认设置)。您可以通过将第二个参数传递给 data 调用来更改此行为。

有关详细信息,请参阅 https://github.com/mbostock/d3/wiki/Selections#data。它被称为 key 参数。

这是一个例子:

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
    .data(arr_subpop_unique, function(d, i) { return d; });

sizemapHeader.enter().append("div")
    .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
    .html(function(d,i){ return d; });

sizemapHeader.exit().remove();

data 函数调用的第二个参数现在将确保数据按值绑定到 DOM 元素,而不是按它们在数组中的索引。

下次您使用新数据调用您的函数时,当前未绑定到 DOM 元素的任何值都将被视为新值并成为 enter 选择的一部分。

这两种情况都有用,具体取决于您要实现的目标。

值得注意的是,链接有点不对称,因为 enter() 具有合并到更新选择中的副作用。这意味着,如果您在 append() 之后将特征添加到更新选择中,它们也将添加到输入节点上。另一方面,更新选择不会合并到输入选择中。因此,在 enter() 之后链接的任何功能只会出现在输入选择中。

OP题的情况下,有两个更新节点和零输入节点。所以在不存在的enter节点上添加HTML,两个update节点的HTML不更新

所以,是的,这有效...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//ENTER
sizemapHeader
.enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")
//UPDATE
sizemapHeader
    .html(function (d, i) { return d; })

//EXIT
sizemapHeader
.exit()
    .remove();

但这并不...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//ENTER
//sizemapHeader
    .enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

//UPDATE
sizemapHeader
        .html(function (d, i) { return d; })

//EXIT
sizemapHeader
.exit()
    .remove();

这会中断初始更新(当更新选择为空时)...

var sizemapHeader = d3.select("#d3-sizemap-hr").selectAll("div")
            .data(arr_subpop_unique)

//UPDATE
sizemapHeader
    .html(function (d, i) { return d; })

//ENTER
sizemapHeader
.enter()
    .append("div")
        .attr("class", "sizemap-hr-title ellipsis scroll_on_hover")

//EXIT
sizemapHeader
.exit()
    .remove();

跟踪代码时,您会看到 sizemapHeader 的值在调用 .enter() 后发生变化。

原因埋在wiki中...

The enter selection merges into the update selection when you append or insert. Rather than applying the same operators to the enter and update selections separately, you can now apply them only once to the update selection after entering the nodes. If you find yourself removing an entire selection's elements only to reinsert most of them, do this instead. For example:

var update_sel = svg.selectAll("circle").data(data)
update_sel.attr(/* operate on old elements only */)
update_sel.enter().append("circle").attr(/* operate on new elements only */)
update_sel.attr(/* operate on old and new elements */)
update_sel.exit().remove() /* complete the enter-update-exit pattern */