blob: ee5c96c2c8f44f5c6f1ee6bc0eb137edcb63c127 [file] [log] [blame]
Simon Hunt4b668592015-01-29 17:33:53 -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 Instances Module.
19 Defines modeling of ONOS instances.
20 */
21
22(function () {
23 'use strict';
24
25 // injected refs
Simon Hunt48e61672015-01-30 14:48:25 -080026 var $log, ps, sus, gs, ts, fs;
Simon Hunt4b668592015-01-29 17:33:53 -080027
28 // configuration
29 var instCfg = {
30 rectPad: 8,
31 nodeOx: 9,
32 nodeOy: 9,
33 nodeDim: 40,
34 birdOx: 19,
35 birdOy: 21,
36 birdDim: 21,
37 uiDy: 45,
38 titleDy: 30,
39 textYOff: 20,
40 textYSpc: 15
41 },
42 showLogicErrors = true,
43 idIns = 'topo-p-instance',
44 instOpts = {
45 edge: 'left',
46 width: 20
47 };
48
49 // internal state
50 var onosInstances,
51 onosOrder,
52 oiShowMaster,
Simon Hunt245a88e2015-02-02 13:26:04 -080053 oiBox,
54 themeListener;
Simon Hunt4b668592015-01-29 17:33:53 -080055
56
57 // ==========================
58 // *** ADD INSTANCE ***
59
60 function addInstance(data) {
61 var id = data.id;
62
63 if (onosInstances[id]) {
64 updateInstance(data);
65 return;
66 }
67 onosInstances[id] = data;
68 onosOrder.push(data);
69 updateInstances();
70 }
71
72 function updateInstance(data) {
73 var id = data.id,
74 d = onosInstances[id];
75 if (d) {
76 angular.extend(d, data);
77 updateInstances();
78 } else {
79 logicError('updateInstance: lookup fail: ID = "' + id + '"');
80 }
81 }
82
Simon Hunt48e61672015-01-30 14:48:25 -080083 function removeInstance(data) {
84 var id = data.id,
85 d = onosInstances[id];
86 if (d) {
87 var idx = fs.find(id, onosOrder);
88 if (idx >= 0) {
89 onosOrder.splice(idx, 1);
90 }
91 delete onosInstances[id];
92 updateInstances();
93 } else {
94 logicError('removeInstance lookup fail. ID = "' + id + '"');
95 }
96 }
97
98 // ==========================
99
Simon Hunt4b668592015-01-29 17:33:53 -0800100 function computeDim(self) {
101 var css = window.getComputedStyle(self);
102 return {
103 w: sus.stripPx(css.width),
104 h: sus.stripPx(css.height)
105 };
106 }
107
108 function clickInst(d) {
109 var el = d3.select(this),
110 aff = el.classed('affinity');
111 if (!aff) {
112 setAffinity(el, d);
113 } else {
114 cancelAffinity();
115 }
116 }
117
118 function setAffinity(el, d) {
119 d3.selectAll('.onosInst')
120 .classed('mastership', true)
121 .classed('affinity', false);
122 el.classed('affinity', true);
123
124 // TODO: suppress the layers and highlight only specific nodes...
125 //suppressLayers(true);
126 //node.each(function (n) {
127 // if (n.master === d.id) {
128 // n.el.classed('suppressed', false);
129 // }
130 //});
131 oiShowMaster = true;
132 }
133
134 function cancelAffinity() {
135 d3.selectAll('.onosInst')
136 .classed('mastership affinity', false);
137
138 // TODO: restore layer state
139 //restoreLayerState();
140 oiShowMaster = false;
141 }
142
143 function instRectAttr(dim) {
144 var pad = instCfg.rectPad;
145 return {
146 x: pad,
147 y: pad,
148 width: dim.w - pad*2,
149 height: dim.h - pad*2,
150 rx: 6
151 };
152 }
153
154 function viewBox(dim) {
155 return '0 0 ' + dim.w + ' ' + dim.h;
156 }
157
158 function attachUiBadge(svg) {
159 gs.addGlyph(svg, 'uiAttached', 30, true, [12, instCfg.uiDy])
160 .classed('badgeIcon uiBadge', true);
161 }
162
163 function instColor(id, online) {
Simon Hunt48e61672015-01-30 14:48:25 -0800164 return sus.cat7().getColor(id, !online, ts.theme());
Simon Hunt4b668592015-01-29 17:33:53 -0800165 }
166
167 // ==============================
168
169 function updateInstances() {
170 var onoses = oiBox.el().selectAll('.onosInst')
171 .data(onosOrder, function (d) { return d.id; }),
172 instDim = {w:0,h:0},
173 c = instCfg;
174
175 function nSw(n) {
176 return '# Switches: ' + n;
177 }
178
179 // operate on existing onos instances if necessary
180 onoses.each(function (d) {
181 var el = d3.select(this),
182 svg = el.select('svg');
183 instDim = computeDim(this);
184
185 // update online state
186 el.classed('online', d.online);
187
188 // update ui-attached state
189 svg.select('use.uiBadge').remove();
190 if (d.uiAttached) {
191 attachUiBadge(svg);
192 }
193
194 function updAttr(id, value) {
195 svg.select('text.instLabel.'+id).text(value);
196 }
197
198 updAttr('ip', d.ip);
199 updAttr('ns', nSw(d.switches));
200 });
201
202
203 // operate on new onos instances
204 var entering = onoses.enter()
205 .append('div')
206 .attr('class', 'onosInst')
207 .classed('online', function (d) { return d.online; })
208 .on('click', clickInst);
209
210 entering.each(function (d) {
211 var el = d3.select(this),
212 rectAttr,
213 svg;
214 instDim = computeDim(this);
215 rectAttr = instRectAttr(instDim);
216
217 svg = el.append('svg').attr({
218 width: instDim.w,
219 height: instDim.h,
220 viewBox: viewBox(instDim)
221 });
222
223 svg.append('rect').attr(rectAttr);
224
225 gs.addGlyph(svg, 'bird', 28, true, [14, 14])
226 .classed('badgeIcon', true);
227
228 if (d.uiAttached) {
229 attachUiBadge(svg);
230 }
231
232 var left = c.nodeOx + c.nodeDim,
233 len = rectAttr.width - left,
234 hlen = len / 2,
235 midline = hlen + left;
236
237 // title
238 svg.append('text')
239 .attr({
240 class: 'instTitle',
241 x: midline,
242 y: c.titleDy
243 })
244 .text(d.id);
245
246 // a couple of attributes
247 var ty = c.titleDy + c.textYOff;
248
249 function addAttr(id, label) {
250 svg.append('text').attr({
251 class: 'instLabel ' + id,
252 x: midline,
253 y: ty
254 }).text(label);
255 ty += c.textYSpc;
256 }
257
258 addAttr('ip', d.ip);
259 addAttr('ns', nSw(d.switches));
260 });
261
262 // operate on existing + new onoses here
263 // set the affinity colors...
264 onoses.each(function (d) {
265 var el = d3.select(this),
266 rect = el.select('svg').select('rect'),
267 col = instColor(d.id, d.online);
268 rect.style('fill', col);
269 });
270
271 // adjust the panel size appropriately...
272 oiBox.width(instDim.w * onosOrder.length);
273 oiBox.height(instDim.h);
274
275 // remove any outgoing instances
276 onoses.exit().remove();
277 }
278
279
280 // ==========================
281
282 function logicError(msg) {
283 if (showLogicErrors) {
284 $log.warn('TopoInstService: ' + msg);
285 }
286 }
287
288 function initInst() {
289 oiBox = ps.createPanel(idIns, instOpts);
290 oiBox.show();
291
292 onosInstances = {};
293 onosOrder = [];
294 oiShowMaster = false;
Simon Hunt245a88e2015-02-02 13:26:04 -0800295
296 // we want to update the instances, each time the theme changes
297 themeListener = ts.addListener(updateInstances);
Simon Hunt4b668592015-01-29 17:33:53 -0800298 }
299
300 function destroyInst() {
Simon Hunt245a88e2015-02-02 13:26:04 -0800301 ts.removeListener(themeListener);
302 themeListener = null;
303
Simon Hunt4b668592015-01-29 17:33:53 -0800304 ps.destroyPanel(idIns);
305 oiBox = null;
306 }
307
308 // ==========================
309
310 angular.module('ovTopo')
311 .factory('TopoInstService',
312 ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
Simon Hunt48e61672015-01-30 14:48:25 -0800313 'ThemeService', 'FnService',
Simon Hunt4b668592015-01-29 17:33:53 -0800314
Simon Hunt48e61672015-01-30 14:48:25 -0800315 function (_$log_, _ps_, _sus_, _gs_, _ts_, _fs_) {
Simon Hunt4b668592015-01-29 17:33:53 -0800316 $log = _$log_;
317 ps = _ps_;
318 sus = _sus_;
319 gs = _gs_;
Simon Hunt48e61672015-01-30 14:48:25 -0800320 ts = _ts_;
321 fs = _fs_;
Simon Hunt4b668592015-01-29 17:33:53 -0800322
323 return {
324 initInst: initInst,
325 destroyInst: destroyInst,
Simon Hunt1894d792015-02-04 17:09:20 -0800326
Simon Hunt48e61672015-01-30 14:48:25 -0800327 addInstance: addInstance,
328 updateInstance: updateInstance,
Simon Huntac4c6f72015-02-03 19:50:53 -0800329 removeInstance: removeInstance,
Simon Hunt1894d792015-02-04 17:09:20 -0800330
Simon Huntac4c6f72015-02-03 19:50:53 -0800331 isVisible: function () { return oiBox.isVisible(); },
332 show: function () { oiBox.show(); },
333 hide: function () { oiBox.hide(); }
Simon Hunt4b668592015-01-29 17:33:53 -0800334 };
335 }]);
336}());