blob: 544482e91d0de201c73209ab68d2a433da4ddd5e [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) => {
Matteo Scandolo89667d32016-03-07 13:34:05 -080039 return TopologyElements.fakedInstance;
Matteo Scandolodf35ca92016-02-25 09:19:41 -080040 };
41
42 // retrieving instances list
43 const getData = () => {
44
Matteo Scandolodab95002016-02-26 13:50:45 -080045 d3.select('svg')
46 .style('width', `${el.clientWidth}px`)
47 .style('height', `${el.clientHeight}px`);
48
Matteo Scandolodf35ca92016-02-25 09:19:41 -080049 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 => {
Matteo Scandolo89667d32016-03-07 13:34:05 -0800265 console.log(d.type);
Matteo Scandolodf35ca92016-02-25 09:19:41 -0800266 return (
267 d.type === 'MME' ||
268 d.type === 'SGW' ||
Matteo Scandolo89667d32016-03-07 13:34:05 -0800269 d.type === 'PGW' ||
270 d.type === 'Vid'
Matteo Scandolodf35ca92016-02-25 09:19:41 -0800271 )
272 }));
273
274 // remove nodes
275 var exit = node.exit();
276
277 NodeDrawer.removeElements(exit);
278
279 force.on('tick', function() {
280 link
281 .attr('x1', d => d.source.x )
282 .attr('y1', d => d.source.y )
283 .attr('x2', d => d.target.x )
284 .attr('y2', d => d.target.y );
285
286 node.attr('transform', (d) => `translate(${d.x},${d.y})`);
287 });
288 };
289
290 $interval(() => {
291 getData();
292 }, 5000);
293 getData();
294
295
296 }
297 };
298});