webgme-rosmod
Version:
This repository contains ROSMOD developed for WebGME. ROSMOD is a web-based, collaborative, modeling and execution environment for distributed embedded applications built using ROS http://rosmod.rcps.isis.vanderbilt.edu
315 lines (268 loc) • 8.46 kB
JavaScript
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 0.1.0 from webgme on Wed Apr 06 2016 14:15:27 GMT-0500 (CDT).
*/
define([
'text!./Plot.html',
'blob/BlobClient',
'./ResultsVizWidget.TraceParser',
'./ResultsVizWidget.UserParser',
'./ResultsVizWidget.Plotter',
'plotly-js/plotly.min',
'select2/js/select2.min',
'd3',
'q',
'css!select2/css/select2.min.css',
'css!./styles/ResultsVizWidget.css'
], function (
PlotHtml,
BlobClient,
TraceParser,
UserParser,
Plotter,
Plotly,
select2,
d3,
Q) {
var ResultsVizWidget,
WIDGET_CLASS = 'results-viz';
ResultsVizWidget = function (options) {
this._logger = options.logger.fork('Widget');
this._el = options.container;
this._blobClient = new BlobClient({logger: options.logger.fork('BlobClient')});
this._client = options.client;
this._initialize();
this._logger.debug('ctor finished');
};
ResultsVizWidget.prototype._initialize = function () {
var width = this._el.width(),
height = this._el.height(),
self = this;
// data we need
this.nodes = {};
this.activeId = null;
this.datas = {};
this.logs = {};
this.timeBeginEnd = {
begin: -1,
end: -1
};
// set widget class
this._el.addClass(WIDGET_CLASS);
// setup the html
this._el.append(PlotHtml);
this._controls = this._el.find('#controls').first();
this._plotSelectors = this._el.find('.plot-selector').first();
this._plotSelectors.select2();
this._plotContainer = this._el.find('#plot-div').first();
// checkbox for shared axes
Plotter.sharedX = true;
this.sharedXAxes_toggle = this._el.find("#cbSharedX").first();
$(this.sharedXAxes_toggle).prop('checked', Plotter.sharedX);
this.sharedXAxes_toggle.on('change', this.togglePlot.bind(this, 'sharedX'));
Plotter.sharedY = false;
this.sharedYAxes_toggle = this._el.find("#cbSharedY").first();
$(this.sharedYAxes_toggle).prop('checked', Plotter.sharedY);
this.sharedYAxes_toggle.on('change', this.togglePlot.bind(this, 'sharedY'));
// checkbox for legend
Plotter.legendInPlot = false;
this.legednInPlot_toggle = this._el.find("#cbLegendInPlot").first();
$(this.legednInPlot_toggle).prop('checked', Plotter.legendInPlot);
this.legednInPlot_toggle.on('change', this.togglePlot.bind(this, 'legendInPlot'));
};
// built-in toggles
ResultsVizWidget.prototype.togglePlot = function(key, event) {
var self=this;
var toggle = event.target;
var checked = toggle.checked;
Plotter[key] = checked;
var id = Object.keys(self.nodes)[0];
self.plotLogs();
};
ResultsVizWidget.prototype.onLogToggled = function(event) {
var self = this;
// set all to false
Object.keys(self.logs).map((logName) => {
self.logs[logName].enabled = false;
});
// now set the selected ones to true
var selectedLogs = self._plotSelectors.select2("data");
selectedLogs.map((log) => {
var logName = log.text;
self.logs[logName].enabled = true;
});
// update the plot
self.plotLogs();
};
ResultsVizWidget.prototype.clearLogToggles = function() {
var self = this;
if (self._plotSelectors) {
self._plotSelectors.val(null);
}
};
ResultsVizWidget.prototype.makeLogControls = function() {
var self = this;
Object.keys(self.logs).sort().map((logName) => {
var key = logName.replace(/\./g, '_');
self._plotSelectors.append(`<option selected="selected" value="${key}">${logName}</option>`);
});
self._plotSelectors.on('change', self.onLogToggled.bind(self));
};
ResultsVizWidget.prototype.loadNodeData = function (desc) {
var self = this;
// reset begin / end times
self.timeBeginEnd = {
begin: -1,
end: -1
};
self.datas = {};
self.logs = {};
// clear out log toggles
self.clearLogToggles();
var attributes = desc.attributes.concat(desc.userLogs);
var tasks = attributes.map((key) => {
var a = key;
// load the attribute
var nodeObj = self._client.getNode(desc.id);
var logHash = nodeObj.getAttribute(a);
var logName = a;
if (logHash) {
// get the name of the file <node>.<comp>.<user/trace>.log
return self._blobClient.getMetadata(logHash)
.then((metadata) => {
// save the name
logName = metadata.name;
// now get the log data
return self._blobClient.getObjectAsString(logHash)
})
.then((data) => {
var parsed = {};
// parse the logs
if (logName.indexOf('.trace.log') > -1) {
parsed = TraceParser.getDataFromAttribute(data);
} else {
parsed = UserParser.getDataFromAttribute(data);
}
// figure out time range
if (!_.isEmpty(parsed)) {
self.logs[logName] = {
data: parsed,
logName: logName,
logHash: logHash,
enabled: true,
};
var logTimeRange = UserParser.getTimeBeginEnd( self.logs[logName].data );
if (self.timeBeginEnd.begin == -1 ||
self.timeBeginEnd.begin > logTimeRange.begin) {
self.timeBeginEnd.begin = logTimeRange.begin;
}
if (self.timeBeginEnd.end == -1 ||
self.timeBeginEnd.end < logTimeRange.end) {
self.timeBeginEnd.end = logTimeRange.end;
}
}
});
}
});
return Q.allSettled(tasks)
.then(function() {
return self.makeLogControls();
});
};
ResultsVizWidget.prototype.plotLogs = function () {
var self = this;
self.clearPlot();
// logs sorted by name and with disabled logs removed
var sortedLogs = Object.keys(self.logs).sort().filter((logKey) => {
return self.logs[logKey].enabled;
});
// data from the sorted & enabled logs
var sortedDatas = sortedLogs.map((logKey) => {
return self.logs[logKey].data;
});
Plotter.plotData(self._plotContainer, 'plot', sortedDatas, self._onClick.bind(self, self.activeId) );
};
// Adding/Removing/Updating items
ResultsVizWidget.prototype.addNode = function (desc) {
var self = this;
if (desc && !self.nodes[desc.id]) {
self.nodes[desc.id] = desc;
self.activeId = desc.id;
self.loadNodeData(desc)
.then(function() {
self.plotLogs();
});
}
};
ResultsVizWidget.prototype.removeNode = function (gmeId) {
var desc = this.nodes[gmeId];
if (desc) { // if this is our results object
this.clearNodes();
}
};
ResultsVizWidget.prototype.updateNode = function (desc) {
if (this.nodes[desc.id]) { // if this is our results object
// remove old data
this.clearNodes();
// recreate with new data
this.addNode(desc);
}
};
ResultsVizWidget.prototype._onClick = function (id) {
this.onActivate();
WebGMEGlobal.State.registerActiveSelection([id]);
};
/* * * * * * * * Visualizer event handlers * * * * * * * */
ResultsVizWidget.prototype.onBackgroundDblClick = function () {
};
ResultsVizWidget.prototype.onWidgetContainerResize = function (width, height) {
//console.log('Widget is resizing...');
var self = this;
if (self._el) {
var p = d3.selectAll(self._el).select('#plot')
if (p) {
var n = p.node();
if (n && Plotly.Plots && Plotly.Plots.resize) {
Plotly.Plots.resize(n);
}
}
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ResultsVizWidget.prototype._addSplitPanelToolbarBtns = function(toolbarEl) {
var self = this;
};
ResultsVizWidget.prototype.clearPlot = function() {
if (this._plotContainer) {
this._plotContainer.empty();
this._plotContainer.append('<div id="plot"></div>');
this._plotEl = this._el.find('#plot').first();
}
};
ResultsVizWidget.prototype.clearNodes = function() {
if (this._plotEl) {
this._plotEl.empty();
}
if (this._plotSelectors) {
this._plotSelectors.empty();
}
delete this.nodes;
this.nodes = {};
};
ResultsVizWidget.prototype.shutdown = function() {
if (this._el) {
this._el.remove();
delete this._el;
}
};
ResultsVizWidget.prototype.destroy = function () {
this.clearNodes();
this.shutdown();
};
ResultsVizWidget.prototype.onActivate = function () {
};
ResultsVizWidget.prototype.onDeactivate = function () {
};
return ResultsVizWidget;
});