【问题标题】:D3.js Adding links between elements in a radial tree (Hierarchical edge bundling elements)D3.js 在径向树中的元素之间添加链接(分层边缘捆绑元素)
【发布时间】:2016-10-26 13:07:45
【问题描述】:

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

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

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 结合起来,但请记住,交互将在以后成为其中的一部分。

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

我目前最大的问题是 HEB 没有“根”,但树以单个项目开头。所以到目前为止我所尝试的一切都导致树的中心变得一团糟。

请注意,树的中心有一个圆圈来覆盖根到级别 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");

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

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

【问题讨论】:

  • 绝对不是重复的,但似乎与this有关。

标签: javascript css json d3.js tree


【解决方案1】:

我目前最大的问题是 HEB 没有“根”,但树以单个项目开头。所以到目前为止我所尝试的一切都导致树的中心变得一团糟。

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

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

我能为您找到的最佳资源是this Stack Mathematics Answer。其中有几点对我来说特别突出:

  1. 您可能会有一堆乱七八糟的连接/分支,但如果它是交互式的,并且当您将鼠标悬停在特定节点上时,进出特定节点的分支会亮起,那么它仍然可以是可读/可用的图表。
  2. 您可以尝试不同的排序算法,直到找到适合您数据的算法。
  3. 圆内可以有一个或多个节点,在这种情况下,将根节点放在中间可能很有意义。

这不是一个实用的答案,因为它在 Mathematica 中,但我认为它对基础理论和技术的解释很有用。

如果您不想将树的根放在中心,也许更艺术的方法是使从父级到根父级的所有分支都是半透明的,并且可能是不同的颜色。

希望这会有所帮助!

【讨论】:

  • 问题是我确实想要那些链接在中间,所有的。我想要的只是我已经拥有的径向树,并根据数据“简单地”在中间添加这些链接(与分层边缘捆绑相同的链接)。当我说“中间乱七八糟”时,我主要是指一个小圆圈,单击时填充并清空,而不是常规树。我不需要一种新的数据排序方式,我只需要那些链接,它们稍后将不得不在折叠等时进行更新。除此之外,我拥有的树与您建议的第一个树相同,只是可折叠。
  • 嗨。你找到解决方案了吗?我尝试将 2 个层次结构组合在一起。例如 Tree 和 Pack 作为叶子。不知道如何在一个 SVG 中做到这一点。如果您有任何信息,请分享:) 谢谢。
  • @AlexeyRyzhkov 抱歉,没有新信息。但是,如果您找到比我更好的解决方案,请在此问题的答案中分享!
  • 不是半透明的——“从父节点到根父节点的所有分支”——只是透明或不显示。这可以分别使用样式(“stroke”,“none”)或(“stroke-width”,0)来实现。并基于链接级别应用,可能使用 D3.js 可能的过滤。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 2015-04-14
    • 1970-01-01
    • 2016-11-27
    • 2016-03-19
    相关资源
    最近更新 更多