blob: 82836a67778e18aaa009102517a0d224a2747258 [file] [log] [blame]
Matteo Scandolo9e9db122016-02-18 15:28:48 -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: '',
Matteo Scandoloe5d38702016-02-18 16:33:49 -080027 controller: function($element, $interval, XosApi, lodash, TopologyElements, NodeDrawer){
Matteo Scandolo9e9db122016-02-18 15:28:48 -080028
29 const el = $element[0];
30
Matteo Scandoloe5d38702016-02-18 16:33:49 -080031 let nodes = [];
32 let links = [];
Matteo Scandolo9e9db122016-02-18 15:28:48 -080033
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
Matteo Scandoloe5d38702016-02-18 16:33:49 -080047 const getData = () => {
48
49 nodes = TopologyElements.nodes;
50 links = TopologyElements.links;
51 console.log('-----------------------------');
52 console.log(`Fabric Links: ${links.length}`);
53
54 XosApi.Instance_List_GET()
55 .then((instances) => {
56 addBbuNodes(filterBBU(instances));
57 addOtherNodes(filterOthers(instances));
58
59 draw(svg, nodes, links);
60 })
61 .catch((e) => {
62 throw new Error(e);
63 });
64 };
Matteo Scandolo9e9db122016-02-18 15:28:48 -080065
66 const force = d3.layout.force();
67
68 // create svg elements
69 const svg = d3.select(el)
70 .append('svg')
71 .style('width', `${el.clientWidth}px`)
72 .style('height', `${el.clientHeight}px`);
73
74
75 let hStep = el.clientWidth / 3;
76 let vStep = el.clientHeight / 5;
77
78 // replace human readable ids with d3 ids
79 const buildLinks = (links, nodes) => {
Matteo Scandoloe5d38702016-02-18 16:33:49 -080080 console.log(`links: ${links.length}`);
81 return links.map((l, i) => {
Matteo Scandolo9e9db122016-02-18 15:28:48 -080082 let source = lodash.findIndex(nodes, {id: l.source});
83 let target = lodash.findIndex(nodes, {id: l.target});
84 return {
85 source: source,
86 target: target,
Matteo Scandoloe5d38702016-02-18 16:33:49 -080087 value: 1,
88 id: `link-${i++}`
Matteo Scandolo9e9db122016-02-18 15:28:48 -080089 };
90
91 });
92 };
93
94 // find fabric nodes and center horizontally
95 const positionFabricNodes = (nodes) => {
96 return lodash.map(nodes, n => {
97 if(n.type !== 'fabric'){
98 return n;
99 }
100
101 n.x = n.x * hStep;
102 n.y = n.y * vStep;
103
104 return n;
105 });
106 };
107
108 const addBbuNodes = (instances) => {
109
110 // calculate bbu hStep
111 let bbuHStep = ((el.clientWidth / 2) / (instances.length + 1));
112
113 // create nodes
114 let bbuNodes = instances.map((n, i) => {
115 return {
116 type: 'bbu',
117 name: n.name,
118 id: `bbu-${n.id}`,
119 fixed: true,
120 y: vStep * 3,
121 x: bbuHStep * (i + 1)
122 };
123 });
124
125 // create links
126 let bbuLinks = bbuNodes.map(n => {
127 return {
128 source: n.id,
129 target: 'fabric2'
130 };
131 });
132
133 // fake RRU nodes and links
134 instances.forEach((n, i) => {
135 bbuNodes.push({
136 type: 'rru',
137 name: 'rru',
138 id: `rru-${n.id}`,
139 fixed: true,
140 y: vStep * 4,
141 x: bbuHStep * (i + 1)
142 });
143
144 bbuLinks.push({
145 source: `rru-${n.id}`,
146 target: `bbu-${n.id}`
147 });
148 })
149
150 nodes = nodes.concat(bbuNodes);
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800151
152 console.log(`bbuLinks: ${bbuLinks.length}`);
153
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800154 links = links.concat(bbuLinks);
155 };
156
157 // add MME, PGW, SGW nodes
158 const addOtherNodes = (instances) => {
159 let hStep = ((el.clientWidth / 2) / (instances.length + 1));
160
161 // create nodes
162 let otherNodes = instances.map((n, i) => {
163 return {
164 type: n.name.substring(0, 3),
165 name: n.name,
166 id: `${n.name.substring(0, 3)}-${n.id}`,
167 fixed: true,
168 y: vStep * 3,
169 x: (el.clientWidth / 2) + (hStep * (i + 1))
170 };
171 });
172
173 // create links
174 let otherLinks = otherNodes.map(n => {
175 return {
176 source: n.id,
177 target: 'fabric4'
178 };
179 });
180
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800181 console.log(`otherLinks: ${otherLinks.length}`);
182
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800183 nodes = nodes.concat(otherNodes);
184 links = links.concat(otherLinks);
185 }
186
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800187 // NOTE links get duplicated
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800188 const draw = (svg, nodes, links) => {
189
190 links = buildLinks(links, nodes);
191
192 nodes = positionFabricNodes(nodes);
193
194 // start force layout
195 force
196 .nodes(nodes)
197 .links(links)
198 .size([el.clientWidth, el.clientHeight])
199 .charge(-20)
200 .chargeDistance(200)
201 .linkDistance(80)
202 .linkStrength(0.1)
203 .start();
204
205 // draw links
206 var link = svg.selectAll('.link')
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800207 .data(links, d => d.id);
208
209 link.enter().append('line')
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800210 .attr({
211 class: 'link',
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800212 id: d => d.id,
213 opacity: 0
214 })
215 .transition()
216 .duration(1000)
217 // .delay((d, i) => 50 * i)
218 .attr({
219 opacity: 1
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800220 });
221
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800222 link.exit()
223 .remove();
224
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800225 //draw nodes
226 var node = svg.selectAll('.node')
227 .data(nodes, d => {
228 return d.id
229 });
230
231 // append a group for any new node
232 var enter = node.enter()
233 .append('g', d => d.interfaceCfgIdentifier)
234 .attr({
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800235 class: d => `${d.type} node`,
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800236 transform: d => `translate(${d.x}, ${d.y})`
237 });
238
239 // draw nodes
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800240 NodeDrawer.drawBbus(enter.filter('.bbu'))
241 NodeDrawer.drawRrus(enter.filter('.rru'))
242 NodeDrawer.drawFabric(enter.filter('.fabric'))
243 NodeDrawer.drawOthers(enter.filter(d => {
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800244 return (
245 d.type === 'MME' ||
246 d.type === 'SGW' ||
247 d.type === 'PGW'
248 )
249 }));
250
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800251 // remove nodes
252 var exit = node.exit();
253
254 NodeDrawer.removeElements(exit);
255
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800256 force.on('tick', function() {
257 link
258 .attr('x1', d => d.source.x )
259 .attr('y1', d => d.source.y )
260 .attr('x2', d => d.target.x )
261 .attr('y2', d => d.target.y );
262
263 node.attr('transform', (d) => `translate(${d.x},${d.y})`);
264 });
265 };
266
Matteo Scandoloe5d38702016-02-18 16:33:49 -0800267 $interval(() => {
268 getData();
269 }, 5000);
270 getData();
271
272
Matteo Scandolo9e9db122016-02-18 15:28:48 -0800273 }
274 };
275});