了解D3使用嵌套内容输入,更新和退出选择



使用d3.js时,我发现我经常想创建绑定到我的数据的元素,但出于样式/布局原因,在DIV和包装器中绑定。我正在努力理解的是嵌套内容和包装器如何与D3的Enter,更新和退出模式一起使用。

基本上,我通常使用JSON数组,其中有一些我要显示的对象的属性。

说我有很多人,每个人的姓名和年龄看起来都这样:

var array = [
    {
        name: "John",
        age: 31
    },
    {
        name: "Mark",
        age: 29
    },
]

我想在包装器Div中使用D3列出此数据:

<div id="wrapper"></div>

我想为每个人创建一个,然后附加一个包含该人名称的段落和一个包含该人年龄的段落。因此,所需的最终结果将是:

<div id="wrapper">
    <div class="person">
        <p>John</p>
        <p>31</p>
    </div>
    <div class="person">
        <p>Mark</p>
        <p>29</p>
    </div>
</div>

我一直在尝试做的是在包装器div中选择所有divs,根据数据阵列输入/更新,然后用所需的信息附加段落:

var selection = d3.select("#wrapper")
    .selectAll("div")
    .data(array);
selection.enter()
    .append("div")
    .classed("person", true)
    .merge(selection);
selection.append("p")
    .html(d.name);
selection.append("p")
    .html(d.age);
selection.exit().remove();

我遇到了一些问题:

  1. 第一次运行

  2. 没有段落附加段落
  3. 如果我有一个事件将另一个人添加到数组中,然后再次运行,我只看到两个在原始数组中的人-John and Mark。

  4. 如果我将另一个人添加到数组中,不仅发行#2持续存在,现在它将段落附加到这些人的包装divs,因此每个人的Divs中都有重复的内容。

坦率地说,当我想将D3元素放置在包装器中并嵌套内容并在同一级别上添加多个孩子,然后更新整个组时,我有点不确定如何使用/更新/退出选择。当数组更新时。对此的任何清晰度将不胜感激 - 谢谢。

您必须重新分配选择:

selection = selection.enter()
  .append("div")
  .classed("person", true)
  .merge(selection);

另外,您不能使用这样的第一个参数,您必须将函数传递给方法:

selection.append("p")
  .html(d=>d.name);
selection.append("p")
  .html(d=>d.age);

这是您的代码和这些更改:

var array = [{
    name: "John",
    age: 31
  },
  {
    name: "Mark",
    age: 29
  },
]
var selection = d3.select("#wrapper")
  .selectAll("div")
  .data(array);
selection = selection.enter()
  .append("div")
  .classed("person", true)
  .merge(selection);
selection.append("p")
  .html(d=>d.name);
selection.append("p")
  .html(d=>d.age);
selection.exit().remove();
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="wrapper"></div>

最后,鉴于您在评论中共享的信息,修复代码的首选似乎是创建嵌套的Enter/Update/Exit选择。

但是,第二个想法,因为您的对象没有嵌套数组,因此一种更简单的解决方案正在附加Enter选择中的<p>元素并在"更新选择"中更新它们。

这是一个片段,展示了这一点,带有3个不同的数据阵列:

var array = [{
    name: "John",
    age: 31
  },
  {
    name: "Mark",
    age: 29
  },
]
function display() {
  var selection = d3.select("#wrapper")
    .selectAll("div")
    .data(array);
  var selectionEnter = selection.enter()
    .append("div")
    .classed("person", true);
  selectionEnter.append("p")
    .classed("name", true)
    .html(d => d.name);
  selectionEnter.append("p")
    .classed("age", true)
    .html(d => d.age);
  selection.exit().remove();
  selection.select(".name")
    .html(d => d.name);
  selection.select(".age")
    .html(d => d.age);
}
display();
setTimeout(function() {
  array = [{
      name: "John",
      age: 31
    },
    {
      name: "Mark",
      age: 29
    },
    {
      name: "Andrew",
      age: 24,
    }
  ];
  display();
}, 2000)
setTimeout(function() {
  array = [{
      name: "John",
      age: 21
    },
    {
      name: "Bob",
      age: 49
    }
  ];
  display();
}, 4000)
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="wrapper"></div>

最新更新