import Ember from 'ember'; import ChartUtilsMixin from 'yarn-ui/mixins/charts-utils'; export default Ember.Component.extend(ChartUtilsMixin, { queues: { data: undefined, foldedQueues: {}, selectedQueueCircle: undefined, maxDepth: -1, }, queueColors: d3.scale.category20().range(), renderQueue: function(now, depth, sequence) { if (depth > this.queues.maxDepth) { this.queues.maxDepth = depth; } var cx = 20 + depth * 30; var cy = 20 + sequence * 30; var name = now.get("name"); var g = this.queues.dataGroup.append("g") .attr("id", "queue-" + name + "-g"); var folded = this.queues.foldedQueues[name]; var isParentQueue = false; // render its children var children = []; var childrenNames = now.get("children"); if (childrenNames) { childrenNames.forEach(function(name) { isParentQueue = true; var child = this.queues.data[name]; if (child) { children.push(child); } }.bind(this)); } if (folded) { children = []; } var linefunction = d3.svg.line() .interpolate("basis") .x(function(d) { return d.x; }) .y(function(d) { return d.y; }); for (var i = 0; i < children.length; i++) { sequence = sequence + 1; // Get center of children queue var cc = this.renderQueue(children[i], depth + 1, sequence); g.append("path") .attr("class", "queue") .attr("d", linefunction([{ x: cx, y: cy }, { x: cc.x - 20, y: cc.y }, cc])); } var circle = g.append("circle") .attr("cx", cx) .attr("cy", cy) .attr("class", "queue"); circle.on('mouseover', function() { circle.style("fill", this.queueColors[1]); }.bind(this)); circle.on('mouseout', function() { if (circle != this.queues.selectedQueueCircle) { circle.style("fill", this.queueColors[0]); } }.bind(this)); circle.on('click', function() { circle.style("fill", this.queueColors[2]); var pre = this.queues.selectedQueueCircle; this.queues.selectedQueueCircle = circle; if (pre) { pre.on('mouseout')(); } this.renderCharts(name); }.bind(this)); circle.on('dblclick', function() { if (!isParentQueue) { return; } if (this.queues.foldedQueues[name]) { delete this.queues.foldedQueues[name]; } else { this.queues.foldedQueues[name] = now; } this.renderQueues(); }.bind(this)); var text = name; if (folded) { text = name + " (+)"; } // print queue's name g.append("text") .attr("x", cx + 30) .attr("y", cy + 5) .text(text) .attr("class", "queue"); return { x: cx, y: cy }; }, renderQueues: function() { if (this.queues.dataGroup) { this.queues.dataGroup.remove(); } // render queues this.queues.dataGroup = this.canvas.svg.append("g") .attr("id", "queues-g"); var rootQueue = undefined; if (this.queues.data) { this.renderQueue(this.queues.data['root'], 0, 0); } }, draw: function() { this.queues.data = {}; this.get("model") .forEach(function(o) { this.queues.data[o.id] = o; }.bind(this)); // get w/h of the svg var bbox = d3.select("#main-container") .node() .getBoundingClientRect(); this.canvas.w = bbox.width; this.canvas.h = Math.max(Object.keys(this.queues.data) .length * 35, 1500); this.canvas.svg = d3.select("#main-container") .append("svg") .attr("width", this.canvas.w) .attr("height", this.canvas.h) .attr("id", "main-svg"); this.renderBackground(); this.renderQueues(); this.renderCharts("root"); }, didInsertElement: function() { this.draw(); }, /* * data = [{label="xx", value=},{...}] */ renderTable: function(data, title, layout) { d3.select("#main-svg") .append('table') .selectAll('tr') .data(data) .enter() .append('tr') .selectAll('td') .data(function(d) { return d; }) .enter() .append('td') .text(function(d) { return d; }); }, renderQueueCapacities: function(queue, layout) { // Render bar chart this.renderBarChart(this.charts.g, [{ label: "Cap", value: queue.get("capacity") }, { label: "MaxCap", value: queue.get("maxCapacity") }, { label: "UsedCap", value: queue.get("usedCapacity") }], "Queue Capacities", layout, 60); }, renderChildrenCapacities: function(queue, layout) { var data = []; var children = queue.get("children"); if (children) { for (var i = 0; i < children.length; i++) { var child = this.queues.data[children[i]]; data.push({ label: child.get("name"), value: child.get("capacity") }); } } this.renderDonutChart(this.charts.g, data, "Children Capacities", layout, true); }, renderChildrenUsedCapacities: function(queue, layout) { var data = []; var children = queue.get("children"); if (children) { for (var i = 0; i < children.length; i++) { var child = this.queues.data[children[i]]; data.push({ label: child.get("name"), value: child.get("usedCapacity") }); } } this.renderDonutChart(this.charts.g, data, "Children Used Capacities", layout, true); }, renderLeafQueueUsedCapacities: function(layout) { var leafQueueUsedCaps = []; for (var queueName in this.queues.data) { var q = this.queues.data[queueName]; if ((!q.get("children")) || q.get("children") .length == 0) { // it's a leafqueue leafQueueUsedCaps.push({ label: q.get("name"), value: q.get("usedCapacity") }); } } this.renderDonutChart(this.charts.g, leafQueueUsedCaps, "LeafQueues Used Capacities", layout, true); }, renderCharts: function(queueName) { this.charts.leftBannerLen = this.queues.maxDepth * 30 + 100; this.initCharts(); var queue = this.queues.data[queueName]; var idx = 0; if (queue.get("name") == "root") { this.renderLeafQueueUsedCapacities(this.getLayout(idx++)); } if (queue.get("name") != "root") { this.renderQueueCapacities(queue, this.getLayout(idx++)); } if (queue.get("children") && queue.get("children") .length > 0) { this.renderChildrenCapacities(queue, this.getLayout(idx++)); this.renderChildrenUsedCapacities(queue, this.getLayout(idx++)); } }, });