Simon Hunt
Committed by Gerrit Code Review

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

Change-Id: I1bc4c11590660142a6bc9f5f71c06a664dbfa80b
...@@ -204,6 +204,11 @@ ...@@ -204,6 +204,11 @@
204 return ms.loadMapInto(mapG, '*continental_us'); 204 return ms.loadMapInto(mapG, '*continental_us');
205 } 205 }
206 206
207 + function opacifyMap(b) {
208 + mapG.transition()
209 + .duration(1000)
210 + .attr('opacity', b ? 1 : 0);
211 + }
207 212
208 // --- Controller Definition ----------------------------------------- 213 // --- Controller Definition -----------------------------------------
209 214
...@@ -226,6 +231,8 @@ ...@@ -226,6 +231,8 @@
226 // provides function calls back into this space 231 // provides function calls back into this space
227 showNoDevs: showNoDevs, 232 showNoDevs: showNoDevs,
228 projection: function () { return projection; }, 233 projection: function () { return projection; },
234 + zoomLayer: function () { return zoomLayer; },
235 + opacifyMap: opacifyMap,
229 sendEvent: _tes_.sendEvent 236 sendEvent: _tes_.sendEvent
230 }; 237 };
231 238
......
...@@ -117,7 +117,6 @@ ...@@ -117,7 +117,6 @@
117 return btnG ? btnG.selected : ''; 117 return btnG ? btnG.selected : '';
118 } 118 }
119 119
120 - // code to manipulate the nodes and links as per the filter settings
121 function inLayer(d, layer) { 120 function inLayer(d, layer) {
122 var type = d.class === 'link' ? d.type() : d.type, 121 var type = d.class === 'link' ? d.type() : d.type,
123 look = layerLookup[d.class], 122 look = layerLookup[d.class],
...@@ -186,7 +185,8 @@ ...@@ -186,7 +185,8 @@
186 destroyFilter: destroyFilter, 185 destroyFilter: destroyFilter,
187 186
188 clickAction: clickAction, 187 clickAction: clickAction,
189 - selected: selected 188 + selected: selected,
189 + inLayer: inLayer
190 }; 190 };
191 }]); 191 }]);
192 }()); 192 }());
......
...@@ -76,7 +76,6 @@ ...@@ -76,7 +76,6 @@
76 hostLabelIndex = 0, // for host label cycling 76 hostLabelIndex = 0, // for host label cycling
77 showHosts = false, // whether hosts are displayed 77 showHosts = false, // whether hosts are displayed
78 showOffline = true, // whether offline devices are displayed 78 showOffline = true, // whether offline devices are displayed
79 - oblique = false, // whether we are in the oblique view
80 nodeLock = false, // whether nodes can be dragged or not (locked) 79 nodeLock = false, // whether nodes can be dragged or not (locked)
81 dim; // the dimensions of the force layout [w,h] 80 dim; // the dimensions of the force layout [w,h]
82 81
...@@ -965,13 +964,13 @@ ...@@ -965,13 +964,13 @@
965 // force layout tick function 964 // force layout tick function
966 965
967 function fResume() { 966 function fResume() {
968 - if (!oblique) { 967 + if (!tos.isOblique()) {
969 force.resume(); 968 force.resume();
970 } 969 }
971 } 970 }
972 971
973 function fStart() { 972 function fStart() {
974 - if (!oblique) { 973 + if (!tos.isOblique()) {
975 force.start(); 974 force.start();
976 } 975 }
977 } 976 }
...@@ -1084,10 +1083,23 @@ ...@@ -1084,10 +1083,23 @@
1084 } 1083 }
1085 } 1084 }
1086 1085
1087 - function mkObliqueApi(uplink) { 1086 + function mkObliqueApi(uplink, fltr) {
1088 return { 1087 return {
1088 + force: function() { return force; },
1089 + zoomLayer: uplink.zoomLayer,
1090 + nodeGBBox: function() { return nodeG.node().getBBox(); },
1089 node: function () { return node; }, 1091 node: function () { return node; },
1090 - link: function () { return link; } 1092 + link: function () { return link; },
1093 + linkLabel: function () { return linkLabel; },
1094 + nodes: function () { return network.nodes; },
1095 + tickStuff: tickStuff,
1096 + nodeLock: function (b) {
1097 + var old = nodeLock;
1098 + nodeLock = b;
1099 + return old;
1100 + },
1101 + opacifyMap: uplink.opacifyMap,
1102 + inLayer: fltr.inLayer
1091 }; 1103 };
1092 } 1104 }
1093 1105
...@@ -1140,7 +1152,7 @@ ...@@ -1140,7 +1152,7 @@
1140 tms.initModel(mkModelApi(uplink), dim); 1152 tms.initModel(mkModelApi(uplink), dim);
1141 tss.initSelect(mkSelectApi(uplink)); 1153 tss.initSelect(mkSelectApi(uplink));
1142 tts.initTraffic(mkTrafficApi(uplink)); 1154 tts.initTraffic(mkTrafficApi(uplink));
1143 - tos.initOblique(mkObliqueApi(uplink)); 1155 + tos.initOblique(mkObliqueApi(uplink, fltr));
1144 fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right')); 1156 fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right'));
1145 1157
1146 settings = angular.extend({}, defaultSettings, opts); 1158 settings = angular.extend({}, defaultSettings, opts);
......
...@@ -24,35 +24,206 @@ ...@@ -24,35 +24,206 @@
24 'use strict'; 24 'use strict';
25 25
26 // injected refs 26 // injected refs
27 - var $log, fs; 27 + var $log, fs, sus, ts;
28 28
29 // api to topoForce 29 // api to topoForce
30 var api; 30 var api;
31 /* 31 /*
32 + force() // get ref to force layout object
33 + zoomLayer() // get ref to zoom layer
34 + nodeGBBox() // get bounding box of node group layer
32 node() // get ref to D3 selection of nodes 35 node() // get ref to D3 selection of nodes
33 link() // get ref to D3 selection of links 36 link() // get ref to D3 selection of links
37 + nodes() // get ref to network nodes array
38 + tickStuff // ref to tick functions
39 + nodeLock(b) // test-and-set nodeLock state
40 + opacifyMap(b) // show or hide map layer
41 + inLayer(d, layer) // return true if d in layer {'pkt'|'opt'}
34 */ 42 */
35 43
44 + // configuration
45 + var xsky = -.7, // x skew y factor
46 + xsk = -35, // x skew angle
47 + ysc = .5, // y scale
48 + pad = 50,
49 + time = 1500,
50 + fill = {
51 + pkt: 'rgba(130,130,170,0.3)', // blue-ish
52 + opt: 'rgba(170,130,170,0.3)' // magenta-ish
53 + };
54 +
36 // internal state 55 // internal state
37 - var foo; 56 + var oblique = false,
57 + xffn = null,
58 + plane = {},
59 + oldNodeLock;
60 +
38 61
39 - // ========================== 62 + function planeId(tag) {
63 + return 'topo-obview-' + tag + 'Plane';
64 + }
40 65
66 + function ytfn(h, dir) {
67 + return h * ysc * dir * 1.1;
68 + }
41 69
42 - function toggleOblique() { 70 + function obXform(h, dir) {
43 - $log.log("TOGGLING OBLIQUE VIEW"); 71 + var yt = ytfn(h, dir);
72 + return sus.scale(1, ysc) + sus.translate(0, yt) + sus.skewX(xsk);
73 + }
74 +
75 + function noXform() {
76 + return sus.skewX(0) + sus.translate(0,0) + sus.scale(1,1);
77 + }
78 +
79 + function padBox(box, p) {
80 + box.x -= p;
81 + box.y -= p;
82 + box.width += p*2;
83 + box.height += p*2;
84 + }
85 +
86 + function toObliqueView() {
87 + var box = api.nodeGBBox(),
88 + ox, oy;
89 +
90 + padBox(box, pad);
91 +
92 + ox = box.x + box.width / 2;
93 + oy = box.y + box.height / 2;
94 +
95 + // remember node lock state, then lock the nodes down
96 + oldNodeLock = api.nodeLock(true);
97 + api.opacifyMap(false);
98 +
99 + insertPlanes(ox, oy);
100 +
101 + xffn = function (xy, dir) {
102 + var yt = ytfn(box.height, dir),
103 + ax = xy.x - ox,
104 + ay = xy.y - oy,
105 + x = ax + ay * xsky,
106 + y = (ay + yt) * ysc;
107 + return {x: ox + x, y: oy + y};
108 + };
109 +
110 + showPlane('pkt', box, -1);
111 + showPlane('opt', box, 1);
112 + obTransitionNodes();
113 + }
114 +
115 + function toNormalView() {
116 + xffn = null;
117 +
118 + hidePlane('pkt');
119 + hidePlane('opt');
120 + obTransitionNodes();
121 +
122 + removePlanes();
123 +
124 + // restore node lock state
125 + api.nodeLock(oldNodeLock);
126 + api.opacifyMap(true);
127 + }
128 +
129 + function obTransitionNodes() {
130 + // return the direction for the node
131 + // -1 for pkt layer, 1 for optical layer
132 + function dir(d) {
133 + return api.inLayer(d, 'pkt') ? -1 : 1;
134 + }
135 +
136 + if (xffn) {
137 + api.nodes().forEach(function (d) {
138 + var oldxy = {x: d.x, y: d.y},
139 + coords = xffn(oldxy, dir(d));
140 + d.oldxy = oldxy;
141 + d.px = d.x = coords.x;
142 + d.py = d.y = coords.y;
143 + });
144 + } else {
145 + api.nodes().forEach(function (d) {
146 + var old = d.oldxy || {x: d.x, y: d.y};
147 + d.px = d.x = old.x;
148 + d.py = d.y = old.y;
149 + delete d.oldxy;
150 + });
151 + }
152 +
153 + api.node().transition()
154 + .duration(time)
155 + .attr(api.tickStuff.nodeAttr);
156 + api.link().transition()
157 + .duration(time)
158 + .attr(api.tickStuff.linkAttr);
159 + api.linkLabel().transition()
160 + .duration(time)
161 + .attr(api.tickStuff.linkLabelAttr);
162 + }
163 +
164 + function showPlane(tag, box, dir) {
165 + // set box origin at center..
166 + box.x = -box.width/2;
167 + box.y = -box.height/2;
168 +
169 + plane[tag].select('rect')
170 + .attr(box)
171 + .attr('opacity', 0)
172 + .transition()
173 + .duration(time)
174 + .attr('opacity', 1)
175 + .attr('transform', obXform(box.height, dir));
176 + }
177 +
178 + function hidePlane(tag) {
179 + plane[tag].select('rect')
180 + .transition()
181 + .duration(time)
182 + .attr('opacity', 0)
183 + .attr('transform', noXform());
44 } 184 }
45 185
186 + function insertPlanes(ox, oy) {
187 + function ins(tag) {
188 + var id = planeId(tag),
189 + g = api.zoomLayer().insert('g', '#topo-G')
190 + .attr('id', id)
191 + .attr('transform', sus.translate(ox,oy));
192 + g.append('rect')
193 + .attr('fill', fill[tag])
194 + .attr('opacity', 0);
195 + plane[tag] = g;
196 + }
197 + ins('opt');
198 + ins('pkt');
199 + }
200 +
201 + function removePlanes() {
202 + function rem(tag) {
203 + var id = planeId(tag);
204 + api.zoomLayer().select('#'+id)
205 + .transition()
206 + .duration(time + 50)
207 + .remove();
208 + delete plane[tag];
209 + }
210 + rem('opt');
211 + rem('pkt');
212 + }
213 +
214 +
46 // === ----------------------------------------------------- 215 // === -----------------------------------------------------
47 // === MODULE DEFINITION === 216 // === MODULE DEFINITION ===
48 217
49 angular.module('ovTopo') 218 angular.module('ovTopo')
50 .factory('TopoObliqueService', 219 .factory('TopoObliqueService',
51 - ['$log', 'FnService', 220 + ['$log', 'FnService', 'SvgUtilService', 'ThemeService',
52 221
53 - function (_$log_, _fs_) { 222 + function (_$log_, _fs_, _sus_, _ts_) {
54 $log = _$log_; 223 $log = _$log_;
55 fs = _fs_; 224 fs = _fs_;
225 + sus = _sus_;
226 + ts = _ts_;
56 227
57 function initOblique(_api_) { 228 function initOblique(_api_) {
58 api = _api_; 229 api = _api_;
...@@ -60,10 +231,21 @@ angular.module('ovTopo') ...@@ -60,10 +231,21 @@ angular.module('ovTopo')
60 231
61 function destroyOblique() { } 232 function destroyOblique() { }
62 233
234 + function toggleOblique() {
235 + oblique = !oblique;
236 + if (oblique) {
237 + api.force().stop();
238 + toObliqueView();
239 + } else {
240 + toNormalView();
241 + }
242 + }
243 +
63 return { 244 return {
64 initOblique: initOblique, 245 initOblique: initOblique,
65 destroyOblique: destroyOblique, 246 destroyOblique: destroyOblique,
66 247
248 + isOblique: function () { return oblique; },
67 toggleOblique: toggleOblique 249 toggleOblique: toggleOblique
68 }; 250 };
69 }]); 251 }]);
......
...@@ -54,7 +54,7 @@ describe('factory: view/topo/topoFilter.js', function() { ...@@ -54,7 +54,7 @@ describe('factory: view/topo/topoFilter.js', function() {
54 it('should define api functions', function () { 54 it('should define api functions', function () {
55 expect(fs.areFunctions(fltr, [ 55 expect(fs.areFunctions(fltr, [
56 'initFilter', 'destroyFilter', 56 'initFilter', 'destroyFilter',
57 - 'clickAction', 'selected' 57 + 'clickAction', 'selected', 'inLayer',
58 ])).toBeTruthy(); 58 ])).toBeTruthy();
59 }); 59 });
60 60
......
...@@ -34,7 +34,7 @@ describe('factory: view/topo/topoOblique.js', function() { ...@@ -34,7 +34,7 @@ describe('factory: view/topo/topoOblique.js', function() {
34 34
35 it('should define api functions', function () { 35 it('should define api functions', function () {
36 expect(fs.areFunctions(tos, [ 36 expect(fs.areFunctions(tos, [
37 - 'initOblique', 'destroyOblique', 'toggleOblique' 37 + 'initOblique', 'destroyOblique', 'isOblique', 'toggleOblique'
38 ])).toBeTruthy(); 38 ])).toBeTruthy();
39 }); 39 });
40 40
......