这是预期的行为,我之前在这个答案中对此进行了解释(虽然不是重复的)。
发生的事情是 D3 的创建者 Mike Bostock 在 D3 v2 中引入了一个魔法行为,他保留在 D3 v3.x 中,但决定在 D3 v4.x 中放弃。要了解更多相关信息,请查看此处:什么让软件变得优秀?他是这样说的:
D3 2.0 引入了一个变化:附加到输入选择现在会将输入元素复制到更新选择中 [...] D3 4.0 删除了 enter.append 的魔力。(实际上,D3 4.0 完全消除了输入和普通选择之间的区别:现在只有一类选择。)
让我们来看看它。
这是您使用 D3 v3 的代码:
var svg = d3.select('body').append('svg')
.attr('width', 250)
.attr('height', 250);
//render the data
function render(data) {
//Bind
var circles = svg.selectAll('circle').data(data);
//Enter
circles.enter().append('circle')
.attr('r', 10);
//Update
circles
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
//Exit
circles.exit().remove();
}
var myObjects = [{
x: 100,
y: 100
}, {
x: 130,
y: 120
}, {
x: 80,
y: 180
}, {
x: 180,
y: 80
}, {
x: 180,
y: 40
}];
render(myObjects);
<script src='https://d3js.org/d3.v3.min.js'></script>
现在使用相同的代码,使用 D3 v4。它会“打破”:
var svg = d3.select('body').append('svg')
.attr('width', 250)
.attr('height', 250);
//render the data
function render(data) {
//Bind
var circles = svg.selectAll('circle').data(data);
//Enter
circles.enter().append('circle')
.attr('r', 10);
//Update
circles
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
//Exit
circles.exit().remove();
}
var myObjects = [{
x: 100,
y: 100
}, {
x: 130,
y: 120
}, {
x: 80,
y: 180
}, {
x: 180,
y: 80
}, {
x: 180,
y: 40
}];
render(myObjects);
<script src='https://d3js.org/d3.v4.min.js'></script>
“中断”是指圆圈将被附加,但它们不会在“输入”选择中接收x和y属性,并且它们将默认为零。这就是为什么您会在左上角看到所有圆圈的原因。
解决方案:合并选择:
circles.enter().append('circle')
.attr('r', 10)
.merge(circles) //from now on, enter + update
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
根据API,merge()...
... 通常用于在数据连接后合并输入和更新选择。分别修改进入和更新元素后,可以合并两个选择并对其进行操作,无需重复代码。
这是代码merge():
var svg = d3.select('body').append('svg')
.attr('width', 250)
.attr('height', 250);
//render the data
function render(data) {
//Bind
var circles = svg.selectAll('circle').data(data);
//Enter
circles.enter().append('circle')
.attr('r', 10)
.merge(circles) //from now on, enter + update
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
//Exit
circles.exit().remove();
}
var myObjects = [{
x: 100,
y: 100
}, {
x: 130,
y: 120
}, {
x: 80,
y: 180
}, {
x: 180,
y: 80
}, {
x: 180,
y: 40
}];
render(myObjects);
<script src='https://d3js.org/d3.v4.min.js'></script>