D3.js在径向树中的元素之间添加链接(分层边缘捆绑元素)

时间:2016-10-26 13:07:45

标签: javascript css json d3.js tree

几个月前,我尝试了combining Hierarchical Edge Bundling and Radial Reingold–Tilford Tree using d3.js

enter image description here

我从HEB开始尝试将它变成一棵树。 事情并没有按照我想要的方式解决,我意识到从一个可折叠的径向树(不是Reingold Tilford)开始,可能会有更好的角度。

enter image description here

Here is a JSFiddle of the radial tree

数据模型也发生了变化,因为元素现在有了名称,子项和导入(链接)。

var flare =
{
    "name": "root",
    "children": [
        {
            "name": "test1.parent1","children": [
                {"name": "test1.child11","children": [
                    {"name": "test1.child111"},
                    {"name": "test1.child112"}
                ]}
            ],"imports": ["test2.parent2","test3.parent3","test4.parent4"]
        },
        {
            "name": "test2.parent2","children": [
                {"name": "test2.child21"},
                {"name": "test2.child22"},
                {"name": "test2.child28","children":[
                    {"name": "test2.child281"},
                    {"name": "test2.child282"}
                ]}
            ],"imports": ["test3.parent3"]
        },
        {"name": "test3.parent3","imports": ["test4.parent4"]},
        {
            "name": "test4.parent4","children": [
                {"name": "test4.child41"},
                {"name": "test4.child42"}
            ]
        }
    ]
};

为了慢慢开始,我想将Mike Bostock的non-interactive Hierarchical edge bundling与当前的JSFiddle结合起来,但要记住,之后的交互将成为其中的一部分。

此外,只有第一级必须有链接(父 - 父链接),如下所示(我想要的结果):

enter image description here

我目前最大的问题是HEB没有" root",但树开头只有一个项目。所以到目前为止我所尝试的一切都导致了树的中心一团糟。

请注意,树的中心有一个圆圈,用于覆盖1级链接的根,因此树从1级(父级)开始。

var circle = svg.append("circle")
  .attr("cx", 0)
  .attr("cy", 0)
  .attr("r", diameter - 725.3)
  .style("fill", "#F3F5F6")
  .style("stroke-width", 0.2)
  .style("stroke", "black");

理想情况下,父级之间的链接必须在级别(un)折叠时更新,就像它对节点和级别之间的链接一样,但是这可以在以后获得,并且在最初获得第一级之后可能不会那么困难要显示的链接。此外,如有必要,数据模板可能会更改,但所有3条信息都很重要(名称,子项和导入)。

另一种方法是能够将数据更改为不包含根部分,并且它的行为与现在完全相同 部分答案也是受欢迎的。

2 个答案:

答案 0 :(得分:0)

  

我目前最大的问题是HEB没有" root",但树开头只有一个项目。所以到目前为止我所尝试的一切都导致了树的中心一团糟。

鉴于你有一个root,为什么不把它设置为中心"节点"并使其成为径向树,如thisHere是另一个例子,但有多个根。

那就是说,你没有要求一个径向树,即使它听起来会回答你的问题。如果你决心把东西排列成不同镭的圆圈,那么要解决的问题可能就是线条的纵横交错看起来如此混乱"。如果是这种情况,则可以使用不同的排序算法。 Here是一篇文章,它扩展了在D3.js的类似场景中使用不同的排序算法。 D3布局算法也是open source online

我能找到的最好的资源是this Stack Mathematics Answer。其中有几点特别突出:

  1. 你可以完全搞乱连接/分支,但如果它是交互式的,当你将鼠标悬停在该节点上时,指向特定节点的分支会亮起,那么它仍然可以是一个可读/可用的图形
  2. 您可以尝试不同的排序算法,直到找到适合您的数据的算法。
  3. 你可以在圈内有一个或多个节点,在这种情况下,将根节点放在中间位置可能很有意义。
  4. 这不是一个实际可用的答案,因为它在Mathematica中,但我认为它对基础理论和技术的解释是有用的。

    如果你不想把树的根放在中心,或许更具艺术性的方法,那就是让从父母到根父母的所有分支都是半透明的,可能是不同的颜色。

    (Sorry for the low-quality photoshop)

    希望这有帮助!

答案 1 :(得分:0)

我已经设法在这个JSFiddle中的元素之间添加链接,使用Mike Bostock在原始分层边缘捆绑中找到的部分代码,并将它们添加到可折叠树的径向版本中。但是,在折叠或扩展孩子时,他们不会更新!

var bundle = d3.layout.bundle();

var line = d3.svg.line.radial()
    .interpolate("bundle")
    .tension(.85)
    .radius(function(d) { return d.y; })
    .angle(function(d) { return d.x / 180 * Math.PI; });

然后在update(source)

var middleLinks = packageImports(root);

svg.selectAll("path.middleLink")
          .data(bundle(middleLinks))
        .enter().append("path")
          .attr("class", "middleLink")
          .attr("d", line);

“packageImport”功能可以在底部找到。

function packageImports(json) {
      var map = {},
          imports = [];

      console.log(json.children);

      // Compute a map from name to node.
      json.children.forEach(function(d) {
        console.log(d.name)
        map[d.name] = d;
      });

      // For each import, construct a link from the source to target node.
      json.children.forEach(function(d) {
        if (d.imports) d.imports.forEach(function(i) {
          imports.push({source: map[d.name], target: map[i]});
        });
      });

      console.log(imports);
      return imports;
    }