d3.js - v3 和 v4 - 输入和更新差异
d3.js - v3 and v4 - Enter and Update differences
我正在尝试获取 x
和 y
的值以使用 d3.js v4 制作圆圈。使用以下代码,我设法创建了类似于圆圈行为的图表,但是当我尝试 运行 v4 中的相同代码时,它不再起作用。我知道 v4 的更新有一些差异,但我没有找到任何相关信息。所以我想知道是否有人可以帮助我 运行 d3.js v4.
中的这段代码
这是使用 v3 的代码(使用 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.v3.min.js'></script>
d3v4 中的更新模式已更改。
摘自documentation:
In addition, selection.append no longer merges entering nodes into the
update selection; use selection.merge to combine enter and update
after a data join.
你应该这样重写你的代码:
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) // <== !!!
.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://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
这是预期的行为,我之前在 中对此进行了解释(不过不是重复的)。
发生的事情是 D3 的创建者 Mike Bostock 在 D3 v2 中引入了一个魔术行为,他在 D3 v3.x 中保留了该行为,但决定在 D3 v4.x 中放弃。要了解更多相关信息,请看这里:What Makes Software Good? 他是这么说的:
D3 2.0 introduced a change: appending to the enter selection would now copy entering elements into the update selection [...] D3 4.0 removes the magic of enter.append. (In fact, D3 4.0 removes the distinction between enter and normal selections entirely: there is now only one class of selection.)
让我们看看。
这是您使用 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。它将 "break":
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>
"break" 我的意思是圆圈将被追加,但它们不会收到 "enter" 选择中的 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()
...
... is commonly used to merge the enter and update selections after a data-join. After modifying the entering and updating elements separately, you can merge the two selections and perform operations on both without duplicate code.
这是带有 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>
我正在尝试获取 x
和 y
的值以使用 d3.js v4 制作圆圈。使用以下代码,我设法创建了类似于圆圈行为的图表,但是当我尝试 运行 v4 中的相同代码时,它不再起作用。我知道 v4 的更新有一些差异,但我没有找到任何相关信息。所以我想知道是否有人可以帮助我 运行 d3.js v4.
这是使用 v3 的代码(使用 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.v3.min.js'></script>
d3v4 中的更新模式已更改。 摘自documentation:
In addition, selection.append no longer merges entering nodes into the update selection; use selection.merge to combine enter and update after a data join.
你应该这样重写你的代码:
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) // <== !!!
.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://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
这是预期的行为,我之前在
发生的事情是 D3 的创建者 Mike Bostock 在 D3 v2 中引入了一个魔术行为,他在 D3 v3.x 中保留了该行为,但决定在 D3 v4.x 中放弃。要了解更多相关信息,请看这里:What Makes Software Good? 他是这么说的:
D3 2.0 introduced a change: appending to the enter selection would now copy entering elements into the update selection [...] D3 4.0 removes the magic of enter.append. (In fact, D3 4.0 removes the distinction between enter and normal selections entirely: there is now only one class of selection.)
让我们看看。
这是您使用 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。它将 "break":
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>
"break" 我的意思是圆圈将被追加,但它们不会收到 "enter" 选择中的 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()
...
... is commonly used to merge the enter and update selections after a data-join. After modifying the entering and updating elements separately, you can merge the two selections and perform operations on both without duplicate code.
这是带有 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>