了解D3具有嵌套内容的输入,更新和退出选择

时间:2019-05-06 06:36:02

标签: javascript d3.js

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

基本上,我通常对要显示的每个对象使用带有一些属性的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中的所有div,根据数据数组输入/更新,然后在段落中附加所需的信息:

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. 如果我有一个事件将另一个人添加到数组中,然后再次运行此事件,则我只会看到原始数组中的两个人-John和Mark。

  3. 如果我将另一个人添加到数组中,不仅问题2仍然存在,现在它还会将段落添加到该人的包装div中,以便每个人的div中都有重复的内容。

坦率地说,当我要在包装器中嵌套D3元素并嵌套内容并在同一级别添加多个子项然后更新整个组时,我不太确定输入/更新/退出选择应该如何工作数组更新时。对此的任何澄清将不胜感激-谢谢。

1 个答案:

答案 0 :(得分:1)

您必须重新分配选择:

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>

最后,鉴于您在your comment中共享的信息,解决您的代码的第一选择似乎是创建嵌套的进入/更新/退出选择。

但是,再三考虑一下,因为您的对象没有嵌套数组,所以一种更简单的解决方案是将<p>元素添加到enter选择中,然后在update选择中对其进行更新。

以下是演示此代码段的示例,其中包含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>