ONOS-2328 GUI -- Enhanced Topology View to show multiple links individually between devices (1 - 4). 5 or more is a thick line.
Change-Id: Ie096086454fd8d1d5d40f09396681f9cba8597a1
diff --git a/web/gui/src/main/webapp/app/view/topo/topoD3.js b/web/gui/src/main/webapp/app/view/topo/topoD3.js
index 09883b1..4dcf3f0 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoD3.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoD3.js
@@ -367,17 +367,10 @@
.classed('linkLabel', true)
.attr('id', function (d) { return d.id; });
- // FIXME: x and y position calculated here, use link.position obj
entering.each(function (d) {
var el = d3.select(this),
rect,
- text,
- parms = {
- x1: d.ldata.source.x,
- y1: d.ldata.source.y,
- x2: d.ldata.target.x,
- y2: d.ldata.target.y
- };
+ text;
if (d.ldata.type() === 'hostLink') {
el.classed('hostLinkLabel', true);
@@ -390,7 +383,7 @@
rect.attr(rectAroundText(el));
text.attr('dy', linkLabelOffset);
- el.attr('transform', transformLabel(parms));
+ el.attr('transform', transformLabel(d.ldata.position));
});
// Remove any labels that are no longer required.
@@ -411,7 +404,6 @@
return box;
}
- // FIXME: x and y position calculated here
function transformLabel(p) {
var dx = p.x2 - p.x1,
dy = p.y2 - p.y1,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js
index 0380c65..48309f0 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -575,6 +575,82 @@
// ==========================
+ function getDefaultPos(link) {
+ return {
+ x1: link.source.x,
+ y1: link.source.y,
+ x2: link.target.x,
+ y2: link.target.y
+ };
+ }
+
+ // returns amount of adjustment along the normal for given link
+ function amt(numLinks, linkIdx) {
+ var gap = 6;
+ return (linkIdx - ((numLinks - 1) / 2)) * gap;
+ }
+
+ function calcMovement(d, amt, flipped) {
+ var pos = getDefaultPos(d),
+ mult = flipped ? -amt : amt,
+ dx = pos.x2 - pos.x1,
+ dy = pos.y2 - pos.y1,
+ length = Math.sqrt((dx * dx) + (dy * dy));
+
+ return {
+ x1: pos.x1 + (mult * dy / length),
+ y1: pos.y1 + (mult * -dx / length),
+ x2: pos.x2 + (mult * dy / length),
+ y2: pos.y2 + (mult * -dx / length)
+ };
+ }
+
+ function calcPosition() {
+ var lines = this,
+ linkSrcId;
+ lines.each(function (d) {
+ if (d.type() === 'hostLink') {
+ d.position = getDefaultPos(d);
+ }
+ });
+
+ function normalizeLinkSrc(link) {
+ // ensure source device is consistent across set of links
+ // temporary measure until link modeling is refactored
+ if (!linkSrcId) {
+ linkSrcId = link.source.id;
+ return false;
+ }
+
+ return link.source.id !== linkSrcId;
+ }
+
+ angular.forEach(network.linksByDevice, function (linkArr) {
+ var numLinks = linkArr.length,
+ link;
+
+ if (numLinks === 1) {
+ link = linkArr[0];
+ link.position = getDefaultPos(link);
+ } else if (numLinks >= 5) {
+ // this code is inefficient, in the future the way links
+ // are modeled will be changed
+ angular.forEach(linkArr, function (link) {
+ link.position = getDefaultPos(link);
+ link.position.multiLink = true;
+ });
+ } else {
+ // calculate position of links
+ linkSrcId = null;
+ angular.forEach(linkArr, function (link, index) {
+ var offsetAmt = amt(numLinks, index),
+ needToFlip = normalizeLinkSrc(link);
+ link.position = calcMovement(link, offsetAmt, needToFlip);
+ });
+ }
+ });
+ }
+
function updateLinks() {
if (fLinksTimer) {
$timeout.cancel(fLinksTimer);
@@ -602,14 +678,14 @@
});
// operate on entering links:
- // FIXME: x and y position calculated here - calculate position and add it to the link
var entering = link.enter()
.append('line')
+ .call(calcPosition)
.attr({
- x1: function (d) { return d.source.x; },
- y1: function (d) { return d.source.y; },
- x2: function (d) { return d.target.x; },
- y2: function (d) { return d.target.y; },
+ x1: function (d) { return d.position.x1; },
+ y1: function (d) { return d.position.y1; },
+ x2: function (d) { return d.position.x2; },
+ y2: function (d) { return d.position.y2; },
stroke: linkConfig[th].inColor,
'stroke-width': linkConfig.inWidth
});
@@ -664,24 +740,17 @@
nodeAttr: {
transform: function (d) { return sus.translate(d.x, d.y); }
},
- // FIXME: x and y position calculated here, will be deleted
linkAttr: {
- x1: function (d) { return d.source.x; },
- y1: function (d) { return d.source.y; },
- x2: function (d) { return d.target.x; },
- y2: function (d) { return d.target.y; }
+ x1: function (d) { return d.position.x1; },
+ y1: function (d) { return d.position.y1; },
+ x2: function (d) { return d.position.x2; },
+ y2: function (d) { return d.position.y2; }
},
linkLabelAttr: {
transform: function (d) {
var lnk = tms.findLinkById(d.key);
if (lnk) {
- // FIXME: x and y position calculated here, use link.position object
- return td3.transformLabel({
- x1: lnk.source.x,
- y1: lnk.source.y,
- x2: lnk.target.x,
- y2: lnk.target.y
- });
+ return td3.transformLabel(lnk.position);
}
}
}
@@ -693,8 +762,8 @@
node.attr(tickStuff.nodeAttr);
}
if (link) {
- // FIXME: instead of tickStuff here, use link.position object
- link.attr(tickStuff.linkAttr);
+ link.call(calcPosition)
+ .attr(tickStuff.linkAttr);
}
if (linkLabel) {
linkLabel.attr(tickStuff.linkLabelAttr);
@@ -827,7 +896,8 @@
return old;
},
opacifyMap: uplink.opacifyMap,
- inLayer: fltr.inLayer
+ inLayer: fltr.inLayer,
+ calcLinkPos: calcPosition
};
}
diff --git a/web/gui/src/main/webapp/app/view/topo/topoLink.js b/web/gui/src/main/webapp/app/view/topo/topoLink.js
index 834f024..38f3a6c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoLink.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoLink.js
@@ -104,16 +104,6 @@
return {x:x4, y:y4};
}
- // FIXME: x and y position calculated here, use link.position
- function lineSeg(d) {
- return {
- x1: d.source.x,
- y1: d.source.y,
- x2: d.target.x,
- y2: d.target.y
- };
- }
-
function lineHit(line, p, m) {
if (p.x < line.x1 && p.x < line.x2) return false;
if (p.x > line.x1 && p.x > line.x2) return false;
@@ -131,7 +121,7 @@
return; // skip hidden host links
}
- var line = lineSeg(d),
+ var line = d.position,
point = pdrop(line, mouse),
hit = lineHit(line, point, mouse),
dist;
@@ -201,24 +191,23 @@
td3.applyPortLabels(data, api.portLabelG());
}
- // FIXME: x and y position calculated here somewhere
function locatePortLabel(link, src) {
- var near = src ? 'source' : 'target',
- far = src ? 'target' : 'source',
- ln = link[near],
- lf = link[far],
- offset = 32;
+ var offset = 32,
+ pos = link.position,
+ nearX = src ? pos.x1 : pos.x2,
+ nearY = src ? pos.y1 : pos.y2,
+ farX = src ? pos.x2 : pos.x1,
+ farY = src ? pos.y2 : pos.y1;
function dist(x, y) { return Math.sqrt(x*x + y*y); }
- var dx = lf.x - ln.x,
- dy = lf.y - ln.y,
+ var dx = farX - nearX,
+ dy = farY - nearY,
k = offset / dist(dx, dy);
- return {x: k * dx + ln.x, y: k * dy + ln.y};
+ return {x: k * dx + nearX, y: k * dy + nearY};
}
-
function selectLink(ldata) {
// if the new link is same as old link, do nothing
if (selectedLink && ldata && selectedLink.key === ldata.key) return;
diff --git a/web/gui/src/main/webapp/app/view/topo/topoModel.js b/web/gui/src/main/webapp/app/view/topo/topoModel.js
index 9c8d46b..c42e3ec 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoModel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoModel.js
@@ -209,7 +209,7 @@
t = lnk.fromTarget,
ws = (s && s.linkWidth) || 0,
wt = (t && t.linkWidth) || 0;
- return Math.max(ws, wt);
+ return lnk.position.multiLink ? 5 : Math.max(ws, wt);
}
});
return lnk;
diff --git a/web/gui/src/main/webapp/app/view/topo/topoOblique.js b/web/gui/src/main/webapp/app/view/topo/topoOblique.js
index d04965c..326271a 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOblique.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOblique.js
@@ -39,6 +39,7 @@
nodeLock(b) // test-and-set nodeLock state
opacifyMap(b) // show or hide map layer
inLayer(d, layer) // return true if d in layer {'pkt'|'opt'}
+ calcLinkPos() // recomputes link pos based on node data
*/
// configuration
@@ -155,6 +156,7 @@
.attr(api.tickStuff.nodeAttr);
api.link().transition()
.duration(time)
+ .call(api.calcLinkPos)
.attr(api.tickStuff.linkAttr);
api.linkLabel().transition()
.duration(time)