import Ember from 'ember'; import Converter from 'yarn-ui/utils/converter'; export default Ember.Component.extend({ canvas: { svg: undefined, h: 0, w: 0, tooltip: undefined }, clusterMetrics: undefined, modelArr: [], colors: d3.scale.category10().range(), _selected: undefined, selected: function() { return this._selected; }.property(), tableComponentName: function() { return "app-attempt-table"; }.property(), setSelected: function(d) { if (this._selected == d) { return; } // restore color if (this._selected) { var dom = d3.select("#timeline-bar-" + this._selected.get("id")); dom.attr("fill", this.colors[0]); } this._selected = d; this.set("selected", d); dom = d3.select("#timeline-bar-" + d.get("id")); dom.attr("fill", this.colors[1]); }, getPerItemHeight: function() { var arrSize = this.modelArr.length; if (arrSize < 20) { return 30; } else if (arrSize < 100) { return 10; } else { return 2; } }, getPerItemGap: function() { var arrSize = this.modelArr.length; if (arrSize < 20) { return 5; } else if (arrSize < 100) { return 1; } else { return 1; } }, getCanvasHeight: function() { return (this.getPerItemHeight() + this.getPerItemGap()) * this.modelArr.length + 200; }, draw: function(start, end) { // get w/h of the svg var bbox = d3.select("#" + this.get("parent-id")) .node() .getBoundingClientRect(); this.canvas.w = bbox.width; this.canvas.h = this.getCanvasHeight(); this.canvas.svg = d3.select("#" + this.get("parent-id")) .append("svg") .attr("width", this.canvas.w) .attr("height", this.canvas.h) .attr("id", this.get("my-id")); this.renderTimeline(start, end); }, renderTimeline: function(start, end) { var border = 30; var singleBarHeight = this.getPerItemHeight(); var gap = this.getPerItemGap(); var textWidth = 50; /* start-time end-time |--------------------------------------| ============== ============== ============== =============== */ var xScaler = d3.scale.linear() .domain([start, end]) .range([0, this.canvas.w - 2 * border - textWidth]); /* * Render frame of timeline view */ this.canvas.svg.append("line") .attr("x1", border + textWidth) .attr("y1", border - 5) .attr("x2", this.canvas.w - border) .attr("y2", border - 5) .attr("class", "chart"); this.canvas.svg.append("line") .attr("x1", border + textWidth) .attr("y1", border - 10) .attr("x2", border + textWidth) .attr("y2", border - 5) .attr("class", "chart"); this.canvas.svg.append("line") .attr("x1", this.canvas.w - border) .attr("y1", border - 10) .attr("x2", this.canvas.w - border) .attr("y2", border - 5) .attr("class", "chart"); this.canvas.svg.append("text") .text(Converter.timeStampToDate(start)) .attr("y", border - 15) .attr("x", border + textWidth) .attr("class", "bar-chart-text") .attr("text-anchor", "left"); this.canvas.svg.append("text") .text(Converter.timeStampToDate(end)) .attr("y", border - 15) .attr("x", this.canvas.w - border) .attr("class", "bar-chart-text") .attr("text-anchor", "end"); // show bar var bar = this.canvas.svg.selectAll("bars") .data(this.modelArr) .enter() .append("rect") .attr("y", function(d, i) { return border + (gap + singleBarHeight) * i; }) .attr("x", function(d, i) { return border + textWidth + xScaler(d.get("startTs")); }) .attr("height", singleBarHeight) .attr("fill", function(d, i) { return this.colors[0]; }.bind(this)) .attr("width", function(d, i) { var finishedTs = xScaler(d.get("finishedTs")); finishedTs = finishedTs > 0 ? finishedTs : xScaler(end); return finishedTs - xScaler(d.get("startTs")); }) .attr("id", function(d, i) { return "timeline-bar-" + d.get("id"); }); bar.on("click", function(d) { this.setSelected(d); }.bind(this)); this.bindTooltip(bar); if (this.modelArr.length <= 20) { // show bar texts for (var i = 0; i < this.modelArr.length; i++) { this.canvas.svg.append("text") .text(this.modelArr[i].get(this.get("label"))) .attr("y", border + (gap + singleBarHeight) * i + singleBarHeight / 2) .attr("x", border) .attr("class", "bar-chart-text"); } } }, bindTooltip: function(d) { d.on("mouseover", function(d) { this.tooltip .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }.bind(this)) .on("mousemove", function(d) { this.tooltip.style("opacity", .9); this.tooltip.html(d.get("tooltipLabel")) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }.bind(this)) .on("mouseout", function(d) { this.tooltip.style("opacity", 0); }.bind(this)); }, initTooltip: function() { this.tooltip = d3.select("body") .append("div") .attr("class", "tooltip") .attr("id", "chart-tooltip") .style("opacity", 0); }, didInsertElement: function() { // init tooltip this.initTooltip(); // init model if (this.get("rmModel")) { this.get("rmModel").forEach(function(o) { this.modelArr.push(o); }.bind(this)); } if (this.get("tsModel")) { this.get("tsModel").forEach(function(o) { this.modelArr.push(o); }.bind(this)); } this.modelArr.sort(function(a, b) { var tsA = a.get("startTs"); var tsB = b.get("startTs"); return tsA - tsB; }); if (this.modelArr.length > 0) { var begin = this.modelArr[0].get("startTs"); } var end = 0; for (var i = 0; i < this.modelArr.length; i++) { var ts = this.modelArr[i].get("finishedTs"); if (ts > end) { end = ts; } } if (end < begin) { end = Date.now(); } this.draw(begin, end); if (this.modelArr.length > 0) { this.setSelected(this.modelArr[0]); } }, });