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