使用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();
我遇到了一些问题:
第一次运行
没有段落附加段落如果我有一个事件将另一个人添加到数组中,然后再次运行,我只看到两个在原始数组中的人-John and Mark。
如果我将另一个人添加到数组中,不仅发行#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>