blob: 326271a996ebf4c2dbb7b27560e8a5a657f92ba5 [file] [log] [blame]
Simon Huntef1138d2015-02-19 17:14:03 -08001/*
2 * Copyright 2015 Open Networking Laboratory
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 Cole9cf1a8d2015-04-21 13:15:29 -070027 var $log, fs, sus, flash;
Simon Huntef1138d2015-02-19 17:14:03 -080028
29 // api to topoForce
30 var api;
31 /*
Simon Huntc3c5b672015-02-20 11:32:13 -080032 force() // get ref to force layout object
33 zoomLayer() // get ref to zoom layer
34 nodeGBBox() // get bounding box of node group layer
Simon Huntef1138d2015-02-19 17:14:03 -080035 node() // get ref to D3 selection of nodes
36 link() // get ref to D3 selection of links
Simon Huntc3c5b672015-02-20 11:32:13 -080037 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 Cole038aedd2015-07-13 15:25:16 -070042 calcLinkPos() // recomputes link pos based on node data
Simon Huntef1138d2015-02-19 17:14:03 -080043 */
44
Simon Huntc3c5b672015-02-20 11:32:13 -080045 // 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 Huntef1138d2015-02-19 17:14:03 -080056 // internal state
Simon Huntc3c5b672015-02-20 11:32:13 -080057 var oblique = false,
58 xffn = null,
59 plane = {},
60 oldNodeLock;
Simon Huntef1138d2015-02-19 17:14:03 -080061
Simon Hunt96f88c62015-02-19 17:57:25 -080062
Simon Huntc3c5b672015-02-20 11:32:13 -080063 function planeId(tag) {
64 return 'topo-obview-' + tag + 'Plane';
Simon Hunt96f88c62015-02-19 17:57:25 -080065 }
66
Simon Huntc3c5b672015-02-20 11:32:13 -080067 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 Cole038aedd2015-07-13 15:25:16 -0700159 .call(api.calcLinkPos)
Simon Huntc3c5b672015-02-20 11:32:13 -0800160 .attr(api.tickStuff.linkAttr);
161 api.linkLabel().transition()
162 .duration(time)
163 .attr(api.tickStuff.linkLabelAttr);
164 }
165
166 function showPlane(tag, box, dir) {
167 // set box origin at center..
168 box.x = -box.width/2;
169 box.y = -box.height/2;
170
171 plane[tag].select('rect')
172 .attr(box)
173 .attr('opacity', 0)
174 .transition()
175 .duration(time)
176 .attr('opacity', 1)
177 .attr('transform', obXform(box.height, dir));
178 }
179
180 function hidePlane(tag) {
181 plane[tag].select('rect')
182 .transition()
183 .duration(time)
184 .attr('opacity', 0)
185 .attr('transform', noXform());
186 }
187
188 function insertPlanes(ox, oy) {
189 function ins(tag) {
190 var id = planeId(tag),
191 g = api.zoomLayer().insert('g', '#topo-G')
192 .attr('id', id)
193 .attr('transform', sus.translate(ox,oy));
194 g.append('rect')
195 .attr('fill', fill[tag])
196 .attr('opacity', 0);
197 plane[tag] = g;
198 }
199 ins('opt');
200 ins('pkt');
201 }
202
203 function removePlanes() {
204 function rem(tag) {
205 var id = planeId(tag);
206 api.zoomLayer().select('#'+id)
207 .transition()
208 .duration(time + 50)
209 .remove();
210 delete plane[tag];
211 }
212 rem('opt');
213 rem('pkt');
214 }
215
216
Simon Huntef1138d2015-02-19 17:14:03 -0800217// === -----------------------------------------------------
218// === MODULE DEFINITION ===
219
220angular.module('ovTopo')
221 .factory('TopoObliqueService',
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700222 ['$log', 'FnService', 'SvgUtilService', 'FlashService',
Simon Huntef1138d2015-02-19 17:14:03 -0800223
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700224 function (_$log_, _fs_, _sus_, _flash_) {
Simon Huntef1138d2015-02-19 17:14:03 -0800225 $log = _$log_;
226 fs = _fs_;
Simon Huntc3c5b672015-02-20 11:32:13 -0800227 sus = _sus_;
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700228 flash = _flash_;
Simon Huntef1138d2015-02-19 17:14:03 -0800229
230 function initOblique(_api_) {
231 api = _api_;
232 }
233
234 function destroyOblique() { }
235
Simon Huntc3c5b672015-02-20 11:32:13 -0800236 function toggleOblique() {
237 oblique = !oblique;
238 if (oblique) {
239 api.force().stop();
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700240 flash.flash('Oblique view');
Simon Huntc3c5b672015-02-20 11:32:13 -0800241 toObliqueView();
242 } else {
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700243 flash.flash('Normal view');
Simon Huntc3c5b672015-02-20 11:32:13 -0800244 toNormalView();
245 }
246 }
247
Simon Huntef1138d2015-02-19 17:14:03 -0800248 return {
249 initOblique: initOblique,
Simon Hunt96f88c62015-02-19 17:57:25 -0800250 destroyOblique: destroyOblique,
251
Simon Huntc3c5b672015-02-20 11:32:13 -0800252 isOblique: function () { return oblique; },
Simon Hunt96f88c62015-02-19 17:57:25 -0800253 toggleOblique: toggleOblique
Simon Huntef1138d2015-02-19 17:14:03 -0800254 };
255 }]);
256}());