queue-view.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import Ember from 'ember';
  2. import ChartUtilsMixin from 'yarn-ui/mixins/charts-utils';
  3. export default Ember.Component.extend(ChartUtilsMixin, {
  4. queues: {
  5. data: undefined,
  6. foldedQueues: {},
  7. selectedQueueCircle: undefined,
  8. maxDepth: -1,
  9. },
  10. queueColors: d3.scale.category20().range(),
  11. renderQueue: function(now, depth, sequence) {
  12. if (depth > this.queues.maxDepth) {
  13. this.queues.maxDepth = depth;
  14. }
  15. var cx = 20 + depth * 30;
  16. var cy = 20 + sequence * 30;
  17. var name = now.get("name");
  18. var g = this.queues.dataGroup.append("g")
  19. .attr("id", "queue-" + name + "-g");
  20. var folded = this.queues.foldedQueues[name];
  21. var isParentQueue = false;
  22. // render its children
  23. var children = [];
  24. var childrenNames = now.get("children");
  25. if (childrenNames) {
  26. childrenNames.forEach(function(name) {
  27. isParentQueue = true;
  28. var child = this.queues.data[name];
  29. if (child) {
  30. children.push(child);
  31. }
  32. }.bind(this));
  33. }
  34. if (folded) {
  35. children = [];
  36. }
  37. var linefunction = d3.svg.line()
  38. .interpolate("basis")
  39. .x(function(d) {
  40. return d.x;
  41. })
  42. .y(function(d) {
  43. return d.y;
  44. });
  45. for (var i = 0; i < children.length; i++) {
  46. sequence = sequence + 1;
  47. // Get center of children queue
  48. var cc = this.renderQueue(children[i],
  49. depth + 1, sequence);
  50. g.append("path")
  51. .attr("class", "queue")
  52. .attr("d", linefunction([{
  53. x: cx,
  54. y: cy
  55. }, {
  56. x: cc.x - 20,
  57. y: cc.y
  58. }, cc]));
  59. }
  60. var circle = g.append("circle")
  61. .attr("cx", cx)
  62. .attr("cy", cy)
  63. .attr("class", "queue");
  64. circle.on('mouseover', function() {
  65. circle.style("fill", this.queueColors[1]);
  66. }.bind(this));
  67. circle.on('mouseout', function() {
  68. if (circle != this.queues.selectedQueueCircle) {
  69. circle.style("fill", this.queueColors[0]);
  70. }
  71. }.bind(this));
  72. circle.on('click', function() {
  73. circle.style("fill", this.queueColors[2]);
  74. var pre = this.queues.selectedQueueCircle;
  75. this.queues.selectedQueueCircle = circle;
  76. if (pre) {
  77. pre.on('mouseout')();
  78. }
  79. this.renderCharts(name);
  80. }.bind(this));
  81. circle.on('dblclick', function() {
  82. if (!isParentQueue) {
  83. return;
  84. }
  85. if (this.queues.foldedQueues[name]) {
  86. delete this.queues.foldedQueues[name];
  87. } else {
  88. this.queues.foldedQueues[name] = now;
  89. }
  90. this.renderQueues();
  91. }.bind(this));
  92. var text = name;
  93. if (folded) {
  94. text = name + " (+)";
  95. }
  96. // print queue's name
  97. g.append("text")
  98. .attr("x", cx + 30)
  99. .attr("y", cy + 5)
  100. .text(text)
  101. .attr("class", "queue");
  102. return {
  103. x: cx,
  104. y: cy
  105. };
  106. },
  107. renderQueues: function() {
  108. if (this.queues.dataGroup) {
  109. this.queues.dataGroup.remove();
  110. }
  111. // render queues
  112. this.queues.dataGroup = this.canvas.svg.append("g")
  113. .attr("id", "queues-g");
  114. var rootQueue = undefined;
  115. if (this.queues.data) {
  116. this.renderQueue(this.queues.data['root'], 0, 0);
  117. }
  118. },
  119. draw: function() {
  120. this.queues.data = {};
  121. this.get("model")
  122. .forEach(function(o) {
  123. this.queues.data[o.id] = o;
  124. }.bind(this));
  125. // get w/h of the svg
  126. var bbox = d3.select("#main-container")
  127. .node()
  128. .getBoundingClientRect();
  129. this.canvas.w = bbox.width;
  130. this.canvas.h = Math.max(Object.keys(this.queues.data)
  131. .length * 35, 1500);
  132. this.canvas.svg = d3.select("#main-container")
  133. .append("svg")
  134. .attr("width", this.canvas.w)
  135. .attr("height", this.canvas.h)
  136. .attr("id", "main-svg");
  137. this.renderBackground();
  138. this.renderQueues();
  139. this.renderCharts("root");
  140. },
  141. didInsertElement: function() {
  142. this.draw();
  143. },
  144. /*
  145. * data = [{label="xx", value=},{...}]
  146. */
  147. renderTable: function(data, title, layout) {
  148. d3.select("#main-svg")
  149. .append('table')
  150. .selectAll('tr')
  151. .data(data)
  152. .enter()
  153. .append('tr')
  154. .selectAll('td')
  155. .data(function(d) {
  156. return d;
  157. })
  158. .enter()
  159. .append('td')
  160. .text(function(d) {
  161. return d;
  162. });
  163. },
  164. renderQueueCapacities: function(queue, layout) {
  165. // Render bar chart
  166. this.renderBarChart(this.charts.g, [{
  167. label: "Cap",
  168. value: queue.get("capacity")
  169. }, {
  170. label: "MaxCap",
  171. value: queue.get("maxCapacity")
  172. }, {
  173. label: "UsedCap",
  174. value: queue.get("usedCapacity")
  175. }], "Queue Capacities", layout, 60);
  176. },
  177. renderChildrenCapacities: function(queue, layout) {
  178. var data = [];
  179. var children = queue.get("children");
  180. if (children) {
  181. for (var i = 0; i < children.length; i++) {
  182. var child = this.queues.data[children[i]];
  183. data.push({
  184. label: child.get("name"),
  185. value: child.get("capacity")
  186. });
  187. }
  188. }
  189. this.renderDonutChart(this.charts.g, data, "Children Capacities", layout, true);
  190. },
  191. renderChildrenUsedCapacities: function(queue, layout) {
  192. var data = [];
  193. var children = queue.get("children");
  194. if (children) {
  195. for (var i = 0; i < children.length; i++) {
  196. var child = this.queues.data[children[i]];
  197. data.push({
  198. label: child.get("name"),
  199. value: child.get("usedCapacity")
  200. });
  201. }
  202. }
  203. this.renderDonutChart(this.charts.g, data, "Children Used Capacities", layout, true);
  204. },
  205. renderLeafQueueUsedCapacities: function(layout) {
  206. var leafQueueUsedCaps = [];
  207. for (var queueName in this.queues.data) {
  208. var q = this.queues.data[queueName];
  209. if ((!q.get("children")) || q.get("children")
  210. .length == 0) {
  211. // it's a leafqueue
  212. leafQueueUsedCaps.push({
  213. label: q.get("name"),
  214. value: q.get("usedCapacity")
  215. });
  216. }
  217. }
  218. this.renderDonutChart(this.charts.g, leafQueueUsedCaps, "LeafQueues Used Capacities",
  219. layout, true);
  220. },
  221. renderCharts: function(queueName) {
  222. this.charts.leftBannerLen = this.queues.maxDepth * 30 + 100;
  223. this.initCharts();
  224. var queue = this.queues.data[queueName];
  225. var idx = 0;
  226. if (queue.get("name") == "root") {
  227. this.renderLeafQueueUsedCapacities(this.getLayout(idx++));
  228. }
  229. if (queue.get("name") != "root") {
  230. this.renderQueueCapacities(queue, this.getLayout(idx++));
  231. }
  232. if (queue.get("children") && queue.get("children")
  233. .length > 0) {
  234. this.renderChildrenCapacities(queue, this.getLayout(idx++));
  235. this.renderChildrenUsedCapacities(queue, this.getLayout(idx++));
  236. }
  237. },
  238. });