D3 更新 circle-pack 数据新节点与现有节点重叠
D3 update circle-pack data new nodes overlap existing nodes
我正在关注 General Update Pattern,但在分层方面遇到问题。
使用circle-pack布局,我pack新数据,update,enter 和 退出 圆形元素。但是,当新元素 进入 时,它们会与 updated 圈重叠。
数据键函数基于元素名称:
.data(nodes, function(d, i) { return d.name; });
所以我的圆圈包有一个 更新的 圆圈(位置和大小正确),但它隐藏在新 进入的 家长圈子.
有没有办法将这些 更新的 节点发送到前面或在 输入的 圈上重新绘制它们?
--更新--
正如关闭此问题的人所建议的那样,我尝试使用 moveToFront 实现链接到解决方案。
我在 update 部分添加了以下代码(没有任何改变),然后尝试在 enter 之后添加它和 exit 代码,这也没有任何区别。
.each("end", function(d){ d3.select(this).moveToFront(); });
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
为清楚起见,选择和更新如下所示:
// Load data into svg, join new data with old elements, if any.
var nodes = pack.nodes(postData);
node = root = postData;
groupNodes = svg.selectAll("g")
.data(nodes, function(d, i) { return d.name; });
// Update and transition existing elements
groupNodes.select("circle")
.transition()
.duration(duration)
.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; })
.attr('r', function(d) { return d.r; })
.each("end", function(d){ d3.select(this).moveToFront(); });
此 moveToFront 代码对我的输出没有影响,更新的 圆圈仍然落后于 输入的选择圈子。
总结:这个问题似乎是由层次结构布局(圆形包装)引起的,它期望圆圈按照数据层次结构的顺序绘制。 d3 更新模式(使用进入、更新和退出选择)导致选定的更新元素在重新绘制层次结构时保留在 svg 中,并在其上绘制新层。这些节点的父节点已正确设置,因此 parentNode.appendChild
在这种情况下不会执行任何操作,因为这不是问题的原因。
Here is a fiddle 来证明我的问题。我试过将 moveToFront
代码放在不同的地方,没有明显的区别。
当您点击 "Change Data" 按钮时,它会重新绘制圆圈,但是两个数据集之间名称重叠的任何圆圈都没有正确嵌套在圆圈包中。 "Group A" 的子级隐藏在其中一个父级圈子的后面。您可以通过 Inspect Element 验证节点是否存在。
更新后的另一张照片 fiddle:
D3 提供了一种根据使用 .sort()
function 绑定到元素的数据重新排序元素的方法。在您的情况下,要检查的条件是元素的 .depth
属性——"deeper" 元素应出现在前面:
svg.selectAll("g")
.sort(function (a, b) {
if (a.depth < b.depth) return -1;
else return 1;
});
完成演示 here。
我正在关注 General Update Pattern,但在分层方面遇到问题。
使用circle-pack布局,我pack新数据,update,enter 和 退出 圆形元素。但是,当新元素 进入 时,它们会与 updated 圈重叠。
数据键函数基于元素名称:
.data(nodes, function(d, i) { return d.name; });
所以我的圆圈包有一个 更新的 圆圈(位置和大小正确),但它隐藏在新 进入的 家长圈子.
有没有办法将这些 更新的 节点发送到前面或在 输入的 圈上重新绘制它们?
--更新-- 正如关闭此问题的人所建议的那样,我尝试使用 moveToFront 实现链接到解决方案。
我在 update 部分添加了以下代码(没有任何改变),然后尝试在 enter 之后添加它和 exit 代码,这也没有任何区别。
.each("end", function(d){ d3.select(this).moveToFront(); });
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
为清楚起见,选择和更新如下所示:
// Load data into svg, join new data with old elements, if any.
var nodes = pack.nodes(postData);
node = root = postData;
groupNodes = svg.selectAll("g")
.data(nodes, function(d, i) { return d.name; });
// Update and transition existing elements
groupNodes.select("circle")
.transition()
.duration(duration)
.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; })
.attr('r', function(d) { return d.r; })
.each("end", function(d){ d3.select(this).moveToFront(); });
此 moveToFront 代码对我的输出没有影响,更新的 圆圈仍然落后于 输入的选择圈子。
总结:这个问题似乎是由层次结构布局(圆形包装)引起的,它期望圆圈按照数据层次结构的顺序绘制。 d3 更新模式(使用进入、更新和退出选择)导致选定的更新元素在重新绘制层次结构时保留在 svg 中,并在其上绘制新层。这些节点的父节点已正确设置,因此 parentNode.appendChild
在这种情况下不会执行任何操作,因为这不是问题的原因。
Here is a fiddle 来证明我的问题。我试过将 moveToFront
代码放在不同的地方,没有明显的区别。
当您点击 "Change Data" 按钮时,它会重新绘制圆圈,但是两个数据集之间名称重叠的任何圆圈都没有正确嵌套在圆圈包中。 "Group A" 的子级隐藏在其中一个父级圈子的后面。您可以通过 Inspect Element 验证节点是否存在。
更新后的另一张照片 fiddle:
D3 提供了一种根据使用 .sort()
function 绑定到元素的数据重新排序元素的方法。在您的情况下,要检查的条件是元素的 .depth
属性——"deeper" 元素应出现在前面:
svg.selectAll("g")
.sort(function (a, b) {
if (a.depth < b.depth) return -1;
else return 1;
});
完成演示 here。