blob: 015fbdde79ec9bf250b59e4adb1f25cac6f2e665 [file] [log] [blame]
Simon Hunt3a6eec02015-02-09 21:16:43 -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 Model Module.
19 Auxiliary functions for the model of the topology; that is, our internal
20 representations of devices, hosts, links, etc.
21 */
22
23(function () {
24 'use strict';
25
26 // injected refs
27 var $log, fs, rnd, api;
28
29 var dim; // dimensions of layout, as [w,h]
30
31 // configuration 'constants'
32 var defaultLinkType = 'direct',
33 nearDist = 15;
34
35
36 function coordFromLngLat(loc) {
37 var p = api.projection();
38 return p ? p([loc.lng, loc.lat]) : [0, 0];
39 }
40
41 function lngLatFromCoord(coord) {
42 var p = api.projection();
43 return p ? p.invert(coord) : [0, 0];
44 }
45
46 function positionNode(node, forUpdate) {
47 var meta = node.metaUi,
48 x = meta && meta.x,
49 y = meta && meta.y,
50 xy;
51
52 // If we have [x,y] already, use that...
53 if (x && y) {
54 node.fixed = true;
55 node.px = node.x = x;
56 node.py = node.y = y;
57 return;
58 }
59
60 var location = node.location,
61 coord;
62
63 if (location && location.type === 'latlng') {
64 coord = coordFromLngLat(location);
65 node.fixed = true;
66 node.px = node.x = coord[0];
67 node.py = node.y = coord[1];
68 return true;
69 }
70
71 // if this is a node update (not a node add).. skip randomizer
72 if (forUpdate) {
73 return;
74 }
75
76 // Note: Placing incoming unpinned nodes at exactly the same point
77 // (center of the view) causes them to explode outwards when
78 // the force layout kicks in. So, we spread them out a bit
79 // initially, to provide a more serene layout convergence.
80 // Additionally, if the node is a host, we place it near
81 // the device it is connected to.
82
83 function rand() {
84 return {
85 x: rnd.randDim(dim[0]),
86 y: rnd.randDim(dim[1])
87 };
88 }
89
90 function near(node) {
91 return {
92 x: node.x + nearDist + rnd.spread(nearDist),
93 y: node.y + nearDist + rnd.spread(nearDist)
94 };
95 }
96
97 function getDevice(cp) {
98 var d = api.lookup[cp.device];
99 return d || rand();
100 }
101
102 xy = (node.class === 'host') ? near(getDevice(node.cp)) : rand();
103 angular.extend(node, xy);
104 }
105
106 function mkSvgCls(dh, t, on) {
107 var ndh = 'node ' + dh,
108 ndht = t ? ndh + ' ' + t : ndh;
109 return on ? ndht + ' online' : ndht;
110 }
111
112 function createDeviceNode(device) {
113 var node = device;
114
115 // Augment as needed...
116 node.class = 'device';
117 node.svgClass = mkSvgCls('device', device.type, device.online);
118 positionNode(node);
119 return node;
120 }
121
122 function createHostNode(host) {
123 var node = host;
124
125 // Augment as needed...
126 node.class = 'host';
127 if (!node.type) {
128 node.type = 'endstation';
129 }
130 node.svgClass = mkSvgCls('host', node.type);
131 positionNode(node);
132 return node;
133 }
134
135 function createHostLink(host) {
136 var src = host.id,
137 dst = host.cp.device,
138 id = host.ingress,
139 lnk = linkEndPoints(src, dst);
140
141 if (!lnk) {
142 return null;
143 }
144
145 // Synthesize link ...
146 angular.extend(lnk, {
147 key: id,
148 class: 'link',
149
150 type: function () { return 'hostLink'; },
151 online: function () {
152 // hostlink target is edge switch
153 return lnk.target.online;
154 },
155 linkWidth: function () { return 1; }
156 });
157 return lnk;
158 }
159
160 function createLink(link) {
161 var lnk = linkEndPoints(link.src, link.dst);
162
163 if (!lnk) {
164 return null;
165 }
166
167 angular.extend(lnk, {
168 key: link.id,
169 class: 'link',
170 fromSource: link,
171
172 // functions to aggregate dual link state
173 type: function () {
174 var s = lnk.fromSource,
175 t = lnk.fromTarget;
176 return (s && s.type) || (t && t.type) || defaultLinkType;
177 },
178 online: function () {
179 var s = lnk.fromSource,
180 t = lnk.fromTarget,
181 both = lnk.source.online && lnk.target.online;
182 return both && ((s && s.online) || (t && t.online));
183 },
184 linkWidth: function () {
185 var s = lnk.fromSource,
186 t = lnk.fromTarget,
187 ws = (s && s.linkWidth) || 0,
188 wt = (t && t.linkWidth) || 0;
189 return Math.max(ws, wt);
190 }
191 });
192 return lnk;
193 }
194
195
196 function linkEndPoints(srcId, dstId) {
197 var srcNode = api.lookup[srcId],
198 dstNode = api.lookup[dstId],
199 sMiss = !srcNode ? missMsg('src', srcId) : '',
200 dMiss = !dstNode ? missMsg('dst', dstId) : '';
201
202 if (sMiss || dMiss) {
203 $log.error('Node(s) not on map for link:' + sMiss + dMiss);
204 //logicError('Node(s) not on map for link:\n' + sMiss + dMiss);
205 return null;
206 }
207 return {
208 source: srcNode,
209 target: dstNode,
210 x1: srcNode.x,
211 y1: srcNode.y,
212 x2: dstNode.x,
213 y2: dstNode.y
214 };
215 }
216
217 function missMsg(what, id) {
218 return '\n[' + what + '] "' + id + '" missing';
219 }
220
221 // ==========================
222 // Module definition
223
224 angular.module('ovTopo')
225 .factory('TopoModelService',
226 ['$log', 'FnService', 'RandomService',
227
228 function (_$log_, _fs_, _rnd_) {
229 $log = _$log_;
230 fs = _fs_;
231 rnd = _rnd_;
232
233 function initModel(_api_, _dim_) {
234 api = _api_;
235 dim = _dim_;
236 }
237
238 function newDim(_dim_) {
239 dim = _dim_;
240 }
241
242 return {
243 initModel: initModel,
244 newDim: newDim,
245
246 positionNode: positionNode,
247 createDeviceNode: createDeviceNode,
248 createHostNode: createHostNode,
249 createHostLink: createHostLink,
250 createLink: createLink,
251 coordFromLngLat: coordFromLngLat,
252 lngLatFromCoord: lngLatFromCoord,
253 }
254 }]);
255}());