blob: 8889168d185eca50796b375e3d766c9f434cfe4f [file] [log] [blame]
Steven Burrows1c5c8612016-10-05 13:45:13 -05001/*
2 * Copyright 2016-present 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 Node Position Module.
19 Module that helps position nodes in the topology
20 */
21
22(function () {
23 'use strict';
24
25 // Injected vars
Steven Burrows68d6f952017-03-10 13:53:35 +000026 var rs, t2mcs, t2sls, t2bgs;
Steven Burrows1c5c8612016-10-05 13:45:13 -050027
28 // Internal state;
29 var nearDist = 15;
30
Simon Huntf27a9292017-05-04 17:36:26 -070031 function setElCoord(el, coord) {
32 el.fix(true);
33 el.x = el.px = coord[0];
34 el.y = el.py = coord[1];
35 return true;
36 }
37
Steven Burrows1c5c8612016-10-05 13:45:13 -050038 function positionNode(node, forUpdate) {
Steven Burrows68d6f952017-03-10 13:53:35 +000039
Steven Burrows1c5c8612016-10-05 13:45:13 -050040 var meta = node.get('metaUi'),
41 x = meta && meta.x,
42 y = meta && meta.y,
Simon Hunt2521d5f2017-03-20 18:17:28 -070043 hasMeta = x !== undefined && y !== undefined,
Steven Burrows1c5c8612016-10-05 13:45:13 -050044 dim = [800, 600],
45 xy;
46
Simon Hunt2521d5f2017-03-20 18:17:28 -070047 // If the node has metaUI data attached, it indicates that the user
48 // has dragged the node to a new position on the view; so we should
49 // respect that above any script-configured position...
Simon Huntf27a9292017-05-04 17:36:26 -070050 // (NOTE: This is slightly different to the "classic" topology code)
Steven Burrows68d6f952017-03-10 13:53:35 +000051
Simon Hunt2521d5f2017-03-20 18:17:28 -070052 if (hasMeta) {
53 node.fix(true);
54 node.px = node.x = x;
55 node.py = node.y = y;
56 return;
57 }
58
59 // Otherwise, use a precomputed location for peer regions, or
60 // LONG/LAT (or GRID) locations for regions/devices/hosts
61
62 if (node.nodeType === 'peer-region') {
Steven Burrows68d6f952017-03-10 13:53:35 +000063 if (t2bgs.getBackgroundType() === 'geo') {
Steven Burrowsa85a5d32017-04-10 09:46:27 -070064 setLongLat(node);
65 return true;
Steven Burrows68d6f952017-03-10 13:53:35 +000066 }
67
Simon Huntf27a9292017-05-04 17:36:26 -070068 // assumed to be grid
Simon Huntcc2d7fc2017-05-11 17:26:30 -070069 var loc = node.get('location');
70
71 // fallback to default placement if not defined.
72 if (!loc.latOrY && !loc.longOrX) {
73 loc = {
74 longOrX: -20,
75 latOrY: 10 * node.index()
76 };
77 }
Steven Burrows68d6f952017-03-10 13:53:35 +000078
Simon Huntf27a9292017-05-04 17:36:26 -070079 setElCoord(node, coordFromXY(loc));
Steven Burrows68d6f952017-03-10 13:53:35 +000080 return;
81 }
82
Steven Burrows1c5c8612016-10-05 13:45:13 -050083 // If the device contains explicit LONG/LAT data, use that to position
84 if (setLongLat(node)) {
85 // Indicate we want to update cached meta data...
86 return true;
87 }
88
Steven Burrows1c5c8612016-10-05 13:45:13 -050089 // if this is a node update (not a node add).. skip randomizer
90 if (forUpdate) {
91 return;
92 }
93
94 // Note: Placing incoming unpinned nodes at exactly the same point
95 // (center of the view) causes them to explode outwards when
96 // the force layout kicks in. So, we spread them out a bit
97 // initially, to provide a more serene layout convergence.
98 // Additionally, if the node is a host, we place it near
99 // the device it is connected to.
100
101 function rand() {
102 return {
103 x: rs.randDim(dim[0]),
104 y: rs.randDim(dim[1])
105 };
106 }
107
108 function near(node) {
109 return {
110 x: node.x + nearDist + rs.spread(nearDist),
111 y: node.y + nearDist + rs.spread(nearDist)
112 };
113 }
114
115 function getDevice(cp) {
116 return rand();
117 }
118
119 xy = (node.class === 'host') ? near(getDevice(node.cp)) : rand();
120
121 if (node.class === 'sub-region') {
122 xy = rand();
123 node.x = node.px = xy.x;
124 node.y = node.py = xy.y;
125 }
126 angular.extend(node, xy);
127 }
128
129 function setLongLat(el) {
Simon Huntf27a9292017-05-04 17:36:26 -0700130 var loc = el.get('location');
Steven Burrows1c5c8612016-10-05 13:45:13 -0500131
Simon Huntf27a9292017-05-04 17:36:26 -0700132 // bail if no location set
133 if (!loc || (loc.latOrY === 0 && loc.longOrX === 0)) {
134 return false;
Steven Burrows1c5c8612016-10-05 13:45:13 -0500135 }
Simon Huntbc30e682017-02-15 18:39:23 -0800136
Simon Huntf27a9292017-05-04 17:36:26 -0700137 if (loc.locType === 'geo') {
138 return setElCoord(el, coordFromLngLat(loc));
Steven Burrows3db5ddb2017-02-17 15:21:20 +0000139 }
Simon Huntf27a9292017-05-04 17:36:26 -0700140 if (loc.locType === 'grid') {
141 return setElCoord(el, coordFromXY(loc));
142 }
143
144 return false;
Steven Burrows1c5c8612016-10-05 13:45:13 -0500145 }
146
147 function coordFromLngLat(loc) {
148 var p = t2mcs.projection();
Simon Huntf27a9292017-05-04 17:36:26 -0700149 return p ? p([loc.longOrX, loc.latOrY]) : [0, 0];
Steven Burrows1c5c8612016-10-05 13:45:13 -0500150 }
151
Steven Burrows3db5ddb2017-02-17 15:21:20 +0000152 function coordFromXY(loc) {
Steven Burrowse8a455a2017-03-16 16:58:59 +0000153 var bgWidth = t2sls.getWidth() || 100,
154 bgHeight = t2sls.getHeight() || 100;
Steven Burrowsbd402842017-03-08 21:30:38 +0000155
Steven Burrowse8a455a2017-03-16 16:58:59 +0000156 var scale = 1000 / bgWidth,
157 yOffset = (1000 - (bgHeight * scale)) / 2;
Steven Burrows3db5ddb2017-02-17 15:21:20 +0000158
Steven Burrows11162542017-02-27 21:52:56 +0000159 // 1000 is a hardcoded HTML value of the SVG element (topo2.html)
Simon Huntf27a9292017-05-04 17:36:26 -0700160 var x = scale * loc.longOrX,
161 y = (scale * loc.latOrY) + yOffset;
Steven Burrowsb43c1a92017-03-07 17:13:28 +0000162
Steven Burrows3db5ddb2017-02-17 15:21:20 +0000163 return [x, y];
164 }
165
Steven Burrows1c5c8612016-10-05 13:45:13 -0500166 angular.module('ovTopo2')
167 .factory('Topo2NodePositionService',
Simon Hunt2521d5f2017-03-20 18:17:28 -0700168 ['RandomService', 'Topo2MapConfigService',
169 'Topo2SpriteLayerService', 'Topo2BackgroundService',
Steven Burrows68d6f952017-03-10 13:53:35 +0000170 function (_rs_, _t2mcs_, _t2sls_, _t2bgs_) {
Steven Burrows1c5c8612016-10-05 13:45:13 -0500171
172 rs = _rs_;
173 t2mcs = _t2mcs_;
Steven Burrows3db5ddb2017-02-17 15:21:20 +0000174 t2sls = _t2sls_;
Steven Burrows68d6f952017-03-10 13:53:35 +0000175 t2bgs = _t2bgs_;
Steven Burrows1c5c8612016-10-05 13:45:13 -0500176
177 return {
178 positionNode: positionNode,
179 setLongLat: setLongLat
180 };
181 }
182 ]);
183})();