mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-23 13:21:21 +02:00
Topo2: Implemented Link Labels
JIRA-Tasks; ONOS-6387 Change-Id: I6d0292846349d73d6d274ae806d14736b2d3eb7c
This commit is contained in:
parent
0ad49b129a
commit
ca1a39c5d1
@ -293,35 +293,45 @@
|
||||
/* TODO: Review for not-permitted links */
|
||||
#ov-topo2 svg .link.not-permitted {
|
||||
stroke: rgb(255,0,0);
|
||||
stroke-width: 5.0;
|
||||
stroke-dasharray: 8 4;
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary {
|
||||
stroke-width: 3px;
|
||||
stroke: rgba(0,153,51,0.5);
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-green {
|
||||
stroke: rgb(0,153,51);
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-yellow {
|
||||
stroke: rgb(128,145,27);
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-orange {
|
||||
stroke: rgb(255, 137, 3);
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-red {
|
||||
stroke: rgb(183, 30, 21);
|
||||
}
|
||||
|
||||
/* Port traffic color visualization for Kbps, Mbps, and Gbps */
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-Kbps {
|
||||
stroke: rgb(0,153,51);
|
||||
stroke-width: 5.0;
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-Mbps {
|
||||
stroke: rgb(128,145,27);
|
||||
stroke-width: 6.5;
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-Gbps {
|
||||
stroke: rgb(255, 137, 3);
|
||||
stroke-width: 8.0;
|
||||
}
|
||||
|
||||
#ov-topo2 svg .link.secondary.port-traffic-Gbps-choked {
|
||||
stroke: rgb(183, 30, 21);
|
||||
stroke-width: 8.0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,12 +48,14 @@
|
||||
addModel: function (data) {
|
||||
if (Object.getPrototypeOf(data) !== Object.prototype) {
|
||||
this.models.push(data);
|
||||
data.collection = this;
|
||||
this._byId[data.get('id')] = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
var CollectionModel = this.model;
|
||||
var model = new CollectionModel(data, this);
|
||||
model.collection = this;
|
||||
|
||||
this.models.push(model);
|
||||
this._byId[data.id] = model;
|
||||
@ -96,6 +98,12 @@
|
||||
filter: function (comparator) {
|
||||
return _.filter(this.models, comparator);
|
||||
},
|
||||
empty: function () {
|
||||
_.map(this.models, function (m) {
|
||||
m.remove();
|
||||
});
|
||||
this._reset();
|
||||
},
|
||||
_reset: function () {
|
||||
this._byId = [];
|
||||
this.models = [];
|
||||
@ -111,7 +119,6 @@
|
||||
.factory('Topo2Collection',
|
||||
['Topo2Model', 'FnService',
|
||||
function (_Model_, fn) {
|
||||
|
||||
Collection.extend = fn.extend;
|
||||
Model = _Model_;
|
||||
return Collection;
|
||||
|
@ -27,7 +27,7 @@
|
||||
'use strict';
|
||||
|
||||
// injected refs
|
||||
var $log, wss, t2fs;
|
||||
var $log, wss, t2fs, t2ovs;
|
||||
|
||||
// internal state
|
||||
var handlerMap,
|
||||
@ -42,7 +42,8 @@
|
||||
topo2CurrentRegion: t2fs,
|
||||
topo2PeerRegions: t2fs,
|
||||
|
||||
topo2UiModelEvent: t2fs
|
||||
topo2UiModelEvent: t2fs,
|
||||
topo2Highlights: t2ovs.showHighlights,
|
||||
|
||||
// Add further event names / module references as needed
|
||||
};
|
||||
@ -83,12 +84,13 @@
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2EventService', [
|
||||
'$log', 'WebSocketService', 'Topo2ForceService',
|
||||
'$log', 'WebSocketService', 'Topo2ForceService', 'Topo2OverlayService',
|
||||
|
||||
function (_$log_, _wss_, _t2fs_) {
|
||||
function (_$log_, _wss_, _t2fs_, _t2ovs_) {
|
||||
$log = _$log_;
|
||||
wss = _wss_;
|
||||
t2fs = _t2fs_;
|
||||
t2ovs = _t2ovs_;
|
||||
|
||||
// deferred creation of handler map, so module references are good
|
||||
createHandlerMap();
|
||||
|
@ -50,26 +50,39 @@
|
||||
_iconG: {},
|
||||
_labelG: {},
|
||||
|
||||
initialize: function (data, node, options) {
|
||||
initialize: function (data, node) {
|
||||
this.parent = node;
|
||||
this.options = options || {};
|
||||
|
||||
t2zs.addZoomEventListener(this.setScale.bind(this));
|
||||
this.beforeRender();
|
||||
this.render();
|
||||
this.afterRender();
|
||||
},
|
||||
onChange: function (property, value, options) {
|
||||
onChange: function (property) {
|
||||
if (property === 'x' || property === 'y') {
|
||||
this._position();
|
||||
}
|
||||
|
||||
if (property === 'label') {
|
||||
var width = this._labelG.text.node().getBBox().width + 20,
|
||||
height = this._labelG.text.node().getBBox().height + 10;
|
||||
|
||||
this._labelG.text.text(this.get('label'));
|
||||
this._labelG.rect.attr({
|
||||
width: width,
|
||||
height: height
|
||||
}).style({
|
||||
transform: sus.translate(-(width/2) + 'px', -(height/2) + 'px')
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setPosition: function () {},
|
||||
setScale: function () {},
|
||||
|
||||
applyStyles: function () {
|
||||
var styles = _.extend({}, defaultStyles, this.get('styles'));
|
||||
var styles = _.extend({}, defaultStyles, this.get('styles') || {});
|
||||
|
||||
if (this.get('text')) {
|
||||
if (this.get('label')) {
|
||||
this._labelG.text.style(styles.label.text);
|
||||
this._labelG.rect.style(styles.label.rect);
|
||||
}
|
||||
@ -79,21 +92,17 @@
|
||||
this._iconG.rect.style(styles.icon.rect);
|
||||
}
|
||||
},
|
||||
|
||||
_position: function () {
|
||||
this.el.style('transform', sus.translate(this.get('x') + 'px',
|
||||
this.get('y') + 'px'));
|
||||
},
|
||||
labelDimensions: function () {
|
||||
return this.content.node().getBBox();
|
||||
},
|
||||
renderText: function () {
|
||||
this._labelG.el = this.content.append('g')
|
||||
.attr('class', 'label-group');
|
||||
|
||||
this._labelG.rect = this._labelG.el.append('rect');
|
||||
this._labelG.text = this._labelG.el.append('text')
|
||||
.text(this.get('text'))
|
||||
.text(this.get('label'))
|
||||
.attr('y', '0.4em')
|
||||
.style('text-anchor', 'middle');
|
||||
|
||||
@ -127,6 +136,7 @@
|
||||
transform: sus.translate(iconX, iconY)
|
||||
});
|
||||
},
|
||||
beforeRender: function () {},
|
||||
render: function () {
|
||||
this.el = this.parent.append('g')
|
||||
.attr('class', 'topo2-label')
|
||||
@ -146,6 +156,10 @@
|
||||
this.applyStyles();
|
||||
this.setPosition();
|
||||
this.setScale();
|
||||
},
|
||||
afterRender: function () {},
|
||||
remove: function () {
|
||||
this.el.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
A collection of any type of label (Topo2Label, Topo2Badge, Topo2LinkLabel)
|
||||
*/
|
||||
|
||||
|
||||
(function () {
|
||||
|
||||
var instance;
|
||||
@ -32,12 +31,18 @@
|
||||
var LabelCollection = Collection.extend({
|
||||
initialize: function () {
|
||||
instance = this;
|
||||
},
|
||||
addLabel: function (Model, label, targetNode, options) {
|
||||
if (this._byId[label.id]) {
|
||||
this.get(label.id).set(label);
|
||||
} else {
|
||||
var lab = new Model(label, targetNode, options)
|
||||
this.add(lab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return instance || new LabelCollection();
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
})();
|
||||
})();
|
||||
|
@ -22,7 +22,8 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var $log, Collection, Model, ts, sus, t2zs, t2vs, t2lps, fn, ps, t2mss;
|
||||
var $log, Collection, Model, ts, sus, t2zs, t2vs, t2lps,
|
||||
fn, ps, t2mss, t2ts;
|
||||
|
||||
var linkLabelOffset = '0.35em';
|
||||
|
||||
@ -134,7 +135,8 @@
|
||||
enhanced: this.get('enhanced'),
|
||||
selected: this.get('selected'),
|
||||
suppressedmax: this.get('mastership')
|
||||
}
|
||||
},
|
||||
(this.linkLabel) ? this.linkLabel.linkLabelCSSClass() : null
|
||||
);
|
||||
},
|
||||
expected: function () {
|
||||
@ -154,6 +156,7 @@
|
||||
// Update class names when the model changes
|
||||
if (this.el) {
|
||||
this.el.attr('class', this.svgClassName());
|
||||
this.setScale();
|
||||
}
|
||||
},
|
||||
enhance: function () {
|
||||
@ -239,7 +242,6 @@
|
||||
};
|
||||
},
|
||||
setPosition: function () {
|
||||
|
||||
var multiline = this.get('multiline');
|
||||
if (multiline) {
|
||||
var offsetAmt = this.amt(multiline.deviceLinks, multiline.index);
|
||||
@ -256,6 +258,9 @@
|
||||
this.el.attr(this.get('position'));
|
||||
}
|
||||
|
||||
if (this.linkLabel) {
|
||||
this.linkLabel.setPosition();
|
||||
}
|
||||
},
|
||||
updatePortPosition: function () {
|
||||
var sourcePos = this.locatePortLabel(1),
|
||||
@ -324,11 +329,39 @@
|
||||
this.setVisibility();
|
||||
this.setScale();
|
||||
},
|
||||
linkWidth: function () {
|
||||
var width = widthRatio;
|
||||
if (this.get('enhanced')) { width = 3.5; }
|
||||
if (this.linkLabel) {
|
||||
var scale = d3.scale.ordinal()
|
||||
.rangeRoundPoints([4, 8]),
|
||||
label = this.linkLabel.get('label').split(' ');
|
||||
|
||||
switch (t2ts.selectedTrafficOverlay()) {
|
||||
case 'flowStatsBytes':
|
||||
scale.domain(['KB', 'MB', 'GB']);
|
||||
width = scale(label[1]);
|
||||
break;
|
||||
case 'portStatsBitSec':
|
||||
scale.domain(['Kbps', 'Mbps', 'Gbps'])
|
||||
width = scale(label[1]);
|
||||
break;
|
||||
case 'portStatsPktSec':
|
||||
scale = d3.scale.linear()
|
||||
.domain([1, 10, 100, 1000, 10000])
|
||||
.range(d3.range(3.5, 9))
|
||||
.clamp(true);
|
||||
width = scale(parseInt(label[0]));
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
},
|
||||
setScale: function () {
|
||||
|
||||
if (!this.el) return;
|
||||
|
||||
var linkWidthRatio = this.get('enhanced') ? 3.5 : widthRatio;
|
||||
var linkWidthRatio = this.linkWidth();
|
||||
|
||||
var width = linkScale(linkWidthRatio) / t2zs.scale();
|
||||
this.el.attr('stroke-width', width + 'px');
|
||||
@ -342,6 +375,9 @@
|
||||
|
||||
this.setPosition();
|
||||
|
||||
if (this.linkLabel) {
|
||||
this.linkLabel.setScale();
|
||||
}
|
||||
},
|
||||
update: function () {
|
||||
if (this.get('enhanced')) {
|
||||
@ -390,9 +426,9 @@
|
||||
'$log', 'Topo2Collection', 'Topo2Model',
|
||||
'ThemeService', 'SvgUtilService', 'Topo2ZoomService',
|
||||
'Topo2ViewService', 'Topo2LinkPanelService', 'FnService', 'PrefsService',
|
||||
'Topo2MastershipService',
|
||||
'Topo2MastershipService', 'Topo2TrafficService',
|
||||
function (_$log_, _c_, _Model_, _ts_, _sus_,
|
||||
_t2zs_, _t2vs_, _t2lps_, _fn_, _ps_, _t2mss_) {
|
||||
_t2zs_, _t2vs_, _t2lps_, _fn_, _ps_, _t2mss_, _t2ts_) {
|
||||
|
||||
$log = _$log_;
|
||||
ts = _ts_;
|
||||
@ -405,6 +441,7 @@
|
||||
fn = _fn_;
|
||||
ps = _ps_;
|
||||
t2mss = _t2mss_;
|
||||
t2ts = _t2ts_;
|
||||
|
||||
return {
|
||||
createLinkCollection: createLinkCollection
|
||||
|
@ -30,8 +30,21 @@
|
||||
className: 'topo2-linklabel',
|
||||
maxHeight: 30,
|
||||
minHeight: 20,
|
||||
initialize: function (label, dom, options) {
|
||||
this.link = options.link;
|
||||
this.parent = dom;
|
||||
this.super = this.constructor.__super__;
|
||||
this.super.initialize.apply(this, arguments);
|
||||
},
|
||||
onChange: function () {
|
||||
this.link.onChange();
|
||||
this.constructor.__super__.onChange.apply(this, arguments);
|
||||
},
|
||||
linkLabelCSSClass: function () {
|
||||
return this.get('css') || '';
|
||||
},
|
||||
setPosition: function () {
|
||||
var link = this.options.link;
|
||||
var link = this.link;
|
||||
this.set({
|
||||
x: (link.source.x + link.target.x) / 2,
|
||||
y: (link.source.y + link.target.y) / 2
|
||||
@ -40,6 +53,14 @@
|
||||
setScale: function () {
|
||||
this.content.style('transform',
|
||||
'scale(' + t2zs.adjustmentScale(20, 30) + ')');
|
||||
},
|
||||
beforeRender: function () {
|
||||
this.link.linkLabel = this;
|
||||
},
|
||||
remove: function () {
|
||||
this.link.linkLabel = null;
|
||||
this.link.onChange();
|
||||
this.constructor.__super__.remove.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -23,13 +23,8 @@ Visualization of the topology in an SVG layer, using a D3 Force Layout.
|
||||
'use strict';
|
||||
|
||||
function Model(attributes, collection) {
|
||||
|
||||
var attrs = attributes || {};
|
||||
this.attributes = {};
|
||||
|
||||
attrs = angular.extend({}, attrs);
|
||||
this.set(attrs, { silent: true });
|
||||
this.collection = collection;
|
||||
this.set(angular.extend({}, attributes || {}), { silent: true });
|
||||
this.initialize.apply(this, arguments);
|
||||
}
|
||||
|
||||
@ -116,6 +111,11 @@ Visualization of the topology in an SVG layer, using a D3 Force Layout.
|
||||
},
|
||||
toJSON: function (options) {
|
||||
return angular.copy(this.attributes);
|
||||
},
|
||||
remove: function () {
|
||||
if (this.collection) {
|
||||
this.collection.remove(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
var t2os = 'Topo2OverlayService: ';
|
||||
|
||||
// injected refs
|
||||
var $log, $timeout, fs, gs, wss, t2kcs, api;
|
||||
var $log, $timeout, fs, gs, wss, t2kcs, t2rs, t2lc, api, LinkLabel;
|
||||
|
||||
// internal state
|
||||
var overlays = {},
|
||||
@ -134,27 +134,20 @@
|
||||
}
|
||||
|
||||
function showHighlights(data) {
|
||||
function doHighlight() {
|
||||
_showHighlights(data);
|
||||
}
|
||||
|
||||
// note: this allows the server-side event to add a manual delay
|
||||
// before invoking the highlight... this was (originally) to
|
||||
// allow for the re-creation of the DOM model, before trying
|
||||
// to reference elements. For Topo2, there may be a better
|
||||
// solution, making this piece of code redundant. Steven??
|
||||
|
||||
if (data.delay) {
|
||||
$timeout(doHighlight, data.delay);
|
||||
} else {
|
||||
doHighlight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _showHighlights(data) {
|
||||
// TODO: implement the highlighting .. see topoOverlay.js for example
|
||||
$log.info('+++ TOPO 2 +++ show highlights', data);
|
||||
t2lc.empty();
|
||||
var linkLabelsDOM = d3.select('.topo2-linkLabels');
|
||||
_.each(data.links, function (link) {
|
||||
// TODO: Inconsistent host id's (currentRegion and LinkLabel)
|
||||
var id = link.id.replace('/None/0', '/None').replace('-', '~'),
|
||||
lab = t2rs.getLink(id);
|
||||
// TODO: There's a bug in backend where link id is in reverse
|
||||
if (lab) {
|
||||
t2lc.addLabel(LinkLabel, link, linkLabelsDOM, {
|
||||
link: lab
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
@ -162,15 +155,20 @@
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2OverlayService', [
|
||||
'$log', '$timeout', 'FnService', 'GlyphService', 'WebSocketService',
|
||||
'Topo2KeyCommandService',
|
||||
'Topo2KeyCommandService', 'Topo2RegionService', 'Topo2LabelCollection',
|
||||
'Topo2LinkLabel',
|
||||
|
||||
function (_$log_, _$timeout_, _fs_, _gs_, _wss_, _t2kcs_) {
|
||||
function (_$log_, _$timeout_, _fs_, _gs_, _wss_, _t2kcs_, _t2rs_,
|
||||
_t2lc_, _t2ll_) {
|
||||
$log = _$log_;
|
||||
$timeout = _$timeout_;
|
||||
fs = _fs_;
|
||||
gs = _gs_;
|
||||
wss = _wss_;
|
||||
t2kcs = _t2kcs_;
|
||||
t2rs = _t2rs_;
|
||||
t2lc = _t2lc_;
|
||||
LinkLabel = _t2ll_;
|
||||
|
||||
return {
|
||||
register: register,
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
// internal state
|
||||
var mode = null,
|
||||
currentIndex = 0,
|
||||
allIndex = 0;
|
||||
|
||||
// === -----------------------------------------------------
|
||||
@ -59,9 +60,14 @@
|
||||
trafficType: allTrafficTypes[allIndex]
|
||||
});
|
||||
flash.flash(allTrafficMsgs[allIndex]);
|
||||
currentIndex = allIndex;
|
||||
allIndex = (allIndex + 1) % 3;
|
||||
}
|
||||
|
||||
function selectedTrafficOverlay() {
|
||||
return allTrafficTypes[currentIndex];
|
||||
}
|
||||
|
||||
// === -----------------------------------------------------
|
||||
|
||||
angular.module('ovTopo2')
|
||||
@ -80,7 +86,8 @@
|
||||
|
||||
// invoked from toolbar overlay buttons or keystrokes
|
||||
cancelTraffic: cancelTraffic,
|
||||
showAllTraffic: showAllTraffic
|
||||
showAllTraffic: showAllTraffic,
|
||||
selectedTrafficOverlay: selectedTrafficOverlay
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user