【问题标题】:D3 Tree Layout Separation Between Nodes using NodeSize使用 NodeSize 在节点之间分离 D3 树布局
【发布时间】:2013-07-09 21:32:35
【问题描述】:

现在我正在尝试分离我的矩形节点,因为它们重叠如下图所示:

我看了看,发现 D3 提供了 nodeSizeseparation 方法,但由于某种原因它不起作用。

我发现这个 blog post 在谈论这个问题,但他说

节点中不存在 size 属性,因此它将是您想要控制它们大小的任何属性。

但显然有一个 nodeSize 方法,所以我觉得我只是错误地使用了该方法和/或博客文章已过时。我想将我的节点塑造成矩形的大小并将它们均匀地隔开,这样它们就不会相互重叠。有谁知道如何正确使用这些方法?关于这些方法的文档没有很好地解释,也没有产生任何区别。我也找不到很多人们改变树的节点大小或需要分隔矩形对象的例子(有一些关于圆形的例子,但我觉得这太不同了......)

这里是相关代码。我会尝试准备一个 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 + ")");

【问题讨论】:

  • 看起来您的nodeSize 规范将高度作为宽度,将宽度作为高度。
  • @LarsKotthoff 我做了相反的事情,但问题是当我改变它时似乎没有区别。当我输入大小时,我希望节点能够正确地间隔开,但也许我误解了它的工作原理?
  • 这也是我对文档的理解。你有没有玩弄这些价值观,看看它们是否有什么不同?
  • @LarsKotthoff 是的,我什至将它们设置为荒谬的数量,例如 (1000, 500) 并且没有任何改变......
  • @invincibleDudess 我认为有几种方法可以解决它,但总会有一个问题取决于你的树有多大,因为视口只会这么大。我的示例允许您拖动树并放大或缩小以处理此问题。你也可以consider repositioning where your tree is located so every time you click on a node, it centers the tree。希望有帮助!

标签: javascript tree d3.js


【解决方案1】:

2018 年 5 月 4 日更新:据我了解,d3 发生了很大变化(变得更好),变得更加模块化。对于那些正在寻找这个答案的人,这是使用更旧版本的 d3(特别是 v3)。

很多发现仍然与cluster.size() and cluster.nodeSize() 下的d3-hierarchy 包相关,我计划可能更新我的示例以使用它。不过,作为历史参考,我将保持底部不变。


这是一个 jsFiddle:http://jsfiddle.net/augburto/YMa2y/

编辑:更新并将示例移至 Codepen。该示例仍然存在于 jsFiddle 上,但 Codepen 似乎有一个更好的编辑器,并且允许您轻松地分叉。一旦减少了其中的内容量,我还将尝试将示例直接添加到此答案中。

http://codepen.io/augbog/pen/LEXZKK

更新此答案。我和我的朋友谈过,我们查看了sizenodeSize 的来源

  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;
  };

当您为树设置size 时,您将设置一个固定大小,以便树必须符合该宽度和高度。当您设置nodeSize 时,树必须是动态的,因此它会重置树的大小。

当我在nodeSize 之后指定size 时,我几乎覆盖了我想要的东西哈哈...

底线:如果你想让nodeSize 工作,你不能有一个固定的树大小。它将大小设置为null。如果您要声明 nodeSize,请不要声明 size

编辑:D3.js 实际上是 updated the documentation。感谢这样做的人,因为现在更清楚了!

nodeSize 属性是 tree.size 独有的;环境 tree.nodeSize 将 tree.size 设置为 null。

这就是我的树现在的样子。我还添加了缩放功能以及如何在矩形内居中文本。

【讨论】:

  • 我无法让它工作,你能发布更多代码或 jsfiddle 吗?谢谢
  • @Dhana 我会尽我所能。抱歉,我从来没有完成过。
  • @Dhana 我现在在我的答案中更新了 jsFiddle。希望对你有帮助:)
  • @aug 谢谢,拯救了我的一天
  • 我认为还有一点小改进。您还应该添加 if(d3.event.defaultPrevented) return ;作为点击函数的第一行。
【解决方案2】:

在我自己进行一些挖掘之前,我不太明白接受的答案,所以我想我也会分享我的发现......

如果您使用.size() 并且您的节点重叠,请改用.nodeSize()

正如接受的答案中所解释的,.size() 设置树的可用大小,因此根据表亲节点、第二表亲等之间的间距,它们可能会被挤压在一起并重叠。使用.nodeSize() 只是说每个节点都应该获得这么多的空间,所以它们永远不会重叠!

最终为我工作的代码是

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

如果没有horizontalSeparationBetweenNodesverticalSeparationBetweenNodes,节点边会相互接触。我还添加了这个.separation() 以减少表亲节点之间的空间量,因为我的节点非常宽并且浪费了大量空间。

注意:这是针对 d3 v3,而不是 v4

【讨论】:

    【解决方案3】:

    首先,感谢所有之前发布的人,纯金。 我想为那些可能正在为与水平绘制的树相关的偏移问题而苦苦挣扎的人添加到这篇文章中。

    关键是,如果您在水平树上从 .size() 切换到 .nodeSize(),您会注意到您的根节点似乎跳转/重新定向到位于 (0,0) 处。 根据 d3.js 文档,情况确实如此(请参阅https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize

    但是,要进行调整,您只需确保重新定位您的 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 + ")");
    

    【讨论】:

      【解决方案4】:

      D3 现在通过 Observable 进行操作。

      设置 nodeSize寻找

      main.variable(observer("tree")).define("tree", ["d3","dx","dy"],
      function(d3,dx,dy){return(
      d3.tree()
      

      并且用添加的常量设置nodeSize

      main.variable(observer("tree")).define("tree", ["d3","dx","dy"],
      function(d3,dx,dy){return(
      d3.tree().nodeSize([dx + 10, dy + 10])
      

      或者使用一个函数来设置图表大小的值,如其他答案中所讨论的,使用旧的 D3 方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-30
        • 2015-07-21
        相关资源
        最近更新 更多