Drawing a basic mCord Topology
diff --git a/views/ngXosViews/mcordTopology/src/css/dev.css b/views/ngXosViews/mcordTopology/src/css/dev.css
new file mode 100644
index 0000000..32d915d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/dev.css
@@ -0,0 +1,7 @@
+#xosMcordTopology{
+ position: absolute;
+ /*top: 100px;
+ left: 200px;*/
+ width: 100%;
+ height: 100%;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/css/mcord.css b/views/ngXosViews/mcordTopology/src/css/mcord.css
new file mode 100644
index 0000000..54854ef
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/mcord.css
@@ -0,0 +1,46 @@
+[ui-view],
+m-cord-topology{
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
+line {
+ stroke: red;
+ stroke-width: 1;
+}
+
+circle,
+rect {
+ fill: #fff;
+ stroke-width: 1;
+}
+
+.fabric {
+ stroke: green;
+}
+
+.bbu {
+ stroke: blue;
+}
+
+.bbu text {
+ font-size: 10px;
+}
+
+.rru {
+ stroke: blue;
+ fill: blue;
+}
+
+.rru-shadow {
+ fill: lightblue;
+}
+
+.MME, .SGW, .PGW {
+ stroke: purple;
+}
+
+.MME text, .SGW text, .PGW text {
+ font-size: 10px;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/index.html b/views/ngXosViews/mcordTopology/src/index.html
new file mode 100644
index 0000000..84baae5
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/index.html
@@ -0,0 +1,36 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/mcord.css">
+<!-- endinject -->
+
+<div ng-app="xos.mcordTopology" id="xosMcordTopology">
+ <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/ng-lodash/build/ng-lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/xosHelpers/src/xosHelpers.module.js"></script>
+<script src="/xosHelpers/src/services/noHyperlinks.interceptor.js"></script>
+<script src="/xosHelpers/src/services/csrfToken.interceptor.js"></script>
+<script src="/xosHelpers/src/services/api.services.js"></script>
+<script src="/api/ng-xoslib.js"></script>
+<script src="/api/ng-xos.js"></script>
+<script src="/api/ng-hpcapi.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/static.data.js"></script>
+<script src="/.tmp/bbu.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/mcordTopology/src/js/bbu.js b/views/ngXosViews/mcordTopology/src/js/bbu.js
new file mode 100644
index 0000000..1192c1d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/bbu.js
@@ -0,0 +1,60 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.service('NodeDrawer', function(){
+ this.drawBbus = (nodes) => {
+ nodes.append('circle')
+ .attr({
+ class: d => d.type,
+ r: 15
+ });
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'middle',
+ y: 4
+ })
+ .text('BBU')
+ };
+
+ this.drawRrus = (nodes) => {
+
+ nodes.append('circle')
+ .attr({
+ class: d => `${d.type}-shadow`,
+ r: 30
+ });
+
+ nodes.append('circle')
+ .attr({
+ class: d => d.type,
+ r: 10
+ });
+ };
+
+ this.drawFabric = (nodes) => {
+ nodes.append('rect')
+ .attr({
+ class: d => d.type,
+ width: 20,
+ height: 20,
+ x: -10,
+ y: -10
+ });
+ };
+
+ this.drawOthers = (nodes) => {
+ nodes.append('circle')
+ .attr({
+ class: d => d.type,
+ r: 15
+ });
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'middle',
+ y: 4
+ })
+ .text(d => d.type)
+ };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/main.js b/views/ngXosViews/mcordTopology/src/js/main.js
new file mode 100644
index 0000000..f0605c3
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/main.js
@@ -0,0 +1,237 @@
+'use strict';
+
+angular.module('xos.mcordTopology', [
+ 'ngResource',
+ 'ngCookies',
+ 'ngLodash',
+ 'ui.router',
+ 'xos.helpers'
+])
+.config(($stateProvider) => {
+ $stateProvider
+ .state('topology', {
+ url: '/',
+ template: '<m-cord-topology></m-cord-topology>'
+ });
+})
+.config(function($httpProvider){
+ $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('mCordTopology', function(){
+ return {
+ restrict: 'E',
+ scope: {},
+ bindToController: true,
+ controllerAs: 'vm',
+ template: '',
+ controller: function($element, $window, XosApi, lodash, TopologyElements, NodeDrawer){
+
+ const el = $element[0];
+
+ let nodes = TopologyElements.nodes;
+ let links = TopologyElements.links;
+
+ const filterBBU = (instances) => {
+ return lodash.filter(instances, i => i.name.indexOf('BBU') >= 0);
+ };
+
+ const filterOthers = (instances) => {
+ return lodash.filter(instances, i => {
+ return (i.name.indexOf('MME') >= 0)
+ || (i.name.indexOf('SGW') >= 0)
+ || (i.name.indexOf('PGW') >= 0)
+ });
+ };
+
+ // retrieving instances list
+ XosApi.Instance_List_GET()
+ .then((instances) => {
+ addBbuNodes(filterBBU(instances));
+ addOtherNodes(filterOthers(instances));
+ draw(svg, nodes, links);
+ })
+ .catch((e) => {
+ throw new Error(e);
+ });
+
+ const force = d3.layout.force();
+
+ // create svg elements
+ const svg = d3.select(el)
+ .append('svg')
+ .style('width', `${el.clientWidth}px`)
+ .style('height', `${el.clientHeight}px`);
+
+
+ let hStep = el.clientWidth / 3;
+ let vStep = el.clientHeight / 5;
+
+ // replace human readable ids with d3 ids
+ const buildLinks = (links, nodes) => {
+ return links.map((l) => {
+ let source = lodash.findIndex(nodes, {id: l.source});
+ let target = lodash.findIndex(nodes, {id: l.target});
+ return {
+ source: source,
+ target: target,
+ value: 1
+ };
+
+ });
+ };
+
+ // find fabric nodes and center horizontally
+ const positionFabricNodes = (nodes) => {
+ return lodash.map(nodes, n => {
+ if(n.type !== 'fabric'){
+ return n;
+ }
+
+ n.x = n.x * hStep;
+ n.y = n.y * vStep;
+
+ return n;
+ });
+ };
+
+ const addBbuNodes = (instances) => {
+
+ // calculate bbu hStep
+ let bbuHStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+ // create nodes
+ let bbuNodes = instances.map((n, i) => {
+ return {
+ type: 'bbu',
+ name: n.name,
+ id: `bbu-${n.id}`,
+ fixed: true,
+ y: vStep * 3,
+ x: bbuHStep * (i + 1)
+ };
+ });
+
+ // create links
+ let bbuLinks = bbuNodes.map(n => {
+ return {
+ source: n.id,
+ target: 'fabric2'
+ };
+ });
+
+ // fake RRU nodes and links
+ instances.forEach((n, i) => {
+ bbuNodes.push({
+ type: 'rru',
+ name: 'rru',
+ id: `rru-${n.id}`,
+ fixed: true,
+ y: vStep * 4,
+ x: bbuHStep * (i + 1)
+ });
+
+ bbuLinks.push({
+ source: `rru-${n.id}`,
+ target: `bbu-${n.id}`
+ });
+ })
+
+ nodes = nodes.concat(bbuNodes);
+ links = links.concat(bbuLinks);
+ };
+
+ // add MME, PGW, SGW nodes
+ const addOtherNodes = (instances) => {
+ let hStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+ // create nodes
+ let otherNodes = instances.map((n, i) => {
+ return {
+ type: n.name.substring(0, 3),
+ name: n.name,
+ id: `${n.name.substring(0, 3)}-${n.id}`,
+ fixed: true,
+ y: vStep * 3,
+ x: (el.clientWidth / 2) + (hStep * (i + 1))
+ };
+ });
+
+ // create links
+ let otherLinks = otherNodes.map(n => {
+ return {
+ source: n.id,
+ target: 'fabric4'
+ };
+ });
+
+ nodes = nodes.concat(otherNodes);
+ links = links.concat(otherLinks);
+ }
+
+ // NOTE nodes get dublicated
+ const draw = (svg, nodes, links) => {
+
+ links = buildLinks(links, nodes);
+
+ nodes = positionFabricNodes(nodes);
+
+ // start force layout
+ force
+ .nodes(nodes)
+ .links(links)
+ .size([el.clientWidth, el.clientHeight])
+ .charge(-20)
+ .chargeDistance(200)
+ .linkDistance(80)
+ .linkStrength(0.1)
+ .start();
+
+ // draw links
+ var link = svg.selectAll('.link')
+ .data(links)
+ .enter().append('line')
+ .attr({
+ class: 'link',
+ });
+
+ //draw nodes
+ var node = svg.selectAll('.node')
+ .data(nodes, d => {
+ return d.id
+ });
+
+ // append a group for any new node
+ var enter = node.enter()
+ .append('g', d => d.interfaceCfgIdentifier)
+ .attr({
+ class: d => d.type,
+ transform: d => `translate(${d.x}, ${d.y})`
+ });
+
+ // draw nodes
+ NodeDrawer.drawBbus(node.filter('.bbu'))
+ NodeDrawer.drawRrus(node.filter('.rru'))
+ NodeDrawer.drawFabric(node.filter('.fabric'))
+ NodeDrawer.drawOthers(node.filter(d => {
+ return (
+ d.type === 'MME' ||
+ d.type === 'SGW' ||
+ d.type === 'PGW'
+ )
+ }));
+
+ force.on('tick', function() {
+ link
+ .attr('x1', d => d.source.x )
+ .attr('y1', d => d.source.y )
+ .attr('x2', d => d.target.x )
+ .attr('y2', d => d.target.y );
+
+ node.attr('transform', (d) => `translate(${d.x},${d.y})`);
+ });
+ };
+
+ // draw(svg, TopologyElements.nodes, TopologyElements.links);
+ }
+ };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/static.data.js b/views/ngXosViews/mcordTopology/src/js/static.data.js
new file mode 100644
index 0000000..8dbca46
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/static.data.js
@@ -0,0 +1,57 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.constant('TopologyElements', {
+ nodes: [
+ {
+ id: 'fabric1',
+ type: 'fabric',
+ name: 'fabric1',
+ fixed: true,
+ x: 1,
+ y: 1
+ },
+ {
+ id: 'fabric2',
+ type: 'fabric',
+ name: 'fabric2',
+ fixed: true,
+ x: 1,
+ y: 2
+ },
+ {
+ id: 'fabric3',
+ type: 'fabric',
+ name: 'fabric3',
+ fixed: true,
+ x: 2,
+ y: 1
+ },
+ {
+ id: 'fabric4',
+ type: 'fabric',
+ name: 'fabric4',
+ fixed: true,
+ x: 2,
+ y: 2
+ }
+ ],
+ links: [
+ {
+ source: 'fabric1',
+ target: 'fabric2'
+ },
+ {
+ source: 'fabric1',
+ target: 'fabric4'
+ },
+ {
+ source: 'fabric3',
+ target: 'fabric4'
+ },
+ {
+ source: 'fabric3',
+ target: 'fabric2'
+ }
+ ]
+})
\ No newline at end of file