美文网首页
d3 树状布局tree

d3 树状布局tree

作者: 瘦人假噜噜 | 来源:发表于2017-04-23 23:36 被阅读0次

树状布局Tree-Layout简介

显而易见,树状布局就是我们通常所理解的数据结构中的树,由一个根节点向外展开,与前面力导向图的数据结构模型其实是一致的,只是展示形式略有差别,用树状结构展示看起来更加简洁清晰一点。

API

树结构

  • d3.layout.tree()

    使用默认设置创建一个新的树状布局:

  • tree.nodes(root)

    根据传入数据计算树的布局返回一组节点数组

  • tree.links(nodes)

    根据节点数组返回节点之间的父子连接关系

  • tree.separation([separation]):

    设置或取得两个节点之间的间距

  • tree.size([size])

    指定树布局的尺寸一个

svg形状

因为需要实现一个辐射布局,并且连线是贝塞尔曲线,需要用到坐标投影来实现路径形状生成。
路径形状有很多种选择,比如d3.svg.line()、d3.svg.area()、d3.svg.diagonal()等等。这里选用d3.svg.diagonal(),它能利用projection的API来生成svg中的path形状的路径。

  • d3.svg.diagonal.radial().projection()

示例代码

根据官网一些人提供的Demo修改来写了一个辐射布局。里面做了一些注释,但仍然有一些疑惑点,比如d.x-90那里的原因还是比较模糊。

下面是完整demo代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>tree layout</title>
    <style>
        .node {
          cursor: pointer;
        }

        .node circle {
          fill: #fff;
          stroke: steelblue;
          stroke-width: 1.5px;
        }

        .node text {
          font: 10px sans-serif;
        }

        .link {
          fill: none;
          stroke: #ccc;
          stroke-width: 1.5px;
        }
  </style>
</head>
<body>
<script src="//cdn.bootcss.com/d3/3.2.2/d3.v3.min.js"></script>
<script>

    var width = 800,
        height = 800;

    var i = 0,
        duration = 6000,
        root;

    var tree = d3.layout.tree()
        .size([360, 320])  //360代表展开的最大角度也就是圆,后面的r值代表整个辐射布局的展开最大半径,并不是指某一层级的半径而是整个树,超过这个范围的就不显示了,后面85行d.y的才是某一层级的半径设置。
        .separation(function(a, b) {
            return (a.parent == b.parent ? 1 : 2) / a.depth;  //适应radial布局,可以简单的理解为深度越高,相邻子节点之间的距离越小。
        });

    var diagonal = d3.svg.diagonal.radial()
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; }); //d.y代表半径,(d.x/180)*PI就是各个节点的弧度表示。

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    d3.json("flare1.json", function(error, flare) {
      if (error) throw error;

      root = flare;
      root.x0 = height / 2;  //由于是辐射布局这边当y0设置为0,那么这个角度x0随便设置也无所谓 因为肯定是在圆心。这里的理解不知道对不对
      root.y0 = 0;

      function collapse(d) {
        if (d.children) {
          d._children = d.children;
          d._children.forEach(collapse);
          d.children = null;
        }
      }

      root.children.forEach(collapse);
      update(root);
    });

    // // Hack to make this example display correctly in an iframe on bl.ocks.org 为了在iframe中正常显示而已。
    d3.select(self.frameElement).style("height", "800px");

    function update(source) {

      // Compute the new tree layout.
      var nodes = tree.nodes(root),
          links = tree.links(nodes);

      // Normalize for fixed-depth. 根据深度来给定相应半径,也就是深度越大半径越长。
      nodes.forEach(function(d) { d.y = d.depth * 180; });

      // Update the nodes…
      var node = svg.selectAll("g.node")
          .data(nodes, function(d) { return d.id || (d.id = ++i); });

      // Enter any new nodes at the parent's previous position.
      var nodeEnter = node.enter().append("g")
          .attr("class", "node")
          // .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
          .on("click", click);

      nodeEnter.append("circle")
          .attr("r", 1e-6)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

      nodeEnter.append("text")
          // .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
          .attr("dy", ".35em")

      .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })//小于180度的文字放在前面,否则放在后面  
      .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
          // .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
          .text(function(d) { return d.name; })
          .style("fill-opacity", 1e-6);

      // Transition nodes to their new position.
      var nodeUpdate = node.transition()
          .duration(duration)
          .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
          //translate 与 rotate 的作用效果是怎么样的???
      nodeUpdate.select("circle")
          .attr("r", 4.5)
          .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

      nodeUpdate.select("text")
          .style("fill-opacity", 1);

      // Transition exiting nodes to the parent's new position.
      var nodeExit = node.exit().transition()
          .duration(duration)
          .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
          .remove();

      nodeExit.select("circle")
          .attr("r", 1e-6);

      nodeExit.select("text")
          .style("fill-opacity", 1e-6);

      // Update the links…
      var link = svg.selectAll("path.link")
          .data(links, function(d) { return d.target.id; });

      // Enter any new links at the parent's previous position.
      link.enter().insert("path", "g")
          .attr("class", "link")
          .attr("d", function(d) {
            var o = {x: source.x0, y: source.y0};
            return diagonal({source: o, target: o});
          });

      // Transition links to their new position.
      link.transition()
          .duration(duration)
          .attr("d", diagonal);

      // Transition exiting nodes to the parent's new position.
      link.exit().transition()
          .duration(duration)
          .attr("d", function(d) {
            var o = {x: source.x0, y: source.y0};
            return diagonal({source: o, target: o});
          })
          .remove();

      // Stash the old positions for transition.
      nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
      });
    }

    // Toggle children on click.
    function click(d) {
      if (d.children) {
        d._children = d.children;
        d.children = null;
      } else {
        d.children = d._children;
        d._children = null;
      }
      update(d);
    }

  </script>
