blob: caf7b6536dbcb945098d8cd0d5858d1b35a19981 [file] [log] [blame]
Matteo Scandolodf35ca92016-02-25 09:19:41 -08001'use strict';
2
3angular.module('xos.mcordTopology', [
4 'ngResource',
5 'ngCookies',
6 'ngLodash',
7 'ui.router',
8 'xos.helpers'
9])
10.config(($stateProvider) => {
11 $stateProvider
12 .state('topology', {
13 url: '/',
14 template: '<m-cord-topology></m-cord-topology>'
15 });
16})
17.config(function($httpProvider){
18 $httpProvider.interceptors.push('NoHyperlinks');
19})
20.directive('mCordTopology', function(){
21 return {
22 restrict: 'E',
23 scope: {},
24 bindToController: true,
25 controllerAs: 'vm',
26 template: '',
27 controller: function($element, $interval, XosApi, lodash, TopologyElements, NodeDrawer){
28
29 const el = $element[0];
30
31 let nodes = [];
32 let links = [];
33
34 const filterBBU = (instances) => {
35 return lodash.filter(instances, i => i.name.indexOf('BBU') >= 0);
36 };
37
38 const filterOthers = (instances) => {
39 return lodash.filter(instances, i => {
40 return (i.name.indexOf('MME') >= 0)
41 || (i.name.indexOf('SGW') >= 0)
42 || (i.name.indexOf('PGW') >= 0)
43 });
44 };
45
46 // retrieving instances list
47 const getData = () => {
48
Matteo Scandolodab95002016-02-26 13:50:45 -080049 d3.select('svg')
50 .style('width', `${el.clientWidth}px`)
51 .style('height', `${el.clientHeight}px`);
52
Matteo Scandolodf35ca92016-02-25 09:19:41 -080053 nodes = TopologyElements.nodes;
54 links = TopologyElements.links;
55
56 XosApi.Instance_List_GET()
57 .then((instances) => {
58 addBbuNodes(filterBBU(instances));
59 addOtherNodes(filterOthers(instances));
60
61 draw(svg, nodes, links);
62 })
63 .catch((e) => {
64 throw new Error(e);
65 });
66 };
67
68 const force = d3.layout.force();
69
70 // create svg elements
71 const svg = d3.select(el)
72 .append('svg')
73 .style('width', `${el.clientWidth}px`)
74 .style('height', `${el.clientHeight}px`);
75
76 const linkContainer = svg.append('g')
77 .attr({
78 class: 'link-container'
79 });
80
81 const nodeContainer = svg.append('g')
82 .attr({
83 class: 'node-container'
84 });
85
86 // replace human readable ids with d3 ids
87 // NOTE now ids are not manatined on update...
88 const buildLinks = (links, nodes) => {
89 return links.map((l) => {
90
91
92 let source = lodash.findIndex(nodes, {id: l.source});
93 let target = lodash.findIndex(nodes, {id: l.target});
94 // console.log(`link-${source}-${target}`, source, target);
95 return {
96 source: source,
97 target: target,
98 value: 1,
99 id: `link-${source}-${target}`,
100 type: l.source.indexOf('fabric') >= 0 ? 'big':'small'
101 };
102
103 });
104 };
105
106 // find fabric nodes and center horizontally
107 const positionFabricNodes = (nodes) => {
108 return lodash.map(nodes, n => {
109 if(n.type !== 'fabric'){
110 return n;
111 }
112
113 n.x = n.x * hStep;
114 n.y = n.y * vStep;
115
116 return n;
117 });
118 };
119
120 const addBbuNodes = (instances) => {
121
122 // calculate bbu hStep
123 let bbuHStep = ((el.clientWidth / 2) / (instances.length + 1));
124
125 // create nodes
126 let bbuNodes = instances.map((n, i) => {
127 return {
128 type: 'bbu',
129 name: n.name,
130 id: `bbu-${n.id}`,
131 fixed: true,
132 y: vStep * 3,
133 x: bbuHStep * (i + 1)
134 };
135 });
136
137 // create links
138 let bbuLinks = bbuNodes.map(n => {
139 return {
140 source: n.id,
141 target: 'fabric2'
142 };
143 });
144
145 // fake RRU nodes and links
146 instances.forEach((n, i) => {
147 bbuNodes.push({
148 type: 'rru',
149 name: 'rru',
150 id: `rru-${n.id}`,
151 fixed: true,
152 y: vStep * 4,
153 x: bbuHStep * (i + 1)
154 });
155
156 bbuLinks.push({
157 source: `rru-${n.id}`,
158 target: `bbu-${n.id}`
159 });
160 })
161
162 nodes = nodes.concat(bbuNodes);
163
164
165 links = links.concat(bbuLinks);
166 };
167
168 // add MME, PGW, SGW nodes
169 const addOtherNodes = (instances) => {
170 let hStep = ((el.clientWidth / 2) / (instances.length + 1));
171
172 // create nodes
173 let otherNodes = instances.map((n, i) => {
174 return {
175 type: n.name.substring(0, 3),
176 name: n.name,
177 id: `${n.name.substring(0, 3)}-${n.id}`,
178 fixed: true,
179 y: vStep * 3,
180 x: (el.clientWidth / 2) + (hStep * (i + 1))
181 };
182 });
183
184 // create links
185 let otherLinks = otherNodes.map(n => {
186 return {
187 source: n.id,
188 target: 'fabric4'
189 };
190 });
191
192
193 nodes = nodes.concat(otherNodes);
194 links = links.concat(otherLinks);
195 }
196
197 let hStep, vStep;
198
199 hStep = el.clientWidth / 3;
200 vStep = el.clientHeight / 5;
201
202 const draw = (svg, nodes, links) => {
203
204 hStep = el.clientWidth / 3;
205 vStep = el.clientHeight / 5;
206
207 links = buildLinks(links, nodes);
208
209 nodes = positionFabricNodes(nodes);
210
211
212 // start force layout
213 force
214 .nodes(nodes)
215 .links(links)
216 .size([el.clientWidth, el.clientHeight])
217 .charge(-20)
218 .chargeDistance(200)
219 .linkDistance(80)
220 .linkStrength(0.1)
221 .start();
222
223
224 const linkContainer = d3.select('.link-container');
225 const nodeContainer = d3.select('.node-container');
226
227 NodeDrawer.drawFabricBox(nodeContainer, hStep, vStep);
228
229 // draw links
230 var link = linkContainer.selectAll('.link')
231 .data(links, d => d.id);
232
233 link.enter().append('line')
234 .attr({
235 // class: 'link',
236 id: d => d.id,
237 opacity: 0,
238 class: d => `link ${d.type}`
239 })
240 .transition()
241 .duration(1000)
242 // .delay((d, i) => 50 * i)
243 .attr({
244 opacity: 1
245 });
246
247 link.exit()
248 .remove();
249
250 //draw nodes
251 var node = nodeContainer.selectAll('.node')
252 .data(nodes, d => {
253 return d.id
254 });
255
256 // append a group for any new node
257 var enter = node.enter()
258 .append('g', d => d.interfaceCfgIdentifier)
259 .attr({
260 class: d => `${d.type} node`,
261 transform: d => `translate(${d.x}, ${d.y})`
262 });
263
264 // draw nodes
265 NodeDrawer.drawBbus(enter.filter('.bbu'))
266 NodeDrawer.drawRrus(enter.filter('.rru'))
267 NodeDrawer.drawFabric(enter.filter('.fabric'))
268 NodeDrawer.drawOthers(enter.filter(d => {
269 return (
270 d.type === 'MME' ||
271 d.type === 'SGW' ||
272 d.type === 'PGW'
273 )
274 }));
275
276 // remove nodes
277 var exit = node.exit();
278
279 NodeDrawer.removeElements(exit);
280
281 force.on('tick', function() {
282 link
283 .attr('x1', d => d.source.x )
284 .attr('y1', d => d.source.y )
285 .attr('x2', d => d.target.x )
286 .attr('y2', d => d.target.y );
287
288 node.attr('transform', (d) => `translate(${d.x},${d.y})`);
289 });
290 };
291
292 $interval(() => {
293 getData();
294 }, 5000);
295 getData();
296
297
298 }
299 };
300});