D3更新循环包数据新节点重叠现有节点 [英] D3 update circle-pack data new nodes overlap existing nodes

查看:202
本文介绍了D3更新循环包数据新节点重叠现有节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在关注来演示我的问题。我试着把 moveToFront 代码放在各个地方,没有明显的区别。
当您点击更改数据按钮,它将重画圆圈,但任何名称重叠的两个数据集之间的圈子没有正确嵌套在圈子包。 A组的孩子隐藏在一个父圈后面。您可以通过Inspect Element验证节点。



来自更新的小提琴的另一张图片:

解决方案

D3提供了一种方法,根据绑定到它们的数据,使用 .sort() function 。在你的情况下,检查的条件是元素的 .depth 属性 - 更深元素应该出现在前面:

  svg.selectAll(g)
.sort(function(a,b){
if(a.depth< b.depth )return -1;
else return 1;
});

完成演示此处


I'm following the General Update Pattern but having an issue with regards to layering.

Using a circle-pack layout, I pack the new data, update, enter and exit the circle elements. However, when new elements enter, they overlap the updated circles.

Data key function is based on element name:

.data(nodes, function(d, i) { return d.name; });

So my circle pack has a spot for the updated circle (of the correct location and size) but it's hidden behind its newly entered parent circle.

Is there a way to send these updated nodes to the front or redraw them over the entered circles?

--UPDATE-- As suggested by the person who closed this issue, I've tried implementing the linked to solution using moveToFront.

I added the following code in my update section (which didn't change anything) and then tried adding it after the enter and exit code, which also didn't make any difference.

.each("end", function(d){ d3.select(this).moveToFront(); });


d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};

For clarity, this is what the selection and update looks like:

// 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(); });

This moveToFront code does not make a difference to my output, and the updated circles remain behind the entered selection circles.

To summarize: the issue seems to be caused by a hierarchy layout (circle-packing) which expects the circles to be drawn in the order of the data's hierarchy. The d3 update pattern (using enter, update and exit selections) causes selected update elements to remain in the svg when the hierarchy is re-drawn, and the new layers are drawn over it. The parents of those nodes are already correctly set, so parentNode.appendChild doesn't do anything in this case, because it's not the cause of the issue.

Here is a fiddle to demonstrate my issue. I've tried putting the moveToFront code in various places, with no visible difference. When you hit the "Change Data" button, it'll redraw the circles, but any circles whose names overlap between the two data sets are not nested properly in the circle-pack. Children of "Group A" are hidden behind one of the parent circles. You can verify the nodes are there via Inspect Element.

Another pic from the updated fiddle:

解决方案

D3 provides a way to reorder elements based on the data bound to them with the .sort() function. In your case, the condition to check is the .depth attribute of the elements -- "deeper" elements should appear in front:

svg.selectAll("g")
  .sort(function (a, b) {
    if (a.depth < b.depth) return -1;
    else return 1;
  });

Complete demo here.

这篇关于D3更新循环包数据新节点重叠现有节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