aboutsummaryrefslogtreecommitdiff
path: root/assets/js/monitor.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/monitor.js')
-rw-r--r--assets/js/monitor.js352
1 files changed, 352 insertions, 0 deletions
diff --git a/assets/js/monitor.js b/assets/js/monitor.js
new file mode 100644
index 0000000..a92f753
--- /dev/null
+++ b/assets/js/monitor.js
@@ -0,0 +1,352 @@
+var ajax_site = 'ajax';
+var refresh_rate = 3000;
+var send_timeout = 20000;
+var retry_rate = 3000;
+
+function Blocker(sleeper) {
+ this.counter = 0;
+ this.waiting = false;
+ this.sleeper = sleeper;
+}
+
+Blocker.prototype.setHook = function() {
+ var blocker = this;
+ return function() {
+ blocker.counter++;
+ }
+}
+Blocker.prototype.setNotifier = function(cb) {
+ var blocker = this;
+ return function() {
+ cb.apply(this, arguments);
+ if (--blocker.counter == 0 && blocker.waiting)
+ blocker.sleeper();
+ }
+};
+
+Blocker.prototype.go = function() {
+ if (this.counter == 0)
+ this.sleeper();
+ this.waiting = true;
+}
+
+function send_request(on_success) {
+ $.ajax({
+ url: ajax_site,
+ type: 'GET',
+ cache: false,
+ dataType: 'json',
+ async: true,
+ success: on_success,
+ timeout: send_timeout,
+ error: function(a, b, c) {
+ console.log("failed while connecting, reason: " + b);
+ setTimeout(function() {
+ send_request(on_success);
+ }, retry_rate);
+ }
+ });
+}
+
+function hex(x) {
+ return ("0" + parseInt(x).toString(16)).slice(-2);
+}
+
+function random_range(min, max) {
+ return Math.random() * (max - min) + min;
+}
+
+function random_color() {
+ var r = (random_range(0, 200) + 100) / 2;
+ var g = (random_range(0, 200) + 100) / 2;
+ var b = (random_range(0, 200) + 100) / 2;
+ return "#" + hex(r) + hex(g) + hex(b);
+}
+
+function LineGraph() {}
+
+LineGraph.prototype.recalc_y_domain = function(data) {
+ var min = d3.min(data, function(d) { return d.y; });
+ var max = d3.max(data, function(d) { return d.y; });
+ var delta = max - min;
+ this.y.domain([min - delta / 2.0, max + delta / 3.0]);
+}
+
+LineGraph.prototype.recalc_domain = function(data) {
+ this.x.domain(d3.extent(data, function(d) { return d.x; }));
+ this.recalc_y_domain(data);
+}
+
+LineGraph.prototype.parse_data = function(d) {
+ var data = [];
+ for (var i = 0; i < d.records.length; i++)
+ {
+ var rec = d.records[i];
+ data.push({x: i, y: +rec.rec[0], rid: rec.rid});
+ }
+ return data;
+}
+
+LineGraph.prototype.update = function(d, i, b) {
+ var graph = this;
+ var data = this.parse_data(d);
+ if (data.length == 0) return;
+ var pdata = this.pdata;
+ var svg = d3.select(this.elem).select("svg");
+ var path = svg.select(".line");
+
+ var shift = pdata.length ? data[0].rid - pdata[0].rid : 0;
+ var add = pdata.length ? data[data.length - 1].rid - pdata[pdata.length - 1].rid : 0;
+ if (pdata.length == 0 || pdata[pdata.length - 1].rid < data[0].rid ||
+ pdata[0] > data[data.length - 1].rid || shift < 0 || add < 0)
+ {
+ if (data.length == 1)
+ {
+ data = [];
+ console.log("clear");
+ }
+ this.recalc_domain(data);
+ path.transition()
+ .duration(200)
+ .style("opacity", 1e-6)
+ .transition()
+ .attr("d", graph.valueline(data))
+ .transition()
+ .duration(200)
+ .style("opacity", 1)
+ .each(b.setHook())
+ .each("end", b.setNotifier(function() {
+ graph.pdata = data;
+ console.log("refresh complete");
+ }));
+ console.log("refresh started");
+ }
+ else
+ {
+ this.recalc_domain(pdata);
+ //console.log("shift: " + shift + "add: " + add);
+ data = this.pdata.concat(data.slice(data.length - add, data.length));
+ for (var i = 0; i < data.length; i++)
+ data[i].x = i;
+ this.recalc_y_domain(data);
+ path.transition().duration(750)
+ .attr("d", graph.valueline(data))
+ .transition()
+ .duration(750)
+ .attr("transform", "translate(" + this.x(-shift) + ")")
+ .each(b.setHook())
+ .each("end", b.setNotifier(function() {
+ for (var i = 0; i < shift; i++)
+ data.shift();
+ for (var i = 0; i < data.length; i++)
+ data[i].x = i;
+ graph.pdata = data;
+ d3.select(this).attr("d", graph.valueline(data))
+ .attr("transform", "translate(" + graph.x(0) + ")");
+ }));
+ }
+ svg.transition()
+ .duration(750)
+ .select(".x.axis")
+ .call(this.xAxis);
+ svg.transition()
+ .duration(750)
+ .select(".y.axis")
+ .call(this.yAxis);
+}
+
+LineGraph.prototype.setup = function(elem, d, i, b) {
+ var graph = this;
+ var data = this.parse_data(d);
+ this.elem = elem;
+ var margin = {top: 10, right: 0, bottom: 50, left: 30};
+ // Adds the svg canvas
+ var svg = d3.select(this.elem)
+ .append("svg")
+ .attr("width", "100%")
+ .attr("height", "100%")
+ .append("g")
+ .attr("transform",
+ "translate(" + margin.left + "," + margin.top + ")");
+ var width = 500 - margin.left - margin.right;
+ var height = 250 - margin.top - margin.bottom;
+ console.log(width);
+ console.log(height);
+ // Set the ranges
+ this.x = d3.scale.linear().range([0, width]);
+ this.y = d3.scale.linear().range([height, 0]);
+ // Scale the range of the data
+ this.recalc_domain(data);
+ // Define the axes
+ this.xAxis = d3.svg.axis().scale(this.x)
+ .orient("bottom").ticks(5).tickFormat(d3.format("d"));
+
+ this.yAxis = d3.svg.axis().scale(this.y)
+ .orient("left").ticks(5);
+ // Define the line
+ this.valueline = d3.svg.line()
+ .x(function(d) { return this.x(d.x); })
+ .y(function(d) { return this.y(d.y); });
+ /*
+ svg.append("text")
+ .attr("x", (width / 2))
+ .attr("y", 0 - (margin.top / 2))
+ .attr("text-anchor", "middle")
+ .style("font-size", "16px")
+ .style("text-decoration", "none")
+ .text(d.name);
+ */
+ // Add the X Axis
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(this.xAxis);
+
+ // Add the Y Axis
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(this.yAxis);
+
+ svg.append("defs").append("clipPath")
+ .attr("id", "clip")
+ .append("rect")
+ .attr("width", width)
+ .attr("height", height);
+
+ d3.select(this.elem).transition()
+ .duration(750)
+ .style("height", height + margin.top + margin.bottom + "px")
+ .each(b.setHook())
+ .each("end", b.setNotifier(function() {
+ // Get the data
+ var path = svg.append("g")
+ .attr("clip-path", "url(#clip)")
+ .append("path");
+
+ path.attr("class", "line")
+ .style("stroke", random_color)
+ .attr("d", graph.valueline(data));
+ var totalLength = path.node().getTotalLength();
+ path.attr("stroke-dasharray", totalLength + " " + totalLength)
+ .attr("stroke-dashoffset", totalLength)
+ .transition()
+ .duration(2000)
+ .ease("linear")
+ .attr("stroke-dashoffset", 0)
+ .each(b.setHook())
+ .each("end", b.setNotifier(function() {
+ path.attr("stroke-dasharray", "");
+ }));
+ graph.pdata = data;
+ }));
+}
+
+function ListGraph() {}
+
+ListGraph.prototype.parse_data = function(d) {
+ var data = [];
+ for (var i = 0; i < d.records.length; i++)
+ {
+ var rec = d.records[i];
+ data.push({rid: rec[0], rec: rec});
+ }
+ return data;
+}
+
+ListGraph.prototype.setup = function(elem, d, i, b) {
+ var data = this.parse_data(d);
+ var div = d3.select(elem);
+ this.elem = elem;
+ /*
+ div.append("div")
+ .style("text-align", "center")
+ .append("a")
+ .style("font-size", "16px")
+ .style("text-decoration", "none")
+ .text(d.name);
+ */
+ var table = d3.select(elem)
+ .append("table")
+ .attr("class", "listgraph table")
+ .style("width", "100%")
+ .style("height", "100%");
+ this.table = table;
+ table.selectAll("tr").data(data)
+ .enter().append("tr")
+ .selectAll("td").data(function(d) { return d.rec; })
+ .enter().append("td")
+ .style("opacity", 0)
+ .transition().duration(750)
+ .style("opacity", 1)
+ .text(function(d) { return d; })
+ .each(b.setHook())
+ .each("end", b.setNotifier(function(){}));
+ d3.select(elem)
+ //.transition().duration(750)
+ .style("height", null);
+}
+
+ListGraph.prototype.update = function(d, i, b) {
+ var graph = this;
+ var data = this.parse_data(d);
+ var items = this.table.selectAll("tr").data(data, function(d) { return d.rid; });
+ b.setHook()();
+ var b0 = new Blocker(b.setNotifier(function() {
+ items.order();
+ }));
+
+ items.selectAll("td").text(function(d) { return d; });
+ items.enter()
+ .append("tr")
+ .selectAll("td")
+ .data(function(d) { return d.rec; })
+ .enter()
+ .append("td")
+ .text(function(d) { return d; });
+ items.exit().remove();
+ b0.go();
+}
+
+var graph_handler = {"linegraph": LineGraph, "listgraph": ListGraph};
+
+function update_jobs(resp, after) {
+ resp = Object.keys(resp).map(function(k) { return resp[k] });
+ var jobs = d3.select("#jobs").selectAll(".job_graph").data(resp, function(d) { return d.jid; });
+ var b = new Blocker(after);
+ jobs.each(function(d, i) {
+ d3.select(this).select(".job_content").node().handler.update(d, i, b);
+ });
+ var outer = jobs.enter()
+ .append("div")
+ .attr("class", "job_graph panel panel-info")
+ .style("width", "540px");
+ outer.append("div")
+ .attr("class", "panel-heading")
+ .text(function(d) { return d.name; });
+ outer.append("div")
+ .attr("class", "job_content panel-body")
+ .style("height", "0px")
+ .each(function(d, i) {
+ this.handler = new graph_handler[d.metadata.type]();
+ this.handler.setup(this, d, i, b);
+ });
+ console.log(jobs.exit());
+ jobs.exit()
+ .style("height", function(d) { return d3.select(this).style("height"); })
+ .transition().duration(750)
+ .style("height", "0px")
+ .each(b.setHook())
+ .each("end",b.setNotifier(function(){}))
+ .remove();
+ b.go();
+}
+
+function graph_tick() {
+ send_request(function(resp) {
+ update_jobs(resp, function() {
+ setTimeout(graph_tick, refresh_rate);
+ });
+ });
+}
+
+graph_tick();