blob: 94304c73a786c1bcf1a60164aadce42accca5f27 [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Intent Performance View Module
*/
(function () {
'use strict';
// injected refs
var $log, tbs, ts, wss, sus, flash, fs, mast;
// internal state
var handlerMap,
openListener,
theSample = [],
graph;
// ==========================
function createGraph(h, samples) {
var stopped = false,
n = 243,
duration = 750,
now = new Date(Date.now() - duration),
headers = h,
data = [];
var dim = fs.windowSize(mast.mastHeight());
var margin, width, height, x, y;
var svg, axis;
var lines = [],
paths = [];
var transition = d3.select({}).transition()
.duration(duration)
.ease("linear");
svg = d3.select("#intent-perf-chart").append("p").append("svg")
.attr("id", "intent-perf-svg")
.append("g")
.attr("id", "intent-perf-svg-g");
svg.append("defs").append("clipPath")
.attr("id", "intent-perf-clip")
.append("rect");
axis = svg.append("g")
.attr("class", "x axis")
.attr("id", "intent-perf-x");
svg.append("g").attr("class", "y axis")
.attr("id", "intent-perf-yl");
svg.append("g")
.attr("class", "y axis")
.attr("id", "intent-perf-yr");
resize(dim);
headers.forEach(function (h, li) {
// Prime the data to match the headers and zero it out.
data[li] = d3.range(n).map(function() { return 0 });
if (li < headers.length - 1) {
samples.forEach(function (s, i) {
var di = dataIndex(s.time);
if (di >= 0) {
data[li][di] = s.data[li];
}
});
data[li].forEach(function (d, i) {
if (!d && i > 0) {
data[li][i] = data[li][i - 1];
}
});
} else {
data[li].forEach(function (t, i) {
for (var si = 0; si < headers.length - 1; si++) {
data[li][i] = data[si][i];
}
});
}
// Create the lines
lines[li] = d3.svg.line()
.interpolate("basis")
.x(function(d, i) { return x(now - (n - 1 - i) * duration); })
.y(function(d, i) { return y(d); });
// Create the SVG paths
paths[li] = svg.append("g")
.attr("clip-path", "url(#intent-perf-clip)")
.append("path")
.datum(function () { return data[li]; })
.attr("id", "line" + li);
if (li < headers.length - 1) {
paths[li].attr("class", "line").style("stroke", lineColor(li));
} else {
paths[li].attr("class", "lineTotal");
}
});
function dataIndex(time) {
var delta = now.getTime() - time;
var di = Math.round(n - 2 - (delta / duration));
// $log.info('now=' + now.getTime() + '; then=' + time + '; delta=' + delta + '; di=' + di + ';');
return di >= n || di < 0 ? -1 : di;
}
function lineColor(li) {
return sus.cat7().getColor(li, false, ts.theme());
}
function tick() {
if (stopped) {
return;
}
transition = transition.each(function() {
// update the domains
now = new Date();
x.domain([now - (n - 2) * duration, now - duration]);
data.forEach(function (d, li) {
// push the new most recent sample onto the back
d.push(theSample[li]);
// redraw the line and slide it left
paths[li].attr("d", lines[li]).attr("transform", null);
paths[li].transition()
.attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
// pop the old data point off the front
d.shift();
});
// slide the x-axis left
axis.call(x.axis);
}).transition().each("start", tick);
}
function start() {
stopped = false;
headers.forEach(function (h, li) {
theSample[li] = data[li][n-1];
});
tick();
}
function stop() {
headers.forEach(function (h, li) {
theSample[li] = 0;
});
// Schedule delayed stop to allow 0s to render.
setTimeout(function () { stopped = true; }, 1000);
}
function resize(dim) {
margin = {top: 20, right: 90, bottom: 20, left: 70};
width = dim.width - margin.right - margin.left;
height = 480 - margin.top - margin.bottom;
x = d3.time.scale()
.domain([now - (n - 2) * duration, now - duration])
.range([0, width]);
y = d3.scale.linear()
.domain([0, 200000])
.range([height, 0]);
d3.select("#intent-perf-svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
d3.select("#intent-perf-svg-g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.select("#intent-perf-clip rect")
.attr("width", width)
.attr("height", height);
d3.select("#intent-perf-x")
.attr("transform", "translate(0," + height + ")")
.call(x.axis = d3.svg.axis().scale(x).orient("bottom"));
d3.select("#intent-perf-yl")
.call(d3.svg.axis().scale(y).orient("left"))
d3.select("#intent-perf-yr")
.attr("transform", "translate(" + width + " ,0)")
.call(d3.svg.axis().scale(y).orient("right"))
}
return {
start: start,
stop: stop,
resize: resize
};
}
function wsOpen(host, url) {
$log.debug('IntentPerf: web socket open - cluster node:', host, 'URL:', url);
// Request batch of initial data from the new server
wss.sendEvent('intentPerfStart');
}
function createAndInitGraph(d) {
if (!graph) {
d.headers.push("total");
graph = createGraph(d.headers, d.samples);
}
graph.start();
}
function graphResized(dim) {
$log.info("Resized: " + dim.width + "x" + dim.height);
if (graph) {
graph.resize(dim);
}
}
function recordSample(sample) {
var total = 0;
sample.data.forEach(function (d, i) {
theSample[i] = d;
total = total + d;
});
theSample[sample.data.length] = total;
}
function createHandlerMap() {
handlerMap = {
intentPerfInit: createAndInitGraph,
intentPerfSample: recordSample
};
}
// define the controller
angular.module('ovIntentPerf', ['onosUtil'])
.controller('OvIntentPerfCtrl',
['$scope', '$log', 'ToolbarService', 'WebSocketService',
'ThemeService', 'FlashService', 'SvgUtilService', 'FnService',
'MastService',
function ($scope, _$log_, _tbs_, _wss_, _ts_, _flash_, _sus_, _fs_, _mast_) {
var self = this;
$log = _$log_;
tbs = _tbs_;
wss = _wss_;
ts = _ts_;
flash = _flash_;
sus = _sus_;
fs = _fs_;
mast = _mast_;
createHandlerMap();
self.notifyResize = function () {
graphResized(fs.windowSize(mast.mastHeight()));
};
function start() {
openListener = wss.addOpenListener(wsOpen);
wss.bindHandlers(handlerMap);
wss.sendEvent('intentPerfStart');
$log.debug('intentPerf comms started');
}
function stop() {
graph.stop();
wss.sendEvent('intentPerfStop');
wss.unbindHandlers(handlerMap);
wss.removeOpenListener(openListener);
openListener = null;
graph = null;
$log.debug('intentPerf comms stopped');
}
// Cleanup on destroyed scope..
$scope.$on('$destroy', function () {
$log.log('OvIntentPerfCtrl is saying Buh-Bye!');
stop();
});
$log.log('OvIntentPerfCtrl has been created');
start();
}]);
}());