d5.html 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>画一个树图(Tree)</title>
  6. </head>
  7. <style>
  8. .node circle {
  9. stroke: steelblue;
  10. stroke-width: 1px;
  11. cursor:pointer;
  12. }
  13. .node {
  14. font: 12px sans-serif;
  15. display:block;
  16. }
  17. .hidenode {
  18. font: 12px sans-serif;
  19. display:none;
  20. }
  21. .link {
  22. fill: none;
  23. stroke: #ccc;
  24. stroke-width: 1px;
  25. }
  26. </style>
  27. <body>
  28. <script src="http://d3js.org/d3.v3.min.js"></script>
  29. <script type="text/javascript">
  30. //图像区域大小
  31. var R = 600;
  32. //动画持续时间
  33. var duration=1000;
  34. //节点编号
  35. var index=0;
  36. //定义一个Tree对象,定义旋转角度和最大半径
  37. var tree = d3.layout.tree()
  38. .size([360,R/2-120])
  39. .separation(function(a,b) { return (a.parent == b.parent ? 1 : 2)/a.depth;});
  40. //定义布局方向
  41. var diagonal = d3.svg.diagonal()
  42. .projection(function(d) {
  43. var r = d.y, a = (d.x-90) / 180 * Math.PI;
  44. return [r * Math.cos(a), r * Math.sin(a)];
  45. });
  46. //新建画布,移动到圆心位置
  47. var svg = d3.select("body").append("svg")
  48. .attr("width", R)
  49. .attr("height", R)
  50. .append("g")
  51. .attr("transform", function(d){ return "translate("+R/2+"," + R/2 + ")";});
  52. //根据JSON数据生成树
  53. d3.json("d5.json", function(error, data) {
  54. var root=data;
  55. //根据数据生成nodes集合
  56. var nodes = tree.nodes(data);
  57. //记录现在的位置
  58. nodes.forEach(function(d){
  59. d.x0 = d.x;
  60. d.y0 = d.y;
  61. });
  62. //获取node集合的关系集合
  63. var links = tree.links(nodes);
  64. //根据node集合生成节点,添加id是为了区分是否冗余的节点
  65. var node = svg.selectAll(".node")
  66. .data(nodes,function(d){return d.id|| (d.id = ++index);});
  67. //为关系集合设置贝塞尔曲线连接
  68. var link=svg.selectAll(".link")
  69. .data(links, function(d) { return d.target.id;})
  70. .enter()
  71. .append("path")
  72. .attr("class", "link")
  73. .attr("d",diagonal);
  74. node.enter()
  75. .append("g")
  76. .attr("class", "node")
  77. .attr("transform",function(d){return "rotate(" + (d.x-90) + ")translate(" + d.y + ")"; })
  78. .on("click",nodeClick);
  79. //为节点添加圆形标记,如果有子节点为红色,否则绿色
  80. node.append("circle")
  81. .attr("fill",function(d){return d.children==null?"#0F0":"#F00";})
  82. .attr("r", 5);
  83. //为节点添加说明文字
  84. node.append("text")
  85. .attr("dy", ".4em")
  86. .text(function(d){return d.level;})
  87. .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
  88. .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; });
  89. //点击的话,隐藏或者显示子节点
  90. function nodeClick(d)
  91. {
  92. if (d.children)
  93. {
  94. d._children = d.children;
  95. d.children = null;
  96. }
  97. else
  98. {
  99. d.children = d._children;
  100. d._children = null;
  101. }
  102. update(d);
  103. }
  104. //更新显示
  105. function update(source)
  106. {
  107. //取得现有的节点数据,因为设置了Children属性,没有Children的节点将被删除
  108. var nodes = tree.nodes(root).reverse();
  109. var links = tree.links(nodes);
  110. //为节点更新数据
  111. var node = svg.selectAll("g.node")
  112. .data(nodes,function(d){return d.id|| (d.id = ++index);});
  113. //为链接更新数据
  114. var link = svg.selectAll("path.link").data(links, function(d) {return d.target.id;});
  115. //更新链接
  116. link.enter()
  117. .append("path")
  118. .attr("class", "link")
  119. .attr("d", function(d) {
  120. var o = {x: source.x, y: source.y};
  121. return diagonal({source: o, target: o});
  122. });
  123. link.transition()
  124. .duration(duration)
  125. .attr("d",diagonal);
  126. //移除无用的链接
  127. link.exit()
  128. .transition()
  129. .duration(duration)
  130. .attr("d", function(d) {
  131. var o = {x: source.x, y: source.y};
  132. return diagonal({source: o, target: o});
  133. })
  134. .remove();
  135. //更新节点集合
  136. var nodeEnter = node.enter()
  137. .append("g")
  138. .attr("class", "node")
  139. .attr("transform",function(d){return "rotate(" + (source.x0-90) + ")translate(" + source.y0 + ")"; })
  140. .on("click",nodeClick);
  141. //为节点添加圆形标记,如果有子节点为红色,否则绿色
  142. node.append("circle")
  143. .attr("fill",function(d){return d.children==null && d._children==null?"#0F0":"#F00";})
  144. .attr("r", 5);
  145. //为节点添加说明文字
  146. node.append("text")
  147. .attr("dy", ".4em")
  148. .text(function(d){return d.level;})
  149. .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
  150. .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; });
  151. //节点动画
  152. var nodeUpdate = node.transition()
  153. .duration(duration)
  154. .attr("transform", function(d) { return "rotate(" + (d.x-90) + ")translate(" + d.y + ")"; });
  155. //将无用的子节点删除
  156. var nodeExit =node.exit()
  157. .transition()
  158. .duration(duration)
  159. .attr("transform", function(d){return "rotate(" + (source.x-90) + ")translate(" + source.y + ")"; })
  160. .remove();
  161. //记录下当前位置,为下次动画记录初始值
  162. nodes.forEach(function(d) {
  163. d.x0 = d.x;
  164. d.y0 = d.y;
  165. });
  166. }
  167. });
  168. </script>
  169. </body>
  170. </html>