Simon Hunt
Committed by Gerrit Code Review

GUI -- TopoView - Re-instated the oblique view function. (Keystroke 'Z').

Change-Id: I1bc4c11590660142a6bc9f5f71c06a664dbfa80b
......@@ -204,6 +204,11 @@
return ms.loadMapInto(mapG, '*continental_us');
}
function opacifyMap(b) {
mapG.transition()
.duration(1000)
.attr('opacity', b ? 1 : 0);
}
// --- Controller Definition -----------------------------------------
......@@ -226,6 +231,8 @@
// provides function calls back into this space
showNoDevs: showNoDevs,
projection: function () { return projection; },
zoomLayer: function () { return zoomLayer; },
opacifyMap: opacifyMap,
sendEvent: _tes_.sendEvent
};
......
......@@ -117,7 +117,6 @@
return btnG ? btnG.selected : '';
}
// code to manipulate the nodes and links as per the filter settings
function inLayer(d, layer) {
var type = d.class === 'link' ? d.type() : d.type,
look = layerLookup[d.class],
......@@ -186,7 +185,8 @@
destroyFilter: destroyFilter,
clickAction: clickAction,
selected: selected
selected: selected,
inLayer: inLayer
};
}]);
}());
......
......@@ -76,7 +76,6 @@
hostLabelIndex = 0, // for host label cycling
showHosts = false, // whether hosts are displayed
showOffline = true, // whether offline devices are displayed
oblique = false, // whether we are in the oblique view
nodeLock = false, // whether nodes can be dragged or not (locked)
dim; // the dimensions of the force layout [w,h]
......@@ -965,13 +964,13 @@
// force layout tick function
function fResume() {
if (!oblique) {
if (!tos.isOblique()) {
force.resume();
}
}
function fStart() {
if (!oblique) {
if (!tos.isOblique()) {
force.start();
}
}
......@@ -1084,10 +1083,23 @@
}
}
function mkObliqueApi(uplink) {
function mkObliqueApi(uplink, fltr) {
return {
force: function() { return force; },
zoomLayer: uplink.zoomLayer,
nodeGBBox: function() { return nodeG.node().getBBox(); },
node: function () { return node; },
link: function () { return link; }
link: function () { return link; },
linkLabel: function () { return linkLabel; },
nodes: function () { return network.nodes; },
tickStuff: tickStuff,
nodeLock: function (b) {
var old = nodeLock;
nodeLock = b;
return old;
},
opacifyMap: uplink.opacifyMap,
inLayer: fltr.inLayer
};
}
......@@ -1140,7 +1152,7 @@
tms.initModel(mkModelApi(uplink), dim);
tss.initSelect(mkSelectApi(uplink));
tts.initTraffic(mkTrafficApi(uplink));
tos.initOblique(mkObliqueApi(uplink));
tos.initOblique(mkObliqueApi(uplink, fltr));
fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right'));
settings = angular.extend({}, defaultSettings, opts);
......
......@@ -24,35 +24,206 @@
'use strict';
// injected refs
var $log, fs;
var $log, fs, sus, ts;
// api to topoForce
var api;
/*
force() // get ref to force layout object
zoomLayer() // get ref to zoom layer
nodeGBBox() // get bounding box of node group layer
node() // get ref to D3 selection of nodes
link() // get ref to D3 selection of links
nodes() // get ref to network nodes array
tickStuff // ref to tick functions
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'}
*/
// configuration
var xsky = -.7, // x skew y factor
xsk = -35, // x skew angle
ysc = .5, // y scale
pad = 50,
time = 1500,
fill = {
pkt: 'rgba(130,130,170,0.3)', // blue-ish
opt: 'rgba(170,130,170,0.3)' // magenta-ish
};
// internal state
var foo;
var oblique = false,
xffn = null,
plane = {},
oldNodeLock;
function planeId(tag) {
return 'topo-obview-' + tag + 'Plane';
}
function ytfn(h, dir) {
return h * ysc * dir * 1.1;
}
function obXform(h, dir) {
var yt = ytfn(h, dir);
return sus.scale(1, ysc) + sus.translate(0, yt) + sus.skewX(xsk);
}
function noXform() {
return sus.skewX(0) + sus.translate(0,0) + sus.scale(1,1);
}
// ==========================
function padBox(box, p) {
box.x -= p;
box.y -= p;
box.width += p*2;
box.height += p*2;
}
function toObliqueView() {
var box = api.nodeGBBox(),
ox, oy;
padBox(box, pad);
ox = box.x + box.width / 2;
oy = box.y + box.height / 2;
function toggleOblique() {
$log.log("TOGGLING OBLIQUE VIEW");
// remember node lock state, then lock the nodes down
oldNodeLock = api.nodeLock(true);
api.opacifyMap(false);
insertPlanes(ox, oy);
xffn = function (xy, dir) {
var yt = ytfn(box.height, dir),
ax = xy.x - ox,
ay = xy.y - oy,
x = ax + ay * xsky,
y = (ay + yt) * ysc;
return {x: ox + x, y: oy + y};
};
showPlane('pkt', box, -1);
showPlane('opt', box, 1);
obTransitionNodes();
}
function toNormalView() {
xffn = null;
hidePlane('pkt');
hidePlane('opt');
obTransitionNodes();
removePlanes();
// restore node lock state
api.nodeLock(oldNodeLock);
api.opacifyMap(true);
}
function obTransitionNodes() {
// return the direction for the node
// -1 for pkt layer, 1 for optical layer
function dir(d) {
return api.inLayer(d, 'pkt') ? -1 : 1;
}
if (xffn) {
api.nodes().forEach(function (d) {
var oldxy = {x: d.x, y: d.y},
coords = xffn(oldxy, dir(d));
d.oldxy = oldxy;
d.px = d.x = coords.x;
d.py = d.y = coords.y;
});
} else {
api.nodes().forEach(function (d) {
var old = d.oldxy || {x: d.x, y: d.y};
d.px = d.x = old.x;
d.py = d.y = old.y;
delete d.oldxy;
});
}
api.node().transition()
.duration(time)
.attr(api.tickStuff.nodeAttr);
api.link().transition()
.duration(time)
.attr(api.tickStuff.linkAttr);
api.linkLabel().transition()
.duration(time)
.attr(api.tickStuff.linkLabelAttr);
}
function showPlane(tag, box, dir) {
// set box origin at center..
box.x = -box.width/2;
box.y = -box.height/2;
plane[tag].select('rect')
.attr(box)
.attr('opacity', 0)
.transition()
.duration(time)
.attr('opacity', 1)
.attr('transform', obXform(box.height, dir));
}
function hidePlane(tag) {
plane[tag].select('rect')
.transition()
.duration(time)
.attr('opacity', 0)
.attr('transform', noXform());
}
function insertPlanes(ox, oy) {
function ins(tag) {
var id = planeId(tag),
g = api.zoomLayer().insert('g', '#topo-G')
.attr('id', id)
.attr('transform', sus.translate(ox,oy));
g.append('rect')
.attr('fill', fill[tag])
.attr('opacity', 0);
plane[tag] = g;
}
ins('opt');
ins('pkt');
}
function removePlanes() {
function rem(tag) {
var id = planeId(tag);
api.zoomLayer().select('#'+id)
.transition()
.duration(time + 50)
.remove();
delete plane[tag];
}
rem('opt');
rem('pkt');
}
// === -----------------------------------------------------
// === MODULE DEFINITION ===
angular.module('ovTopo')
.factory('TopoObliqueService',
['$log', 'FnService',
['$log', 'FnService', 'SvgUtilService', 'ThemeService',
function (_$log_, _fs_) {
function (_$log_, _fs_, _sus_, _ts_) {
$log = _$log_;
fs = _fs_;
sus = _sus_;
ts = _ts_;
function initOblique(_api_) {
api = _api_;
......@@ -60,10 +231,21 @@ angular.module('ovTopo')
function destroyOblique() { }
function toggleOblique() {
oblique = !oblique;
if (oblique) {
api.force().stop();
toObliqueView();
} else {
toNormalView();
}
}
return {
initOblique: initOblique,
destroyOblique: destroyOblique,
isOblique: function () { return oblique; },
toggleOblique: toggleOblique
};
}]);
......
......@@ -54,7 +54,7 @@ describe('factory: view/topo/topoFilter.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(fltr, [
'initFilter', 'destroyFilter',
'clickAction', 'selected'
'clickAction', 'selected', 'inLayer',
])).toBeTruthy();
});
......
......@@ -34,7 +34,7 @@ describe('factory: view/topo/topoOblique.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(tos, [
'initOblique', 'destroyOblique', 'toggleOblique'
'initOblique', 'destroyOblique', 'isOblique', 'toggleOblique'
])).toBeTruthy();
});
......