树布局

365 edited this page Jul 27, 2016 · 2 revisions

WikiAPI--中文手册布局树布局

树布局使用Reingold–Tilford “tidy” algorithm算法生成整齐的链接点模型树状图。一个典型的例子:在软件的架构中,树布局可以用来组织软件的包及类的层级结构。

diagonal

像其他大多数布局一样,var tree = d3.layout.tree() 得到的即是一个对象也是一个函数;也就是说:可以像调用函数一样调用布局(tree()),也可以直接调用 tree 提供的一些 API 接口来改变其行为,如:```tree.children(Function),同样支持级联调用。

# d3.layout.tree()

创建一个树布局实例,使用默认的设置:

  • tree.sort = null;
  • tree.children = function(d) { return d.children; }, d.children 是一个数组;
  • tree.separation = function(a, b) { return a.parent == b.parent ? 1 : 2; }, 即:兄弟节点间是 1 倍距离、表亲兄弟间是 2 倍距离;(注:该 距离 是树布局基于当前 depth 层级计算出来基础间距;)

# tree(root)
# tree.nodes(root)

运行树布局,返回一个基于根结点 root 的所有结点的数组;树布局是 D3 层布局家族中的一部分,这些布局都遵循类似的基本结构:布局的输入参数是层次结构的根节点 root,输出值是一个经过计算的全部结点的位置的数组;每个节点中包含以下属性:

  • parent - 父节点引用,根节点为 null;
  • children - 所有子节点,叶子节点为 null;
  • depth - 当前节点所处层级(也叫深度);根节点为 0;
  • x - 计算得到的当前节点的计 x 坐标;
  • y - 计算得到的当前节点的计 y 坐标;

尽管树布局计算得到的 x 和 y 有 size 大小概念的味道,但是,这里的 x 和 y 依然可以理解为任意坐标系;举个例子说,把 x 看成是角度,把 y 看做是半径,这时 tree.size([360, 960]) 的设定就意味着,半径的取值范围是 0-960,角度的取值范围是 0-360,所以,树布局计算出来的每个节点的 x 和 y 实际表示的是径向的树结构(平面中的点可以是:直角坐标系的 [x, y] 或 极坐标系的 { θ, r })。

# tree.links(nodes)

根据给定的结点数组 nodes(比如:通过 tree.nodes(root) 返回的一组节点集),生成一组表示从父节点到子节点关系对象,叶子节点不包含该种“输出”关系;每个关系对象有两个属性:

  • source - 父节点的引用;
  • target - 子节点的引用;

该方法的设定目的是,用于检索一组有连接关系的节点集,并输出这种连接关系;通常会配合如diagonal(对角线形状生成器器)一起使用;如下:

svg.selectAll("path")
    .data(tree.links(nodes))
  .enter().append("path")
    .attr("d", d3.svg.diagonal());

# tree.children([children])

如果指定了 children 参数,则设置子节点访问器函数为 children;如果未指定,则返回当前的子节点访问器函数;默认的子节点访问器假定输入数据是一个有 children 的 KEY 的对象,形式如下:

function children(d) {
  return d.children;
}

【略过】Often, it is convenient to load the node hierarchy using d3.json, and represent the input hierarchy as a nested JSON object. For example:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731}
     ]
    }
   ]
  }
 ]
}

访问器首先会在在层次结构的根节点被调用;如果访问器返回 null,则该节点会被认为是叶子节点,从而终止向下遍历;否则,访问器应返回一个包含所有子节点数据元素的数组。

# tree.separation([separation])

如果指定了 separation 参数,则设置相邻节点的间距计算器为 separation;如果未指定,则返回当前的间距计算器函数;默认的间距计算器函数形式如下:

function separation(a, b) {
  return a.parent == b.parent ? 1 : 2;
}

对于一些特殊的,如径向树图,差异化的间距值可以避免叶子节点间的锯齿感,因此,使用如下的间距计算器可以优化该问题:

function separation(a, b) {
  return (a.parent == b.parent ? 1 : 2) / a.depth;
}

间距计算器函数有两个入参:ab,该函数需要返回在这两个节点间的距离期望倍数ab 节点通常是相邻的兄弟;当然,也不排除树布局有意将两个表亲兄弟节点或更远的节点放置在“相邻”的位置。

注:上文提到的间距计算器函数的返回值被称做**倍数**,并不是来自原英文,而是译者结合测试、使用经验自译的;请参考原文。

# tree.size([size])

如果指定了 size 参数,则设置树布局可用的空间范围为指定的两元素数组 size;如果未指定,则返回当前的空间范围;默认是:[1, 1]size 的值可能被认为是:size[0] => x, size[1] => y;但是,这并不局限于平面直角坐标系,而适用于任意的坐标系,xy 只是一个标志位的作用;

举个例子说,把 x 看成是角度,把 y 看做是半径,这时 tree.size([360, 960]) 的设定就意味着,半径的取值范围是 0-960,角度的取值范围是 0-360,所以,树布局计算出来的每个节点的 x 和 y 实际表示的是径向的树结构(平面中的点可以是:直角坐标系的 [x, y] 或 极坐标系的 { θ, r })。

size 属性与 tree.nodeSize 不同时共存,设置了 size 就必须设置 nodeSize 为 null;

# tree.nodeSize([nodeSize])

如果指定了 nodeSize 参数,则为每个节点设置一个固定 size 的表示为 xy 的两元素数组;如果未指定,则返回当前的配置;默认值为 null,表示树布局使用整体配置的 tree.size 值来计算布局;同样,这里的所对应的 xy 也不局限于特定的坐标系。

nodeSize 属性与 tree.size 不同时共存,设置了 nodeSize 就必须设置 size 为 null;

# tree.sort([comparator])

如果指定了 comparator 参数,则启用排序算法并设置排序的比较器为 comparator 函数;如果未指定,则返回当前的比较器;默认的比较器为 null,表示不对原数据进行排序;和数组的原生 sort 函数一样,比较器也有类似的入参及返回值;一个降序排序的参考示例如下:

function comparator(a, b) {
  return b.value - a.value;
}

当然,还有更好的选择,参考:d3.ascendingd3.descending

# tree.value([value])

如果指定了 value 参数,则设置取值器为指定的 value 函数;如果未指定,则返回当前的取值器;默认值为 null;获取节点的 value 值当前并不会影响到树布局的计算中,只是层布局的一个通用 API 接口。


changelog

  • 【阿呆不呆】译于 2014-11-28
  • 大傻】校于 2014-12-07 10:20:53
  • 【二傻】校于 2016-07-27
    • 诸多解释性描述的校对;
    • 译文布局统一的校对;
    • 链接/锚点的校对;
    • 页头、页尾统一化;
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.