blob: 0d3a2acbe3d6267b55fd3cd3a7f5c87959f7e3f0 [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
26 var $log, ps, sus, gs;
27
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,
53 oiBox;
54
55
56 // ==========================
57 // *** ADD INSTANCE ***
58
59 function addInstance(data) {
60 var id = data.id;
61
62 if (onosInstances[id]) {
63 updateInstance(data);
64 return;
65 }
66 onosInstances[id] = data;
67 onosOrder.push(data);
68 updateInstances();
69 }
70
71 function updateInstance(data) {
72 var id = data.id,
73 d = onosInstances[id];
74 if (d) {
75 angular.extend(d, data);
76 updateInstances();
77 } else {
78 logicError('updateInstance: lookup fail: ID = "' + id + '"');
79 }
80 }
81
82 function computeDim(self) {
83 var css = window.getComputedStyle(self);
84 return {
85 w: sus.stripPx(css.width),
86 h: sus.stripPx(css.height)
87 };
88 }
89
90 function clickInst(d) {
91 var el = d3.select(this),
92 aff = el.classed('affinity');
93 if (!aff) {
94 setAffinity(el, d);
95 } else {
96 cancelAffinity();
97 }
98 }
99
100 function setAffinity(el, d) {
101 d3.selectAll('.onosInst')
102 .classed('mastership', true)
103 .classed('affinity', false);
104 el.classed('affinity', true);
105
106 // TODO: suppress the layers and highlight only specific nodes...
107 //suppressLayers(true);
108 //node.each(function (n) {
109 // if (n.master === d.id) {
110 // n.el.classed('suppressed', false);
111 // }
112 //});
113 oiShowMaster = true;
114 }
115
116 function cancelAffinity() {
117 d3.selectAll('.onosInst')
118 .classed('mastership affinity', false);
119
120 // TODO: restore layer state
121 //restoreLayerState();
122 oiShowMaster = false;
123 }
124
125 function instRectAttr(dim) {
126 var pad = instCfg.rectPad;
127 return {
128 x: pad,
129 y: pad,
130 width: dim.w - pad*2,
131 height: dim.h - pad*2,
132 rx: 6
133 };
134 }
135
136 function viewBox(dim) {
137 return '0 0 ' + dim.w + ' ' + dim.h;
138 }
139
140 function attachUiBadge(svg) {
141 gs.addGlyph(svg, 'uiAttached', 30, true, [12, instCfg.uiDy])
142 .classed('badgeIcon uiBadge', true);
143 }
144
145 function instColor(id, online) {
146 // TODO: fix this..
147 //return cat7.get(id, !online, network.view.getTheme());
148 return 'blue';
149 }
150
151 // ==============================
152
153 function updateInstances() {
154 var onoses = oiBox.el().selectAll('.onosInst')
155 .data(onosOrder, function (d) { return d.id; }),
156 instDim = {w:0,h:0},
157 c = instCfg;
158
159 function nSw(n) {
160 return '# Switches: ' + n;
161 }
162
163 // operate on existing onos instances if necessary
164 onoses.each(function (d) {
165 var el = d3.select(this),
166 svg = el.select('svg');
167 instDim = computeDim(this);
168
169 // update online state
170 el.classed('online', d.online);
171
172 // update ui-attached state
173 svg.select('use.uiBadge').remove();
174 if (d.uiAttached) {
175 attachUiBadge(svg);
176 }
177
178 function updAttr(id, value) {
179 svg.select('text.instLabel.'+id).text(value);
180 }
181
182 updAttr('ip', d.ip);
183 updAttr('ns', nSw(d.switches));
184 });
185
186
187 // operate on new onos instances
188 var entering = onoses.enter()
189 .append('div')
190 .attr('class', 'onosInst')
191 .classed('online', function (d) { return d.online; })
192 .on('click', clickInst);
193
194 entering.each(function (d) {
195 var el = d3.select(this),
196 rectAttr,
197 svg;
198 instDim = computeDim(this);
199 rectAttr = instRectAttr(instDim);
200
201 svg = el.append('svg').attr({
202 width: instDim.w,
203 height: instDim.h,
204 viewBox: viewBox(instDim)
205 });
206
207 svg.append('rect').attr(rectAttr);
208
209 gs.addGlyph(svg, 'bird', 28, true, [14, 14])
210 .classed('badgeIcon', true);
211
212 if (d.uiAttached) {
213 attachUiBadge(svg);
214 }
215
216 var left = c.nodeOx + c.nodeDim,
217 len = rectAttr.width - left,
218 hlen = len / 2,
219 midline = hlen + left;
220
221 // title
222 svg.append('text')
223 .attr({
224 class: 'instTitle',
225 x: midline,
226 y: c.titleDy
227 })
228 .text(d.id);
229
230 // a couple of attributes
231 var ty = c.titleDy + c.textYOff;
232
233 function addAttr(id, label) {
234 svg.append('text').attr({
235 class: 'instLabel ' + id,
236 x: midline,
237 y: ty
238 }).text(label);
239 ty += c.textYSpc;
240 }
241
242 addAttr('ip', d.ip);
243 addAttr('ns', nSw(d.switches));
244 });
245
246 // operate on existing + new onoses here
247 // set the affinity colors...
248 onoses.each(function (d) {
249 var el = d3.select(this),
250 rect = el.select('svg').select('rect'),
251 col = instColor(d.id, d.online);
252 rect.style('fill', col);
253 });
254
255 // adjust the panel size appropriately...
256 oiBox.width(instDim.w * onosOrder.length);
257 oiBox.height(instDim.h);
258
259 // remove any outgoing instances
260 onoses.exit().remove();
261 }
262
263
264 // ==========================
265
266 function logicError(msg) {
267 if (showLogicErrors) {
268 $log.warn('TopoInstService: ' + msg);
269 }
270 }
271
272 function initInst() {
273 oiBox = ps.createPanel(idIns, instOpts);
274 oiBox.show();
275
276 onosInstances = {};
277 onosOrder = [];
278 oiShowMaster = false;
279 }
280
281 function destroyInst() {
282 ps.destroyPanel(idIns);
283 oiBox = null;
284 }
285
286 // ==========================
287
288 angular.module('ovTopo')
289 .factory('TopoInstService',
290 ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
291
292 function (_$log_, _ps_, _sus_, _gs_) {
293 $log = _$log_;
294 ps = _ps_;
295 sus = _sus_;
296 gs = _gs_;
297
298 return {
299 initInst: initInst,
300 destroyInst: destroyInst,
301 addInstance: addInstance
302 };
303 }]);
304}());