Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 1 | /* |
Brian O'Connor | a09fe5b | 2017-08-03 21:12:30 -0700 | [diff] [blame] | 2 | * Copyright 2015-present Open Networking Foundation |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /* |
| 18 | ONOS GUI -- Topology Oblique View Module. |
| 19 | Provides functionality to view the topology as two planes (packet & optical) |
| 20 | from an oblique (side-on) perspective. |
| 21 | */ |
| 22 | |
| 23 | (function () { |
| 24 | 'use strict'; |
| 25 | |
| 26 | // injected refs |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 27 | var sus, flash; |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 28 | |
| 29 | // api to topoForce |
| 30 | var api; |
| 31 | /* |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 32 | force() // get ref to force layout object |
| 33 | zoomLayer() // get ref to zoom layer |
| 34 | nodeGBBox() // get bounding box of node group layer |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 35 | node() // get ref to D3 selection of nodes |
| 36 | link() // get ref to D3 selection of links |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 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'} |
Bri Prebilic Cole | 038aedd | 2015-07-13 15:25:16 -0700 | [diff] [blame] | 42 | calcLinkPos() // recomputes link pos based on node data |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 43 | */ |
| 44 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 45 | // configuration |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 46 | var xsky = -.7, // x skew y factor |
| 47 | xsk = -35, // x skew angle |
| 48 | ysc = .5, // y scale |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 49 | pad = 50, |
| 50 | time = 1500, |
| 51 | fill = { |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 52 | pkt: 'rgba(130,130,170,0.3)', // blue-ish |
| 53 | opt: 'rgba(170,130,170,0.3)', // magenta-ish |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 54 | }; |
| 55 | |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 56 | // internal state |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 57 | var oblique = false, |
| 58 | xffn = null, |
| 59 | plane = {}, |
| 60 | oldNodeLock; |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 61 | |
Simon Hunt | 1603c69 | 2017-08-10 19:53:35 -0700 | [diff] [blame] | 62 | // function to be replaced by the localization bundle function |
| 63 | var topoLion = function (x) { |
| 64 | return '#tobq#' + x + '#'; |
| 65 | }; |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 66 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 67 | function planeId(tag) { |
| 68 | return 'topo-obview-' + tag + 'Plane'; |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 69 | } |
| 70 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 71 | function ytfn(h, dir) { |
| 72 | return h * ysc * dir * 1.1; |
| 73 | } |
| 74 | |
| 75 | function obXform(h, dir) { |
| 76 | var yt = ytfn(h, dir); |
| 77 | return sus.scale(1, ysc) + sus.translate(0, yt) + sus.skewX(xsk); |
| 78 | } |
| 79 | |
| 80 | function noXform() { |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 81 | return sus.skewX(0) + sus.translate(0, 0) + sus.scale(1, 1); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | function padBox(box, p) { |
| 85 | box.x -= p; |
| 86 | box.y -= p; |
| 87 | box.width += p*2; |
| 88 | box.height += p*2; |
| 89 | } |
| 90 | |
| 91 | function toObliqueView() { |
| 92 | var box = api.nodeGBBox(), |
| 93 | ox, oy; |
| 94 | |
| 95 | padBox(box, pad); |
| 96 | |
| 97 | ox = box.x + box.width / 2; |
| 98 | oy = box.y + box.height / 2; |
| 99 | |
| 100 | // remember node lock state, then lock the nodes down |
| 101 | oldNodeLock = api.nodeLock(true); |
| 102 | api.opacifyMap(false); |
| 103 | |
| 104 | insertPlanes(ox, oy); |
| 105 | |
| 106 | xffn = function (xy, dir) { |
| 107 | var yt = ytfn(box.height, dir), |
| 108 | ax = xy.x - ox, |
| 109 | ay = xy.y - oy, |
| 110 | x = ax + ay * xsky, |
| 111 | y = (ay + yt) * ysc; |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 112 | return { x: ox + x, y: oy + y }; |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 113 | }; |
| 114 | |
| 115 | showPlane('pkt', box, -1); |
| 116 | showPlane('opt', box, 1); |
| 117 | obTransitionNodes(); |
| 118 | } |
| 119 | |
| 120 | function toNormalView() { |
| 121 | xffn = null; |
| 122 | |
| 123 | hidePlane('pkt'); |
| 124 | hidePlane('opt'); |
| 125 | obTransitionNodes(); |
| 126 | |
| 127 | removePlanes(); |
| 128 | |
| 129 | // restore node lock state |
| 130 | api.nodeLock(oldNodeLock); |
| 131 | api.opacifyMap(true); |
| 132 | } |
| 133 | |
| 134 | function obTransitionNodes() { |
| 135 | // return the direction for the node |
| 136 | // -1 for pkt layer, 1 for optical layer |
| 137 | function dir(d) { |
| 138 | return api.inLayer(d, 'pkt') ? -1 : 1; |
| 139 | } |
| 140 | |
| 141 | if (xffn) { |
| 142 | api.nodes().forEach(function (d) { |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 143 | var oldxy = { x: d.x, y: d.y }, |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 144 | coords = xffn(oldxy, dir(d)); |
| 145 | d.oldxy = oldxy; |
| 146 | d.px = d.x = coords.x; |
| 147 | d.py = d.y = coords.y; |
| 148 | }); |
| 149 | } else { |
| 150 | api.nodes().forEach(function (d) { |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 151 | var old = d.oldxy || { x: d.x, y: d.y }; |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 152 | d.px = d.x = old.x; |
| 153 | d.py = d.y = old.y; |
| 154 | delete d.oldxy; |
| 155 | }); |
| 156 | } |
| 157 | |
| 158 | api.node().transition() |
| 159 | .duration(time) |
| 160 | .attr(api.tickStuff.nodeAttr); |
| 161 | api.link().transition() |
| 162 | .duration(time) |
Bri Prebilic Cole | 038aedd | 2015-07-13 15:25:16 -0700 | [diff] [blame] | 163 | .call(api.calcLinkPos) |
Bri Prebilic Cole | 8040176 | 2015-07-16 11:36:18 -0700 | [diff] [blame] | 164 | .attr(api.tickStuff.linkAttr) |
| 165 | .call(api.applyNumLinkLabels); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 166 | api.linkLabel().transition() |
| 167 | .duration(time) |
| 168 | .attr(api.tickStuff.linkLabelAttr); |
| 169 | } |
| 170 | |
| 171 | function showPlane(tag, box, dir) { |
| 172 | // set box origin at center.. |
| 173 | box.x = -box.width/2; |
| 174 | box.y = -box.height/2; |
| 175 | |
| 176 | plane[tag].select('rect') |
| 177 | .attr(box) |
| 178 | .attr('opacity', 0) |
| 179 | .transition() |
| 180 | .duration(time) |
| 181 | .attr('opacity', 1) |
| 182 | .attr('transform', obXform(box.height, dir)); |
| 183 | } |
| 184 | |
| 185 | function hidePlane(tag) { |
| 186 | plane[tag].select('rect') |
| 187 | .transition() |
| 188 | .duration(time) |
| 189 | .attr('opacity', 0) |
| 190 | .attr('transform', noXform()); |
| 191 | } |
| 192 | |
| 193 | function insertPlanes(ox, oy) { |
| 194 | function ins(tag) { |
| 195 | var id = planeId(tag), |
| 196 | g = api.zoomLayer().insert('g', '#topo-G') |
| 197 | .attr('id', id) |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 198 | .attr('transform', sus.translate(ox, oy)); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 199 | g.append('rect') |
| 200 | .attr('fill', fill[tag]) |
| 201 | .attr('opacity', 0); |
| 202 | plane[tag] = g; |
| 203 | } |
| 204 | ins('opt'); |
| 205 | ins('pkt'); |
| 206 | } |
| 207 | |
| 208 | function removePlanes() { |
| 209 | function rem(tag) { |
| 210 | var id = planeId(tag); |
| 211 | api.zoomLayer().select('#'+id) |
| 212 | .transition() |
| 213 | .duration(time + 50) |
| 214 | .remove(); |
| 215 | delete plane[tag]; |
| 216 | } |
| 217 | rem('opt'); |
| 218 | rem('pkt'); |
| 219 | } |
| 220 | |
Simon Hunt | 1603c69 | 2017-08-10 19:53:35 -0700 | [diff] [blame] | 221 | // invoked after the localization bundle has been received from the server |
| 222 | function setLionBundle(bundle) { |
| 223 | topoLion = bundle; |
| 224 | } |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 225 | |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 226 | // === ----------------------------------------------------- |
| 227 | // === MODULE DEFINITION === |
| 228 | |
| 229 | angular.module('ovTopo') |
| 230 | .factory('TopoObliqueService', |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 231 | ['SvgUtilService', 'FlashService', |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 232 | |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 233 | function (_sus_, _flash_) { |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 234 | sus = _sus_; |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 235 | flash = _flash_; |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 236 | |
| 237 | function initOblique(_api_) { |
| 238 | api = _api_; |
| 239 | } |
| 240 | |
| 241 | function destroyOblique() { } |
| 242 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 243 | function toggleOblique() { |
| 244 | oblique = !oblique; |
| 245 | if (oblique) { |
| 246 | api.force().stop(); |
Simon Hunt | 1603c69 | 2017-08-10 19:53:35 -0700 | [diff] [blame] | 247 | flash.flash(topoLion('fl_oblique_view')); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 248 | toObliqueView(); |
| 249 | } else { |
Simon Hunt | 1603c69 | 2017-08-10 19:53:35 -0700 | [diff] [blame] | 250 | flash.flash(topoLion('fl_normal_view')); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 251 | toNormalView(); |
| 252 | } |
| 253 | } |
| 254 | |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 255 | return { |
| 256 | initOblique: initOblique, |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 257 | destroyOblique: destroyOblique, |
| 258 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 259 | isOblique: function () { return oblique; }, |
Steven Burrows | 1c2a968 | 2017-07-14 16:52:46 +0100 | [diff] [blame] | 260 | toggleOblique: toggleOblique, |
Simon Hunt | 1603c69 | 2017-08-10 19:53:35 -0700 | [diff] [blame] | 261 | setLionBundle: setLionBundle, |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 262 | }; |
| 263 | }]); |
| 264 | }()); |