</body>
</html>

json数据文件flare1.json如下

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "HierarchicalCluster", "size": 6714},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731},
      {"name": "MaxFlowMinCut", "size": 7840},
      {"name": "ShortestPaths", "size": 5914},
      {"name": "SpanningTree", "size": 3416}
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker", "size": 7074}
     ]
    }
   ]
  },
  {
   "name": "animate",
   "children": [
    {"name": "Easing", "size": 17010},
    {"name": "FunctionSequence", "size": 5842},
    {
     "name": "interpolate",
     "children": [
      {"name": "ArrayInterpolator", "size": 1983},
      {"name": "ColorInterpolator", "size": 2047},
      {"name": "DateInterpolator", "size": 1375},
      {"name": "Interpolator", "size": 8746},
      {"name": "MatrixInterpolator", "size": 2202},
      {"name": "NumberInterpolator", "size": 1382},
      {"name": "ObjectInterpolator", "size": 1629},
      {"name": "PointInterpolator", "size": 1675},
      {"name": "RectangleInterpolator", "size": 2042}
     ]
    },
    {"name": "ISchedulable", "size": 1041},
    {"name": "Parallel", "size": 5176},
    {"name": "Pause", "size": 449},
    {"name": "Scheduler", "size": 5593},
    {"name": "Sequence", "size": 5534},
    {"name": "Transition", "size": 9201},
    {"name": "Transitioner", "size": 19975},
    {"name": "TransitionEvent", "size": 1116},
    {"name": "Tween", "size": 6006}
   ]
  },
  {
   "name": "data",
   "children": [
    {
     "name": "converters",
     "children": [
      {"name": "Converters", "size": 721},
      {"name": "DelimitedTextConverter", "size": 4294},
      {"name": "GraphMLConverter", "size": 9800},
      {"name": "IDataConverter", "size": 1314},
      {"name": "JSONConverter", "size": 2220}
     ]
    },
    {"name": "DataField", "size": 1759},
    {"name": "DataSchema", "size": 2165},
    {"name": "DataSet", "size": 586},
    {"name": "DataSource", "size": 3331},
    {"name": "DataTable", "size": 772},
    {"name": "DataUtil", "size": 3322}
   ]
  }
 ]
}

参考资料

1.官方手册

2.Collapsible Tree

3.Radial Tree

相关文章

网友评论

      本文标题:d3 树状布局tree

      本文链接:https://www.haomeiwen.com/subject/kokuzttx.html