Nokia: Putting in support for metro network services within XOS for E-CORD

Change-Id: I9277ccf808479dd593ee1b7b640a2247a5b28a39
diff --git a/views/ngXosViews/ecordTopology/src/js/eline-map.directive.js b/views/ngXosViews/ecordTopology/src/js/eline-map.directive.js
new file mode 100644
index 0000000..f93c314
--- /dev/null
+++ b/views/ngXosViews/ecordTopology/src/js/eline-map.directive.js
@@ -0,0 +1,237 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 6/28/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.ecordTopology')
+    .directive('elanMap', function(){
+      return {
+        restrict: 'E',
+        scope: {
+          elan: '='
+        },
+        bindToController: true,
+        controllerAs: 'vm',
+        template: '',
+        controller: function($element, $scope, $rootScope, $timeout,  _, cordIcons){
+          const el = $element[0];
+          var node, projection;
+          $scope.$watch(() => this.elan, (elan) => {
+            if(elan){
+              $timeout(() => {
+                draw(angular.copy(elan));
+              }, 500)
+            }
+          }, true);
+
+          // set force layout params
+          var force = d3.layout.force();
+
+          // DRAW US MAP
+          const drawMap = () => {
+            projection = d3.geo
+              // .albersUsa()
+              .mercator()
+              .center([-122.2, 37.6])
+              .scale(28000)
+              .translate([el.clientWidth / 2, el.clientHeight / 2]);
+
+            var path = d3.geo.path()
+              .projection(projection);
+
+            var map = d3.select(el).append('svg')
+              .attr('id', 'map')
+              .attr('width', el.clientWidth)
+              .attr('height', el.clientHeight);
+
+            d3.json('/js/json/bayarea.json', function(error, ba) {
+              if (error) {
+                throw new Error(error);
+              };
+
+              //bind feature data to the map
+              map.selectAll('.subunit')
+              .data(topojson.feature(ba, ba.objects.bayareaGEO).features)
+              .enter().append('path')
+              .attr('class', function(d, i) {
+                return 'subunit ' + `_${i}`;
+              })
+              .attr('d', path);
+
+
+            });
+          };
+          // END MAP
+
+          const draw = (elan) => {
+            if (!elan[0]){
+              return;
+            }
+            // set size values
+            force
+              .size([el.clientWidth, el.clientHeight])
+              .charge(-20)
+              .chargeDistance(200)
+              // .linkDistance(80)
+              .linkStrength(0.1);
+
+            // clean svg
+            angular.element(el).children().remove();
+            drawMap();
+
+            // create svg elements
+            const svg = d3.select(el)
+              .append('svg')
+              .style('width', `${el.clientWidth}px`)
+              .style('height', `${el.clientHeight}px`)
+
+
+            var nodes = [];
+            var links = [];
+            var d3id = 0;
+            var unis_i = 0;
+            var latlng_val, lat_val, lng_val;
+
+            // cicle trough E-LINE and create nodes/links
+            _.forEach(elan, (eline) => {
+
+                let isOnMap = _.find(nodes, {id: eline.uni1.pid});
+
+                if(!isOnMap){
+                  eline.uni1.fixed = true;
+                  try {
+
+                    //convert latlng value into array for eline.uni1
+                    var uni1_latlng = eline.uni1.latlng;
+                    if (typeof uni1_latlng === 'string' || uni1_latlng instanceof String){
+                        latlng_val = eline.uni1.latlng;
+                        lat_val = latlng_val.substring(1, latlng_val.indexOf(',') - 1);
+                        lat_val = lat_val.trim();
+                        lng_val = latlng_val.substring(latlng_val.indexOf(',') + 1, latlng_val.length - 1);
+                        lng_val = lng_val.trim()
+                        eline.uni1.latlng = [lat_val, lng_val];
+                    }
+
+                    let ps = projection([eline.uni1.latlng[0], eline.uni1.latlng[1]]);
+                    eline.uni1.x = ps[0];
+                    eline.uni1.y = ps[1];
+                    eline.uni1.pid = eline.uni1.pid || d3id++;
+                    nodes.push(eline.uni1)
+                  }
+                  catch(e){
+                    throw new Error(e);
+                  }
+                }
+                else {
+                  eline.uni1.pid = isOnMap.id;
+                }
+
+                isOnMap = _.find(nodes, {id: eline.uni2.pid});
+                if(!isOnMap){
+                  eline.uni2.fixed = true;
+                  try {
+
+                    //convert latlng value into array for eline.uni2
+                    var uni2_latlng = eline.uni2.latlng;
+                    if (typeof uni2_latlng === 'string' || uni2_latlng instanceof String){
+                        latlng_val = eline.uni2.latlng;
+                        lat_val = latlng_val.substring(1, latlng_val.indexOf(',') - 1);
+                        lat_val = lat_val.trim();
+                        lng_val = latlng_val.substring(latlng_val.indexOf(',') + 1, latlng_val.length - 1);
+                        lng_val = lng_val.trim()
+                        eline.uni2.latlng = [lat_val, lng_val];
+                    }
+
+                    let ps = projection([eline.uni2.latlng[0], eline.uni2.latlng[1]]);
+                    eline.uni2.x = ps[0];
+                    eline.uni2.y = ps[1];
+                    eline.uni2.pid = eline.uni2.pid || d3id++;
+                    nodes.push(eline.uni2)
+                  }
+                  catch(e){
+                    throw new Error(e);
+                  }
+                }
+                else {
+                  eline.uni2.pid = isOnMap.id;
+                }
+
+              links.push({
+                source: _.findIndex(nodes, eline.uni1),
+                target: _.findIndex(nodes, eline.uni2),
+                value: 1
+              });
+
+            });
+
+            // start force layout
+            force
+              .nodes(nodes)
+              .links(links)
+              .start();
+
+            // draw links
+            var link = svg.selectAll('.link')
+              .data(links)
+              .enter().append('line')
+              .attr({
+                class: 'link',
+              });
+
+            //draw nodes
+            node = svg.selectAll('.node')
+              .data(nodes)
+              .enter()
+              .append('g', d => d.scaEthFppUniN.interfaceCfgIdentifier)
+              .attr({
+                class: d => `node ${d.type ? d.type : 'uni'}`
+              });
+
+            node.append('rect')
+              .attr({
+                class: d => d.type ? d.type : 'uni',
+                width: 24,
+                height: 24,
+                x: -12,
+                y: -12
+              });
+
+            node.append('path')
+              .attr({
+                d: cordIcons.cordLogo,
+                transform: 'translate(-10, -10),scale(0.18)'
+              });
+
+            node.append('text')
+              .attr({
+                x: 0,
+                y: 25,
+                'text-anchor': 'middle'
+              })
+              .text(d => {
+                return d.pid
+              });
+
+
+            force.on('tick', function() {
+              link
+                .attr('x1', function(d) { return d.source.x; })
+                .attr('y1', function(d) { return d.source.y; })
+                .attr('x2', function(d) { return d.target.x; })
+                .attr('y2', function(d) { return d.target.y; });
+
+              node.attr('transform', (d) => `translate(${d.x},${d.y})`);
+            });
+          };
+
+        }
+      }
+    });
+})();
+