tree-selector.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. import Ember from 'ember';
  19. export default Ember.Component.extend({
  20. // Map: <queue-name, queue>
  21. map : undefined,
  22. // Normalized data for d3
  23. treeData: undefined,
  24. // folded queues, folded[<queue-name>] == true means <queue-name> is folded
  25. foldedQueues: { },
  26. // maxDepth
  27. maxDepth: 0,
  28. // num of leaf queue, folded queue is treated as leaf queue
  29. numOfLeafQueue: 0,
  30. // mainSvg
  31. mainSvg: undefined,
  32. // Init data
  33. initData: function() {
  34. this.map = { };
  35. this.treeData = { };
  36. this.maxDepth = 0;
  37. this.numOfLeafQueue = 0;
  38. this.get("model")
  39. .forEach(function(o) {
  40. this.map[o.id] = o;
  41. }.bind(this));
  42. var selected = this.get("selected");
  43. this.initQueue("root", 1, this.treeData);
  44. },
  45. // get Children array of given queue
  46. getChildrenNamesArray: function(q) {
  47. var namesArr = [];
  48. // Folded queue's children is empty
  49. if (this.foldedQueues[q.get("name")]) {
  50. return namesArr;
  51. }
  52. var names = q.get("children");
  53. if (names) {
  54. names.forEach(function(name) {
  55. namesArr.push(name);
  56. });
  57. }
  58. return namesArr;
  59. },
  60. // Init queues
  61. initQueue: function(queueName, depth, node) {
  62. if ((!queueName) || (!this.map[queueName])) {
  63. // Queue is not existed
  64. return;
  65. }
  66. if (depth > this.maxDepth) {
  67. this.maxDepth = this.maxDepth + 1;
  68. }
  69. var queue = this.map[queueName];
  70. var names = this.getChildrenNamesArray(queue);
  71. node.name = queueName;
  72. node.parent = queue.get("parent");
  73. node.queueData = queue;
  74. if (names.length > 0) {
  75. node.children = [];
  76. names.forEach(function(name) {
  77. var childQueueData = {};
  78. node.children.push(childQueueData);
  79. this.initQueue(name, depth + 1, childQueueData);
  80. }.bind(this));
  81. } else {
  82. this.numOfLeafQueue = this.numOfLeafQueue + 1;
  83. }
  84. },
  85. update: function(source, root, tree, diagonal) {
  86. var duration = 300;
  87. var i = 0;
  88. // Compute the new tree layout.
  89. var nodes = tree.nodes(root).reverse();
  90. var links = tree.links(nodes);
  91. // Normalize for fixed-depth.
  92. nodes.forEach(function(d) { d.y = d.depth * 200; });
  93. // Update the nodes…
  94. var node = this.mainSvg.selectAll("g.node")
  95. .data(nodes, function(d) { return d.id || (d.id = ++i); });
  96. // Enter any new nodes at the parent's previous position.
  97. var nodeEnter = node.enter().append("g")
  98. .attr("class", "node")
  99. .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
  100. .on("click", function(d,i){
  101. if (d.queueData.get("name") != this.get("selected")) {
  102. document.location.href = "yarnQueue/" + d.queueData.get("name");
  103. }
  104. }.bind(this));
  105. // .on("click", click);
  106. nodeEnter.append("circle")
  107. .attr("r", 1e-6)
  108. .style("fill", function(d) {
  109. var usedCap = d.queueData.get("usedCapacity");
  110. if (usedCap <= 60.0) {
  111. return "LimeGreen";
  112. } else if (usedCap <= 100.0) {
  113. return "DarkOrange";
  114. } else {
  115. return "LightCoral";
  116. }
  117. });
  118. // append percentage
  119. nodeEnter.append("text")
  120. .attr("x", function(d) { return 0; })
  121. .attr("dy", ".35em")
  122. .attr("text-anchor", function(d) { return "middle"; })
  123. .text(function(d) {
  124. var usedCap = d.queueData.get("usedCapacity");
  125. if (usedCap >= 100.0) {
  126. return usedCap.toFixed(0) + "%";
  127. } else {
  128. return usedCap.toFixed(1) + "%";
  129. }
  130. })
  131. .style("fill-opacity", 1e-6);
  132. // append queue name
  133. nodeEnter.append("text")
  134. .attr("x", function(d) { return 40; })
  135. .attr("dy", ".35em")
  136. .attr("text-anchor", function(d) { return "start"; })
  137. .text(function(d) { return d.name; })
  138. .style("fill-opacity", 1e-6);
  139. // Transition nodes to their new position.
  140. var nodeUpdate = node.transition()
  141. .duration(duration)
  142. .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
  143. nodeUpdate.select("circle")
  144. .attr("r", 20)
  145. .attr("href",
  146. function(d) {
  147. return "yarnQueues/" + d.queueData.get("name");
  148. })
  149. .style("stroke", function(d) {
  150. if (d.queueData.get("name") == this.get("selected")) {
  151. return "red";
  152. } else {
  153. return "gray";
  154. }
  155. }.bind(this));
  156. nodeUpdate.selectAll("text")
  157. .style("fill-opacity", 1);
  158. // Transition exiting nodes to the parent's new position.
  159. var nodeExit = node.exit().transition()
  160. .duration(duration)
  161. .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
  162. .remove();
  163. nodeExit.select("circle")
  164. .attr("r", 1e-6);
  165. nodeExit.select("text")
  166. .style("fill-opacity", 1e-6);
  167. // Update the links…
  168. var link = this.mainSvg.selectAll("path.link")
  169. .data(links, function(d) { return d.target.id; });
  170. // Enter any new links at the parent's previous position.
  171. link.enter().insert("path", "g")
  172. .attr("class", "link")
  173. .attr("d", function(d) {
  174. var o = {x: source.x0, y: source.y0};
  175. return diagonal({source: o, target: o});
  176. });
  177. // Transition links to their new position.
  178. link.transition()
  179. .duration(duration)
  180. .attr("d", diagonal);
  181. // Transition exiting nodes to the parent's new position.
  182. link.exit().transition()
  183. .duration(duration)
  184. .attr("d", function(d) {
  185. var o = {x: source.x, y: source.y};
  186. return diagonal({source: o, target: o});
  187. })
  188. .remove();
  189. // Stash the old positions for transition.
  190. nodes.forEach(function(d) {
  191. d.x0 = d.x;
  192. d.y0 = d.y;
  193. });
  194. },
  195. reDraw: function() {
  196. this.initData();
  197. var margin = {top: 20, right: 120, bottom: 20, left: 120};
  198. var treeWidth = this.maxDepth * 200;
  199. var treeHeight = this.numOfLeafQueue * 80;
  200. var width = treeWidth + margin.left + margin.right;
  201. var height = treeHeight + margin.top + margin.bottom;
  202. var layout = { };
  203. if (this.mainSvg) {
  204. this.mainSvg.remove();
  205. }
  206. this.mainSvg = d3.select("#" + this.get("parentId")).append("svg")
  207. .attr("width", width)
  208. .attr("height", height)
  209. .attr("class", "tree-selector")
  210. .append("g")
  211. .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  212. var tree = d3.layout.tree().size([treeHeight, treeWidth]);
  213. var diagonal = d3.svg.diagonal()
  214. .projection(function(d) { return [d.y, d.x]; });
  215. var root = this.treeData;
  216. root.x0 = height / 2;
  217. root.y0 = 0;
  218. d3.select(self.frameElement).style("height", height);
  219. this.update(root, root, tree, diagonal);
  220. },
  221. didInsertElement: function() {
  222. this.reDraw();
  223. }
  224. });