Topo2: Fix layout issues
Change-Id: Ief3772b9755216e44d0fe005c625e0090d8fb2b7
diff --git a/web/gui/src/main/webapp/app/fw/svg/zoom.js b/web/gui/src/main/webapp/app/fw/svg/zoom.js
index 27ce6c8..587c78d 100644
--- a/web/gui/src/main/webapp/app/fw/svg/zoom.js
+++ b/web/gui/src/main/webapp/app/fw/svg/zoom.js
@@ -69,6 +69,7 @@
fail = false,
zoomer;
+
if (!settings.svg) {
$log.error(cz + 'No "svg" (svg tag)' + d3s);
fail = true;
@@ -121,6 +122,10 @@
// apply the zoom behavior to the SVG element
settings.svg && settings.svg.call(zoom);
+
+ // Remove zoom on double click (prevents a
+ // false zoom navigating regions)
+ settings.svg.on("dblclick.zoom", null);
return zoomer;
}
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 bfe0df5..ca2982c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoLink.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoLink.js
@@ -195,9 +195,9 @@
var offset = 32,
pos = link.position,
nearX = src ? pos.x1 : pos.x2,
- nearY = src ? pos.y1 : pos.y2,
+ nearY = src ? pos.y2 : pos.y1,
farX = src ? pos.x2 : pos.x1,
- farY = src ? pos.y2 : pos.y1;
+ farY = src ? pos.y1 : pos.y2;
function dist(x, y) { return Math.sqrt(x*x + y*y); }
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 7679fe1..0b4fd2c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoModel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoModel.js
@@ -248,6 +248,7 @@
//logicError('Node(s) not on map for link:\n' + sMiss + dMiss);
return null;
}
+
return {
source: srcNode,
target: dstNode
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
index 89eb020..b6ed850 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
@@ -183,9 +183,6 @@
function newDim(_dim_) {
dim = _dim_;
t2vs.newDim(dim);
- // force.size(dim);
- // tms.newDim(dim);
- t2ls.setDimensions();
}
// ========================== Main Service Definition
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Layout.js b/web/gui/src/main/webapp/app/view/topo2/topo2Layout.js
index 4cd86cc..9ffcbe0 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Layout.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Layout.js
@@ -110,30 +110,41 @@
link = linkG.selectAll('.link');
linkLabelG.selectAll('.linkLabel');
node = nodeG.selectAll('.node');
-
- _svg_.on('mousemove', mouseMoveHandler);
}
function createForceLayout() {
+ var regionLinks = t2rs.regionLinks(),
+ regionNodes = t2rs.regionNodes();
+
force = d3.layout.force()
.size(t2vs.getDimensions())
- .nodes(t2rs.regionNodes())
- .links(t2rs.regionLinks())
- .gravity(settings.gravity)
- .friction(settings.friction)
.charge(settings.charge._def_)
.linkDistance(settings.linkDistance._def_)
- .linkStrength(settings.linkStrength._def_)
- .on('tick', tick);
+ .on("tick", tick);
+
+ force
+ .nodes(t2rs.regionNodes())
+ .links(regionLinks)
+ .start();
+
+ link = linkG.selectAll('.link')
+ .data(regionLinks, function (d) { return d.get('key'); });
+
+ node = nodeG.selectAll('.node')
+ .data(regionNodes, function (d) { return d.get('id'); });
drag = sus.createDragBehavior(force,
- t2ss.selectObject, atDragEnd, dragEnabled, clickEnabled);
+ t2ss.selectObject, atDragEnd, dragEnabled, clickEnabled);
- start();
update();
}
+ // predicate that indicates when clicking is active
+ function clickEnabled() {
+ return true;
+ }
+
function zoomingOrPanning(ev) {
return ev.metaKey || ev.altKey;
}
@@ -178,21 +189,21 @@
});
}
- // predicate that indicates when clicking is active
- function clickEnabled() {
- return true;
- }
-
function tick() {
- // guard against null (which can happen when our view pages out)...
- if (node && node.size()) {
- node.attr(tickStuff.nodeAttr);
- }
- if (link && link.size()) {
- link.call(calcPosition)
- .attr(tickStuff.linkAttr);
- // t2d3.applyNumLinkLabels(linkNums, numLinkLabelsG);
- }
+ link
+ .attr("x1", function (d) { return d.source.x; })
+ .attr("y1", function (d) { return d.source.y; })
+ .attr("x2", function (d) { return d.target.x; })
+ .attr("y2", function (d) { return d.target.y; });
+
+ node
+ .attr({
+ transform: function (d) {
+ var dx = isNaN(d.x) ? 0 : d.x,
+ dy = isNaN(d.y) ? 0 : d.y;
+ return sus.translate(dx, dy);
+ }
+ });
}
function update() {
@@ -305,7 +316,6 @@
}
function getDefaultPos(link) {
-
return {
x1: link.get('source').x,
y1: link.get('source').y,
@@ -324,100 +334,6 @@
force.start();
}
- // Mouse Events
- function mouseMoveHandler() {
- var mp = getLogicalMousePosition(this),
- link = computeNearestLink(mp);
-
- if (highlightedLink) {
- highlightedLink.unenhance();
- highlightedLink = null;
- }
-
- if (link) {
- link.enhance();
- highlightedLink = link;
- }
- }
-
- // ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ========
-
- function getLogicalMousePosition(container) {
- var m = d3.mouse(container),
- sc = uplink.zoomer().scale(),
- tr = uplink.zoomer().translate(),
- mx = (m[0] - tr[0]) / sc,
- my = (m[1] - tr[1]) / sc;
- return { x: mx, y: my };
- }
-
- function sq(x) {
- return x * x;
- }
-
- function mdist(p, m) {
- return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
- }
-
- function prox(dist) {
- return dist / uplink.zoomer().scale();
- }
-
- function computeNearestLink(mouse) {
- var proximity = prox(30),
- nearest = null,
- minDist,
- regionLinks = t2rs.regionLinks();
-
- function pdrop(line, mouse) {
-
- var x1 = line.x1,
- y1 = line.y1,
- x2 = line.x2,
- y2 = line.y2,
- x3 = mouse.x,
- y3 = mouse.y,
- k = ((y2 - y1) * (x3 - x1) - (x2 - x1) * (y3 - y1)) /
- (sq(y2 - y1) + sq(x2 - x1)),
- x4 = x3 - k * (y2 - y1),
- y4 = y3 + k * (x2 - x1);
- return { x: x4, y: y4 };
- }
-
- 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;
- if (p.y < line.y1 && p.y < line.y2) return false;
- if (p.y > line.y1 && p.y > line.y2) return false;
- // line intersects, but are we close enough?
- return mdist(p, m) <= proximity;
- }
-
- if (regionLinks.length) {
- minDist = proximity * 2;
-
- regionLinks.forEach(function (d) {
- // if (!api.showHosts() && d.type() === 'hostLink') {
- // return; // skip hidden host links
- // }
-
- var line = d.get('position'),
- point = pdrop(line, mouse),
- hit = lineHit(line, point, mouse),
- dist;
-
- if (hit) {
- dist = mdist(point, mouse);
- if (dist < minDist) {
- minDist = dist;
- nearest = d;
- }
- }
- });
- }
- return nearest;
- }
-
angular.module('ovTopo2')
.factory('Topo2LayoutService',
[
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Link.js b/web/gui/src/main/webapp/app/view/topo2/topo2Link.js
index 415a21e..66e3bb5 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Link.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Link.js
@@ -32,7 +32,8 @@
.range([widthRatio, 12 * widthRatio])
.clamp(true),
allLinkTypes = 'direct indirect optical tunnel UiDeviceLink',
- allLinkSubTypes = 'inactive not-permitted';
+ allLinkSubTypes = 'inactive not-permitted',
+ labelDim = 30;
// configuration
var linkConfig = {
@@ -93,6 +94,7 @@
function linkEndPoints(srcId, dstId) {
+ var allNodes = this.region.nodes();
var sourceNode = this.region.findNodeById(srcId);
var targetNode = this.region.findNodeById(dstId);
@@ -102,8 +104,10 @@
return null;
}
- this.source = sourceNode.toJSON();
- this.target = targetNode.toJSON();
+ this.source = allNodes.indexOf(sourceNode);
+ this.target = allNodes.indexOf(targetNode);
+ this.sourceNode = sourceNode;
+ this.targetNode = targetNode;
return {
source: sourceNode,
@@ -162,9 +166,10 @@
var entering = d3.select('#topo-portLabels')
.selectAll('.portLabel')
- .data(data).enter().append('g')
+ .data(data)
+ .enter().append('g')
.classed('portLabel', true)
- .attr('id', function (d) { return d.id; });
+ .attr('id', function (d) { return d.id; })
entering.each(function (d) {
var el = d3.select(this),
@@ -181,7 +186,10 @@
.attr('text-anchor', 'middle');
el.attr('transform', sus.translate(d.x, d.y));
+
});
+
+ this.setScale();
}
},
unenhance: function () {
@@ -189,12 +197,16 @@
d3.select('#topo-portLabels').selectAll('.portLabel').remove();
},
locatePortLabel: function (src) {
- var offset = 32,
- pos = this.get('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;
+
+ var offset = 32 / (labelDim * t2zs.scale()),
+ sourceX = this.get('position').x1,
+ sourceY = this.get('position').y1,
+ targetX = this.get('position').x2,
+ targetY = this.get('position').y2,
+ nearX = src ? sourceX : targetX,
+ nearY = src ? sourceY : targetY,
+ farX = src ? targetX : sourceX,
+ farY = src ? targetY : sourceY;
function dist(x, y) {
return Math.sqrt(x * x + y * y);
@@ -202,7 +214,7 @@
var dx = farX - nearX,
dy = farY - nearY,
- k = offset / dist(dx, dy);
+ k = (32 * offset) / dist(dx, dy);
return { x: k * dx + nearX, y: k * dy + nearY };
},
@@ -232,8 +244,9 @@
}
el.transition()
.duration(delay)
- .attr('stroke-width', linkScale(widthRatio))
.attr('stroke', linkConfig[th].baseColor);
+
+ this.setScale();
}
},
onEnter: function (el) {
@@ -242,13 +255,26 @@
this.el = link;
this.restyleLinkElement();
+ // TODO: Needs improving - originally this was calculated
+ // from mouse position.
+ this.el.on('mouseover', this.enhance.bind(this));
+ this.el.on('mouseout', this.unenhance.bind(this));
+
if (this.get('type') === 'hostLink') {
// sus.visible(link, api.showHosts());
}
},
setScale: function () {
- var width = linkScale(widthRatio / t2zs.scale());
+ var width = linkScale(widthRatio) / t2zs.scale();
this.el.style('stroke-width', width + 'px');
+
+ var labelScale = labelDim / (labelDim * t2zs.scale());
+
+ d3.select('#topo-portLabels')
+ .selectAll('.portLabel')
+ .selectAll('*')
+ .style('transform', 'scale(' + labelScale + ')');
+
},
update: function () {
if (this.el.classed('enhanced')) {
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
index 6becc49..c3acff9 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
@@ -34,7 +34,8 @@
function addRegion(data) {
var RegionModel = Model.extend({
- findNodeById: findNodeById
+ findNodeById: findNodeById,
+ nodes: regionNodes
});
region = new RegionModel({
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index b848f36..0f91449 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -127,7 +127,7 @@
<link rel="stylesheet" href="app/fw/widget/table-theme.css">
<!-- Under development for Region support. -->
- <!--<script src="app/view/topo2/topo2.js"></script>
+ <!-- <script src="app/view/topo2/topo2.js"></script>
<script src="app/view/topo2/topo2Breadcrumb.js"></script>
<script src="app/view/topo2/topo2Collection.js"></script>
<script src="app/view/topo2/topo2D3.js"></script>