blob: e84b1173188b756c0c22e5cd9c6cc4b48266d7bd [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)
Bri Prebilic Cole80401762015-07-16 11:36:18 -0700160 .attr(api.tickStuff.linkAttr)
161 .call(api.applyNumLinkLabels);
Simon Huntc3c5b672015-02-20 11:32:13 -0800162 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 Huntef1138d2015-02-19 17:14:03 -0800218// === -----------------------------------------------------
219// === MODULE DEFINITION ===
220
221angular.module('ovTopo')
222 .factory('TopoObliqueService',
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700223 ['$log', 'FnService', 'SvgUtilService', 'FlashService',
Simon Huntef1138d2015-02-19 17:14:03 -0800224
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700225 function (_$log_, _fs_, _sus_, _flash_) {
Simon Huntef1138d2015-02-19 17:14:03 -0800226 $log = _$log_;
227 fs = _fs_;
Simon Huntc3c5b672015-02-20 11:32:13 -0800228 sus = _sus_;
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700229 flash = _flash_;
Simon Huntef1138d2015-02-19 17:14:03 -0800230
231 function initOblique(_api_) {
232 api = _api_;
233 }
234
235 function destroyOblique() { }
236
Simon Huntc3c5b672015-02-20 11:32:13 -0800237 function toggleOblique() {
238 oblique = !oblique;
239 if (oblique) {
240 api.force().stop();
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700241 flash.flash('Oblique view');
Simon Huntc3c5b672015-02-20 11:32:13 -0800242 toObliqueView();
243 } else {
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -0700244 flash.flash('Normal view');
Simon Huntc3c5b672015-02-20 11:32:13 -0800245 toNormalView();
246 }
247 }
248
Simon Huntef1138d2015-02-19 17:14:03 -0800249 return {
250 initOblique: initOblique,
Simon Hunt96f88c62015-02-19 17:57:25 -0800251 destroyOblique: destroyOblique,
252
Simon Huntc3c5b672015-02-20 11:32:13 -0800253 isOblique: function () { return oblique; },
Simon Hunt96f88c62015-02-19 17:57:25 -0800254 toggleOblique: toggleOblique
Simon Huntef1138d2015-02-19 17:14:03 -0800255 };
256 }]);
257}());