hadoop/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/app/components/timeline-view.js

250 lines
6.4 KiB
JavaScript

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]);
}
},
});