javascript 使用 NodeSize 的节点之间的 D3 树布局分离
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17558649/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
D3 Tree Layout Separation Between Nodes using NodeSize
提问by aug
Right now I am trying to separate my rectangle nodes because they overlap as shown in the picture below:
现在我正在尝试分离我的矩形节点,因为它们如下图所示重叠:
I took a look and found out that D3 offers a nodeSizeand separationmethod but for some reason it did not work.
我看了一下,发现 D3 提供了nodeSize和分离方法,但由于某种原因它不起作用。
I found this blog posttalking about the issue but he says
我发现这篇博文在谈论这个问题,但他说
The size property doesn't exist in nodes, so it will be whatever property you want to control the size of them.
节点中不存在 size 属性,因此它将是您想要控制它们大小的任何属性。
but clearly there is a nodeSize method so I feel like I am simply using the method incorrectly and/or the blog post is out-of-date. I want to shape my nodes to be the size of the rectangle and space them out evenly so they do not overlap each other. Does anyone know how to use the methods properly? The documentation about these methods isn't explained very well and it isn't yielding any difference. I also couldn't find many examples where people changed the nodeSize of trees or needed separation for rectangular objects (there were some examples regarding circular ones but I feel that's too different...)
但显然有一个 nodeSize 方法,所以我觉得我只是错误地使用了该方法和/或博客文章已过时。我想将我的节点塑造成矩形的大小并将它们均匀地间隔开,这样它们就不会相互重叠。有谁知道如何正确使用这些方法?关于这些方法的文档没有得到很好的解释,也没有产生任何区别。我也找不到很多例子,人们改变了树的 nodeSize 或需要分离矩形对象(有一些关于圆形对象的例子,但我觉得这太不同了......)
Here is the relevant code. I will try to prepare a JSFiddle.
这是相关的代码。我将尝试准备一个 JSFiddle。
var margin = {top: 20, right: 120, bottom: 20, left: 120},
height = 960 - margin.right - margin.left,
width = 800 - margin.top - margin.bottom,
rectW = 70;
rectH = 30;
//bbox = NaN,
maxTextLength = 0;
var i = 0,
duration = 750,
root;
//paths from each node drawn initially here
//changed to d.x, d.y
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x+rectW/2, d.y+rectH/2];
//.projection(function(d) { return [d.x+bbox.getBBox().width/2, d.y+bbox.getBBox().height/2];
});
var tree = d3.layout.tree()
.nodeSize([30,70])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2); })
.size([width, height]);
var svg = d3.select("body")
.append("svg")
.attr("height","100%").attr("width","100%")
.call(d3.behavior.zoom().on("zoom", redraw))
.append("g")
.attr("transform", "translate(" + margin.top + "," + margin.left + ")");
回答by aug
UPDATE 05/04/2018: It is my understanding d3 has changed a lot (for the better) to be a lot more modular. For those who are looking towards this answer, this was using a much older version of d3 (specifically v3).
2018 年 5 月 4 日更新:据我所知,d3 已经发生了很大变化(变得更好),变得更加模块化。对于那些正在寻找这个答案的人,这是使用旧版本的 d3(特别是 v3)。
A lot of the findings are still relevant for the d3-hierarchy
package under cluster.size()
and cluster.nodeSize()
and I am planning to potentially update my example to use that. For historical reference though, I'm leaving the bottom untouched.
很多研究结果仍然是相关的d3-hierarchy
包下cluster.size()
,并cluster.nodeSize()
和我计划可能更新我的例子中使用的。不过,作为历史参考,我将底部保持不变。
Here is a jsFiddle: http://jsfiddle.net/augburto/YMa2y/
这是一个 jsFiddle:http: //jsfiddle.net/augburto/YMa2y/
EDIT: Updated and move the example to Codepen. The example still exists on jsFiddle but Codepen seems to have a nicer editor and allows you to easily fork. I'll also try to add the example directly to this answer once I've reduced the amount of content in it.
编辑:更新并将示例移至 Codepen。该示例仍然存在于 jsFiddle 上,但 Codepen 似乎有一个更好的编辑器,并允许您轻松分叉。一旦我减少了其中的内容量,我也会尝试将示例直接添加到此答案中。
http://codepen.io/augbog/pen/LEXZKK
http://codepen.io/augbog/pen/LEXZKK
Updating this answer. I talked with my friend and we looked at the source for size
and nodeSize
更新这个答案。我跟我的朋友,我们看了源size
和nodeSize
tree.size = function(x) {
if (!arguments.length) return nodeSize ? null : size;
nodeSize = (size = x) == null;
return tree;
};
tree.nodeSize = function(x) {
if (!arguments.length) return nodeSize ? size : null;
nodeSize = (size = x) != null;
return tree;
};
When you set a size
for the tree, you are setting a fixed size so that the tree has to conform to that width and height. When you set a nodeSize
, the tree has to be dynamic so it resets the size of the tree.
当您size
为树设置 a 时,您正在设置一个固定大小,以便树必须符合该宽度和高度。当您设置 a 时nodeSize
,树必须是动态的,因此它会重置树的大小。
When I specified size
after nodeSize
, I was pretty much overriding what I wanted haha...
当我size
在之后指定时nodeSize
,我几乎覆盖了我想要的东西哈哈...
Bottom line: If you want nodeSize
to work, you can't have a fixed tree size. It will set the size to null
. Do not declare a size
if you are declaring a nodeSize
.
底线:如果你想nodeSize
工作,你不能有一个固定的树大小。它将大小设置为null
. size
如果您要声明 a ,则不要声明 a nodeSize
。
EDIT: D3.js actually updated the documentation. Thanks to whoever did that because it is way clearer now!
编辑:D3.js 实际上更新了文档。感谢这样做的人,因为它现在更清晰了!
The nodeSize property is exclusive with tree.size; setting tree.nodeSize sets tree.size to null.
nodeSize 属性与 tree.size 互斥;设置 tree.nodeSize 将 tree.size 设置为 null。
This is what my tree looks like now. I have also added zoom functionality as well as how to center text within the rectangle.
这就是我的树现在的样子。我还添加了缩放功能以及如何在矩形内居中文本。
回答by Danny Harding
I didn't quite understand the accepted answer until I did some digging of my own, so I thought I'd share what I found as well...
直到我自己进行了一些挖掘,我才完全理解已接受的答案,所以我想我也会分享我的发现......
If you are using .size()
and your nodes are overlapping, use .nodeSize()
instead
如果您正在使用.size()
并且您的节点重叠,请.nodeSize()
改用
As explained in the accepted answer, .size()
sets the tree's available size, and so depending on the spacing between cousin nodes, second cousins, etc. they may get squished together and overlap. Using .nodeSize()
simply says each node should get this much space, so they will never overlap!
如已接受的答案中所述,.size()
设置树的可用大小,因此根据表亲节点、第二个表亲等之间的间距,它们可能会被挤压在一起并重叠。使用.nodeSize()
简单地说每个节点应该有这么多空间,所以它们永远不会重叠!
The code that ended up working for me was
最终对我来说有效的代码是
var nodeWidth = 300;
var nodeHeight = 75;
var horizontalSeparationBetweenNodes = 16;
var verticalSeparationBetweenNodes = 128;
var tree = d3.layout.tree()
.nodeSize([nodeWidth + horizontalSeparationBetweenNodes, nodeHeight + verticalSeparationBetweenNodes])
.separation(function(a, b) {
return a.parent == b.parent ? 1 : 1.25;
});
Without horizontalSeparationBetweenNodes
and verticalSeparationBetweenNodes
the nodes edges were touching each other. I also added this .separation()
to decrease the amount of space between cousin nodes, as my nodes are pretty wide and lots of space was getting wasted.
没有horizontalSeparationBetweenNodes
和verticalSeparationBetweenNodes
节点边缘相互接触。我还添加了这个.separation()
以减少表亲节点之间的空间量,因为我的节点非常宽并且浪费了很多空间。
Note: This is for d3 v3, not v4
注意:这是针对 d3 v3,而不是 v4
回答by Kevin Gunn
First, thanks to all those who posted before, pure gold. I wanted to add to this post for those that might be struggling with the offset problem associated with a horizontally drawn tree.
首先,感谢之前发帖的所有人,纯金。我想为那些可能正在为与水平绘制的树相关的偏移问题而苦苦挣扎的人添加这篇文章。
The key is, if you switch from .size() to .nodeSize() on a horizontal tree, you'll notice your root node seems to jump/reorient to be located at (0,0). And per the d3.js documentation this is actually the case (see https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize)
关键是,如果你在水平树上从 .size() 切换到 .nodeSize(),你会注意到你的根节点似乎跳转/重定向到 (0,0)。根据 d3.js 文档,情况确实如此(请参阅https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize)
However, to adjust you just need to make sure to reorient your viewBox
.
That is to say, when you .append
your svg
you need to explicitly set your viewBox
. Here's my hacky little line where it worked for me...
但是,要进行调整,您只需要确保重新定位您的viewBox
. 也就是说,当你.append
你svg
你需要明确设置你的viewBox
。这是我的 hacky 小行,它对我有用......
svg = d3.select("#tree").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + 0 + 0)
.attr("viewBox", "0 "+(-1*(height-margin.top-margin.bottom)/2)+" "+width+" "+height)
.append("g")
.attr("transform", "translate("
+ margin.left + "," + 0 + ")");
回答by Cybernetic
D3 now does things through Observable.
D3 现在通过Observable做事。
To set thenodeSizelook for the line:
要设置nodeSize查找该行:
main.variable(observer("tree")).define("tree", ["d3","dx","dy"],
function(d3,dx,dy){return(
d3.tree()
And set nodeSize with added constants:
并使用添加的常量设置 nodeSize:
main.variable(observer("tree")).define("tree", ["d3","dx","dy"],
function(d3,dx,dy){return(
d3.tree().nodeSize([dx + 10, dy + 10])
Or use a function to set values wrt chart size as discussed in other answer using the older D3 approach.
或者使用一个函数来设置图表大小的值,如使用较旧的 D3 方法的其他答案中所述。