blob: a5053688cc4f599f0a7209f0c8a99c1a0a3c0dd7 [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
Simon Hunt2bfbad22015-02-20 11:57:11 -080027 var $log, fs, sus;
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'}
Simon Huntef1138d2015-02-19 17:14:03 -080042 */
43
Simon Huntc3c5b672015-02-20 11:32:13 -080044 // 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
Simon Huntef1138d2015-02-19 17:14:03 -080055 // internal state
Simon Huntc3c5b672015-02-20 11:32:13 -080056 var oblique = false,
57 xffn = null,
58 plane = {},
59 oldNodeLock;
Simon Huntef1138d2015-02-19 17:14:03 -080060
Simon Hunt96f88c62015-02-19 17:57:25 -080061
Simon Huntc3c5b672015-02-20 11:32:13 -080062 function planeId(tag) {
63 return 'topo-obview-' + tag + 'Plane';
Simon Hunt96f88c62015-02-19 17:57:25 -080064 }
65
Simon Huntc3c5b672015-02-20 11:32:13 -080066 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 }
78
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);
91
92 ox = box.x + box.width / 2;
93 oy = box.y + box.height / 2;
94
95 // remember node lock state, then lock the nodes down
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();
113 }
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
Simon Huntef1138d2015-02-19 17:14:03 -0800215// === -----------------------------------------------------
216// === MODULE DEFINITION ===
217
218angular.module('ovTopo')
219 .factory('TopoObliqueService',
Simon Hunt2bfbad22015-02-20 11:57:11 -0800220 ['$log', 'FnService', 'SvgUtilService',
Simon Huntef1138d2015-02-19 17:14:03 -0800221
Simon Hunt2bfbad22015-02-20 11:57:11 -0800222 function (_$log_, _fs_, _sus_) {
Simon Huntef1138d2015-02-19 17:14:03 -0800223 $log = _$log_;
224 fs = _fs_;
Simon Huntc3c5b672015-02-20 11:32:13 -0800225 sus = _sus_;
Simon Huntef1138d2015-02-19 17:14:03 -0800226
227 function initOblique(_api_) {
228 api = _api_;
229 }
230
231 function destroyOblique() { }
232
Simon Huntc3c5b672015-02-20 11:32:13 -0800233 function toggleOblique() {
234 oblique = !oblique;
235 if (oblique) {
236 api.force().stop();
237 toObliqueView();
238 } else {
239 toNormalView();
240 }
241 }
242
Simon Huntef1138d2015-02-19 17:14:03 -0800243 return {
244 initOblique: initOblique,
Simon Hunt96f88c62015-02-19 17:57:25 -0800245 destroyOblique: destroyOblique,
246
Simon Huntc3c5b672015-02-20 11:32:13 -0800247 isOblique: function () { return oblique; },
Simon Hunt96f88c62015-02-19 17:57:25 -0800248 toggleOblique: toggleOblique
Simon Huntef1138d2015-02-19 17:14:03 -0800249 };
250 }]);
251}());