tree.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. Shiny.addCustomMessageHandler("tree_values", function(message) {
  2. var dataset = message;
  3. console.log(dataset);
  4. // Set the dimensions and margins of the diagram
  5. var margin = {top: 20, right: 90, bottom: 30, left: 90},
  6. width = 1080 - margin.left - margin.right,
  7. height = 500 - margin.top - margin.bottom;
  8. // append the svg object to the body of the page
  9. // appends a 'group' element to 'svg'
  10. // moves the 'group' element to the top left margin
  11. var svg = d3.select("#tree_area").append("svg")
  12. .attr("width", width + margin.right + margin.left)
  13. .attr("height", height + margin.top + margin.bottom)
  14. .append("g")
  15. .attr("transform", "translate("
  16. + margin.left + "," + margin.top + ")");
  17. var i = 0,
  18. duration = 750,
  19. root;
  20. // declares a tree layout and assigns the size
  21. var treemap = d3.tree().size([height, width]);
  22. // Assigns parent, children, height, depth
  23. root = d3.hierarchy(dataset, function(d) { return d.children; });
  24. root.x0 = height / 2;
  25. root.y0 = 0;
  26. // Collapse after the second level
  27. root.children.forEach(collapse);
  28. update(root);
  29. // Collapse the node and all it's children
  30. function collapse(d) {
  31. if(d.children) {
  32. d._children = d.children;
  33. d._children.forEach(collapse);
  34. d.children = null;
  35. }
  36. }
  37. function update(source) {
  38. // Assigns the x and y position for the nodes
  39. var dataset = treemap(root);
  40. // Compute the new tree layout.
  41. var nodes = dataset.descendants(),
  42. links = dataset.descendants().slice(1);
  43. // Normalize for fixed-depth.
  44. nodes.forEach(function(d){ d.y = d.depth * 180;});
  45. // ****************** Nodes section ***************************
  46. // Update the nodes...
  47. var node = svg.selectAll('g.node')
  48. .data(nodes, function(d) {return d.id || (d.id = ++i); });
  49. // Enter any new modes at the parent's previous position.
  50. var nodeEnter = node.enter().append('g')
  51. .attr('class', 'node')
  52. .attr("transform", function(d) {
  53. return "translate(" + source.y0 + "," + source.x0 + ")";
  54. })
  55. .on('click', click);
  56. // Add Circle for the nodes
  57. nodeEnter.append('circle')
  58. .attr('class', 'node')
  59. .attr('r', 1e-6)
  60. .style("fill", function(d) {
  61. return d._children ? "lightsteelblue" : "#fff";
  62. });
  63. // Add labels for the nodes
  64. nodeEnter.append('text')
  65. .attr("dy", ".35em")
  66. .attr("x", function(d) {
  67. return d.children || d._children ? -13 : 13;
  68. })
  69. .attr("text-anchor", function(d) {
  70. return d.children || d._children ? "end" : "start";
  71. })
  72. .text(function(d) { return d.data.name; });
  73. // UPDATE
  74. var nodeUpdate = nodeEnter.merge(node);
  75. // Transition to the proper position for the node
  76. nodeUpdate.transition()
  77. .duration(duration)
  78. .attr("transform", function(d) {
  79. return "translate(" + d.y + "," + d.x + ")";
  80. });
  81. // Update the node attributes and style
  82. nodeUpdate.select('circle.node')
  83. .attr('r', 10)
  84. .style("fill", function(d) {
  85. return d._children ? "lightsteelblue" : "#fff";
  86. })
  87. .attr('cursor', 'pointer');
  88. // Remove any exiting nodes
  89. var nodeExit = node.exit().transition()
  90. .duration(duration)
  91. .attr("transform", function(d) {
  92. return "translate(" + source.y + "," + source.x + ")";
  93. })
  94. .remove();
  95. // On exit reduce the node circles size to 0
  96. nodeExit.select('circle')
  97. .attr('r', 1e-6);
  98. // On exit reduce the opacity of text labels
  99. nodeExit.select('text')
  100. .style('fill-opacity', 1e-6);
  101. // ****************** links section ***************************
  102. // Update the links...
  103. var link = svg.selectAll('path.link')
  104. .data(links, function(d) { return d.id; });
  105. // Enter any new links at the parent's previous position.
  106. var linkEnter = link.enter().insert('path', "g")
  107. .attr("class", "link")
  108. .attr('d', function(d){
  109. var o = {x: source.x0, y: source.y0};
  110. return diagonal(o, o);
  111. });
  112. // UPDATE
  113. var linkUpdate = linkEnter.merge(link);
  114. // Transition back to the parent element position
  115. linkUpdate.transition()
  116. .duration(duration)
  117. .attr('d', function(d){ return diagonal(d, d.parent); });
  118. // Remove any exiting links
  119. var linkExit = link.exit().transition()
  120. .duration(duration)
  121. .attr('d', function(d) {
  122. var o = {x: source.x, y: source.y};
  123. return diagonal(o, o);
  124. })
  125. .remove();
  126. // Store the old positions for transition.
  127. nodes.forEach(function(d){
  128. d.x0 = d.x;
  129. d.y0 = d.y;
  130. });
  131. // Creates a curved (diagonal) path from parent to the child nodes
  132. function diagonal(s, d) {
  133. path = `M ${s.y} ${s.x}
  134. C ${(s.y + d.y) / 2} ${s.x},
  135. ${(s.y + d.y) / 2} ${d.x},
  136. ${d.y} ${d.x}`;
  137. return path;
  138. }
  139. // Toggle children on click.
  140. function click(d) {
  141. if (d.children) {
  142. d._children = d.children;
  143. d.children = null;
  144. } else {
  145. d.children = d._children;
  146. d._children = null;
  147. }
  148. update(d);
  149. }
  150. }
  151. });