GUI -- TopoView - Re-instated the oblique view function. (Keystroke 'Z').
Change-Id: I1bc4c11590660142a6bc9f5f71c06a664dbfa80b
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 4b7bc50..8a30862 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOblique.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOblique.js
@@ -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 toggleOblique() {
- $log.log("TOGGLING OBLIQUE VIEW");
+ 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;
+
+ // 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 @@
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
};
}]);