Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 1 | /* |
Brian O'Connor | 5ab426f | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2015-present Open Networking Laboratory |
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 |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 27 | var $log, fs, 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 |
| 46 | var xsky = -.7, // x skew y factor |
| 47 | xsk = -35, // x skew angle |
| 48 | ysc = .5, // y scale |
| 49 | pad = 50, |
| 50 | time = 1500, |
| 51 | fill = { |
| 52 | pkt: 'rgba(130,130,170,0.3)', // blue-ish |
| 53 | opt: 'rgba(170,130,170,0.3)' // magenta-ish |
| 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 | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 62 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 63 | function planeId(tag) { |
| 64 | return 'topo-obview-' + tag + 'Plane'; |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 65 | } |
| 66 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 67 | function ytfn(h, dir) { |
| 68 | return h * ysc * dir * 1.1; |
| 69 | } |
| 70 | |
| 71 | function obXform(h, dir) { |
| 72 | var yt = ytfn(h, dir); |
| 73 | return sus.scale(1, ysc) + sus.translate(0, yt) + sus.skewX(xsk); |
| 74 | } |
| 75 | |
| 76 | function noXform() { |
| 77 | return sus.skewX(0) + sus.translate(0,0) + sus.scale(1,1); |
| 78 | } |
| 79 | |
| 80 | function padBox(box, p) { |
| 81 | box.x -= p; |
| 82 | box.y -= p; |
| 83 | box.width += p*2; |
| 84 | box.height += p*2; |
| 85 | } |
| 86 | |
| 87 | function toObliqueView() { |
| 88 | var box = api.nodeGBBox(), |
| 89 | ox, oy; |
| 90 | |
| 91 | padBox(box, pad); |
| 92 | |
| 93 | ox = box.x + box.width / 2; |
| 94 | oy = box.y + box.height / 2; |
| 95 | |
| 96 | // remember node lock state, then lock the nodes down |
| 97 | oldNodeLock = api.nodeLock(true); |
| 98 | api.opacifyMap(false); |
| 99 | |
| 100 | insertPlanes(ox, oy); |
| 101 | |
| 102 | xffn = function (xy, dir) { |
| 103 | var yt = ytfn(box.height, dir), |
| 104 | ax = xy.x - ox, |
| 105 | ay = xy.y - oy, |
| 106 | x = ax + ay * xsky, |
| 107 | y = (ay + yt) * ysc; |
| 108 | return {x: ox + x, y: oy + y}; |
| 109 | }; |
| 110 | |
| 111 | showPlane('pkt', box, -1); |
| 112 | showPlane('opt', box, 1); |
| 113 | obTransitionNodes(); |
| 114 | } |
| 115 | |
| 116 | function toNormalView() { |
| 117 | xffn = null; |
| 118 | |
| 119 | hidePlane('pkt'); |
| 120 | hidePlane('opt'); |
| 121 | obTransitionNodes(); |
| 122 | |
| 123 | removePlanes(); |
| 124 | |
| 125 | // restore node lock state |
| 126 | api.nodeLock(oldNodeLock); |
| 127 | api.opacifyMap(true); |
| 128 | } |
| 129 | |
| 130 | function obTransitionNodes() { |
| 131 | // return the direction for the node |
| 132 | // -1 for pkt layer, 1 for optical layer |
| 133 | function dir(d) { |
| 134 | return api.inLayer(d, 'pkt') ? -1 : 1; |
| 135 | } |
| 136 | |
| 137 | if (xffn) { |
| 138 | api.nodes().forEach(function (d) { |
| 139 | var oldxy = {x: d.x, y: d.y}, |
| 140 | coords = xffn(oldxy, dir(d)); |
| 141 | d.oldxy = oldxy; |
| 142 | d.px = d.x = coords.x; |
| 143 | d.py = d.y = coords.y; |
| 144 | }); |
| 145 | } else { |
| 146 | api.nodes().forEach(function (d) { |
| 147 | var old = d.oldxy || {x: d.x, y: d.y}; |
| 148 | d.px = d.x = old.x; |
| 149 | d.py = d.y = old.y; |
| 150 | delete d.oldxy; |
| 151 | }); |
| 152 | } |
| 153 | |
| 154 | api.node().transition() |
| 155 | .duration(time) |
| 156 | .attr(api.tickStuff.nodeAttr); |
| 157 | api.link().transition() |
| 158 | .duration(time) |
Bri Prebilic Cole | 038aedd | 2015-07-13 15:25:16 -0700 | [diff] [blame] | 159 | .call(api.calcLinkPos) |
Bri Prebilic Cole | 8040176 | 2015-07-16 11:36:18 -0700 | [diff] [blame] | 160 | .attr(api.tickStuff.linkAttr) |
| 161 | .call(api.applyNumLinkLabels); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 162 | api.linkLabel().transition() |
| 163 | .duration(time) |
| 164 | .attr(api.tickStuff.linkLabelAttr); |
| 165 | } |
| 166 | |
| 167 | function showPlane(tag, box, dir) { |
| 168 | // set box origin at center.. |
| 169 | box.x = -box.width/2; |
| 170 | box.y = -box.height/2; |
| 171 | |
| 172 | plane[tag].select('rect') |
| 173 | .attr(box) |
| 174 | .attr('opacity', 0) |
| 175 | .transition() |
| 176 | .duration(time) |
| 177 | .attr('opacity', 1) |
| 178 | .attr('transform', obXform(box.height, dir)); |
| 179 | } |
| 180 | |
| 181 | function hidePlane(tag) { |
| 182 | plane[tag].select('rect') |
| 183 | .transition() |
| 184 | .duration(time) |
| 185 | .attr('opacity', 0) |
| 186 | .attr('transform', noXform()); |
| 187 | } |
| 188 | |
| 189 | function insertPlanes(ox, oy) { |
| 190 | function ins(tag) { |
| 191 | var id = planeId(tag), |
| 192 | g = api.zoomLayer().insert('g', '#topo-G') |
| 193 | .attr('id', id) |
| 194 | .attr('transform', sus.translate(ox,oy)); |
| 195 | g.append('rect') |
| 196 | .attr('fill', fill[tag]) |
| 197 | .attr('opacity', 0); |
| 198 | plane[tag] = g; |
| 199 | } |
| 200 | ins('opt'); |
| 201 | ins('pkt'); |
| 202 | } |
| 203 | |
| 204 | function removePlanes() { |
| 205 | function rem(tag) { |
| 206 | var id = planeId(tag); |
| 207 | api.zoomLayer().select('#'+id) |
| 208 | .transition() |
| 209 | .duration(time + 50) |
| 210 | .remove(); |
| 211 | delete plane[tag]; |
| 212 | } |
| 213 | rem('opt'); |
| 214 | rem('pkt'); |
| 215 | } |
| 216 | |
| 217 | |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 218 | // === ----------------------------------------------------- |
| 219 | // === MODULE DEFINITION === |
| 220 | |
| 221 | angular.module('ovTopo') |
| 222 | .factory('TopoObliqueService', |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 223 | ['$log', 'FnService', 'SvgUtilService', 'FlashService', |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 224 | |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 225 | function (_$log_, _fs_, _sus_, _flash_) { |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 226 | $log = _$log_; |
| 227 | fs = _fs_; |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 228 | sus = _sus_; |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 229 | flash = _flash_; |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 230 | |
| 231 | function initOblique(_api_) { |
| 232 | api = _api_; |
| 233 | } |
| 234 | |
| 235 | function destroyOblique() { } |
| 236 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 237 | function toggleOblique() { |
| 238 | oblique = !oblique; |
| 239 | if (oblique) { |
| 240 | api.force().stop(); |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 241 | flash.flash('Oblique view'); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 242 | toObliqueView(); |
| 243 | } else { |
Bri Prebilic Cole | 9cf1a8d | 2015-04-21 13:15:29 -0700 | [diff] [blame] | 244 | flash.flash('Normal view'); |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 245 | toNormalView(); |
| 246 | } |
| 247 | } |
| 248 | |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 249 | return { |
| 250 | initOblique: initOblique, |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 251 | destroyOblique: destroyOblique, |
| 252 | |
Simon Hunt | c3c5b67 | 2015-02-20 11:32:13 -0800 | [diff] [blame] | 253 | isOblique: function () { return oblique; }, |
Simon Hunt | 96f88c6 | 2015-02-19 17:57:25 -0800 | [diff] [blame] | 254 | toggleOblique: toggleOblique |
Simon Hunt | ef1138d | 2015-02-19 17:14:03 -0800 | [diff] [blame] | 255 | }; |
| 256 | }]); |
| 257 | }()); |