Simon Hunt

GUI -- TopoView - Initial work for implementing link selection.

- a step in the direction for showing port numbers.

Change-Id: I313782374c82b87b6d426e88519a5ab7c072a622
......@@ -5,6 +5,7 @@
<script src="app/view/topo/topoFilter.js"></script>
<script src="app/view/topo/topoForce.js"></script>
<script src="app/view/topo/topoInst.js"></script>
<script src="app/view/topo/topoLink.js"></script>
<script src="app/view/topo/topoModel.js"></script>
<script src="app/view/topo/topoOblique.js"></script>
<script src="app/view/topo/topoPanel.js"></script>
......
......@@ -232,6 +232,7 @@
showNoDevs: showNoDevs,
projection: function () { return projection; },
zoomLayer: function () { return zoomLayer; },
zoomer: function () { return zoomer; },
opacifyMap: opacifyMap,
sendEvent: _tes_.sendEvent
};
......@@ -287,7 +288,7 @@
);
forceG = zoomLayer.append('g').attr('id', 'topo-force');
tfs.initForce(forceG, uplink, dim);
tfs.initForce(svg, forceG, uplink, dim);
tis.initInst({ showMastership: tfs.showMastership });
tps.initPanels({ sendEvent: tes.sendEvent });
tes.openSock();
......
......@@ -23,7 +23,7 @@
'use strict';
// injected refs
var $log, fs, sus, is, ts, flash, tis, tms, td3, tss, tts, tos, fltr,
var $log, fs, sus, is, ts, flash, tis, tms, td3, tss, tts, tos, fltr, tls,
icfg, uplink;
// configuration
......@@ -728,15 +728,25 @@
};
}
function mkLinkApi(svg, forceG, uplink) {
return {
svg: svg,
forceG: forceG,
zoomer: uplink.zoomer(),
network: network,
showHosts: function () { return showHosts; }
};
}
angular.module('ovTopo')
.factory('TopoForceService',
['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService',
'FlashService', 'TopoInstService', 'TopoModelService',
'TopoD3Service', 'TopoSelectService', 'TopoTrafficService',
'TopoObliqueService', 'TopoFilterService',
'TopoObliqueService', 'TopoFilterService', 'TopoLinkService',
function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_,
_tis_, _tms_, _td3_, _tss_, _tts_, _tos_, _fltr_) {
_tis_, _tms_, _td3_, _tss_, _tts_, _tos_, _fltr_, _tls_) {
$log = _$log_;
fs = _fs_;
sus = _sus_;
......@@ -750,6 +760,7 @@
tts = _tts_;
tos = _tos_;
fltr = _fltr_;
tls = _tls_;
icfg = is.iconConfig();
......@@ -762,7 +773,7 @@
// uplink is the api from the main topo source file
// dim is the initial dimensions of the SVG as [w,h]
// opts are, well, optional :)
function initForce(forceG, _uplink_, _dim_, opts) {
function initForce(svg, forceG, _uplink_, _dim_, opts) {
uplink = _uplink_;
dim = _dim_;
......@@ -774,6 +785,7 @@
tts.initTraffic(mkTrafficApi(uplink));
tos.initOblique(mkObliqueApi(uplink, fltr));
fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right'));
tls.initLink(mkLinkApi(svg, forceG, uplink));
settings = angular.extend({}, defaultSettings, opts);
......@@ -808,6 +820,7 @@
}
function destroyForce() {
tls.destroyLink();
fltr.destroyFilter();
tos.destroyOblique();
tts.destroyTraffic();
......
/*
* 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 -- Topology Link Module.
Functions for highlighting/selecting links
*/
(function () {
'use strict';
// injected refs
var $log, fs, sus, ts;
var api,
network,
enhancedLink = null; // the link which the mouse is hovering over
// SVG elements;
var svg, mouseG;
// ======== ALGORITHM TO FIND LINK CLOSEST TO MOUSE ========
function setupMouse(forceG, zoomer) {
$log.debug('set up mouse handlers for mouse move');
mouseG = forceG.append('g').attr('id', 'topo-mouse');
//mouseG.append('circle')
// .attr({
// r: 5,
// opacity: 0
// })
// .style('fill', 'red');
svg.on('mouseenter', function () {
//$log.log('M--ENTER');
//mouseG.selectAll('circle').attr('opacity', 1);
})
.on('mouseleave', function () {
//$log.log('M--LEAVE');
//mouseG.selectAll('circle').attr('opacity', 0);
})
.on('mousemove', function () {
var m = d3.mouse(this),
sc = zoomer.scale(),
tr = zoomer.translate(),
mx = (m[0] - tr[0]) / sc,
my = (m[1] - tr[1]) / sc;
//$log.log('M--MOVE', m);
//mouseG.selectAll('circle')
// .attr({
// cx: mx,
// cy: my
// });
updatePerps({x: mx, y: my}, zoomer);
});
}
function updatePerps(mouse, zoomer) {
var proximity = 30 / zoomer.scale(),
perpData, perps, nearest, minDist;
function sq(x) { return x * x; }
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 mdist(p, m) {
return Math.sqrt(sq(p.x - m.x) + sq(p.y - m.y));
}
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;
if (p.y < line.y1 && p.y < line.y2) return false;
if (p.y > line.y1 && p.y > line.y2) return false;
// line bisects, but are we close enough?
return mdist(p, m) <= proximity;
}
if (network.links.length) {
perpData = [];
nearest = null;
minDist = proximity * 2;
network.links.forEach(function (d) {
if (!api.showHosts() && d.type() === 'hostLink') {
return; // skip hidden host links
}
var line = lineSeg(d),
point = pdrop(line, mouse),
hit = lineHit(line, point, mouse),
dist;
if (hit) {
dist = mdist(point, mouse);
if (dist < minDist) {
minDist = dist;
nearest = d;
}
/*
perpData.push({
key: d.key,
x1: mouse.x,
y1: mouse.y,
x2: point.x,
y2: point.y
});
*/
}
});
/*
perps = mouseG.selectAll('line')
.data(perpData, function (d) { return d.key; })
.attr({
x1: function (d) { return d.x1; },
y1: function (d) { return d.y1; },
x2: function (d) { return d.x2; },
y2: function (d) { return d.y2; }
});
perps.enter().append('line')
.attr({
x1: function (d) { return d.x1; },
y1: function (d) { return d.y1; },
x2: function (d) { return d.x2; },
y2: function (d) { return d.y2; }
})
.style('stroke-width', 2)
.style('stroke', 'limegreen');
perps.exit().remove();
*/
enhanceNearestLink(nearest);
}
}
function enhanceNearestLink(ldata) {
// if the new link is same as old link, do nothing
if (enhancedLink && ldata && enhancedLink.key === ldata.key) return;
// first, unenhance the currently enhanced link
if (enhancedLink) {
unenhance(enhancedLink);
}
enhancedLink = ldata;
if (enhancedLink) {
enhance(enhancedLink);
}
}
function unenhance(d) {
d.el.style('stroke', '#666');
$log.debug('UN-enhancing link: ', d.key);
}
function enhance(d) {
d.el.style('stroke', 'gold');
$log.debug('enhancing link: ', d.key);
}
// ==========================
// Module definition
angular.module('ovTopo')
.factory('TopoLinkService',
['$log', 'FnService', 'SvgUtilService', 'ThemeService',
function (_$log_, _fs_, _sus_, _ts_) {
$log = _$log_;
fs = _fs_;
sus = _sus_;
ts = _ts_;
function initLink(_api_) {
api = _api_;
svg = api.svg;
network = api.network;
setupMouse(api.forceG, api.zoomer);
}
function destroyLink() {
svg.on('mouseenter', null)
.on('mouseleave', null)
.on('mousemove', null);
}
return {
initLink: initLink,
destroyLink: destroyLink
};
}]);
}());
......@@ -91,6 +91,7 @@
<script src="app/view/topo/topoFilter.js"></script>
<script src="app/view/topo/topoForce.js"></script>
<script src="app/view/topo/topoInst.js"></script>
<script src="app/view/topo/topoLink.js"></script>
<script src="app/view/topo/topoModel.js"></script>
<script src="app/view/topo/topoOblique.js"></script>
<script src="app/view/topo/topoPanel.js"></script>
......