Committed by
Gerrit Code Review
GUI -- TopoView - Re-instated the oblique view function. (Keystroke 'Z').
Change-Id: I1bc4c11590660142a6bc9f5f71c06a664dbfa80b
Showing
6 changed files
with
218 additions
and
17 deletions
| ... | @@ -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 | + | ||
| 61 | + | ||
| 62 | + function planeId(tag) { | ||
| 63 | + return 'topo-obview-' + tag + 'Plane'; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + function ytfn(h, dir) { | ||
| 67 | + return h * ysc * dir * 1.1; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + function obXform(h, dir) { | ||
| 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 | + } | ||
| 38 | 78 | ||
| 39 | - // ========================== | 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); | ||
| 40 | 91 | ||
| 92 | + ox = box.x + box.width / 2; | ||
| 93 | + oy = box.y + box.height / 2; | ||
| 41 | 94 | ||
| 42 | - function toggleOblique() { | 95 | + // remember node lock state, then lock the nodes down |
| 43 | - $log.log("TOGGLING OBLIQUE VIEW"); | 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(); | ||
| 44 | } | 113 | } |
| 45 | 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()); | ||
| 184 | + } | ||
| 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 | ... | ... |
-
Please register or login to post a comment