Service graph sketch
diff --git a/views/ngXosLib/bower.json b/views/ngXosLib/bower.json
index bc9c23a..228a082 100644
--- a/views/ngXosLib/bower.json
+++ b/views/ngXosLib/bower.json
@@ -21,7 +21,8 @@
     "angular-cookies": "1.4.7",
     "angular-animate": "1.4.7",
     "lodash": "~4.11.1",
-    "angular-chart.js": "~0.10.2"
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
   },
   "devDependencies": {
     "angular-mocks": "1.4.7",
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Services.js b/views/ngXosLib/xosHelpers/src/services/rest/Services.js
index a39098a..eda57e4 100644
--- a/views/ngXosLib/xosHelpers/src/services/rest/Services.js
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Services.js
@@ -4,7 +4,7 @@
   angular.module('xos.helpers')
   /**
   * @ngdoc service
-  * @name xos.helpers.Instances
+  * @name xos.helpers.Services
   * @description Angular resource to fetch /api/core/services/:id/
   **/
   .service('Services', function($resource){
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js b/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js
new file mode 100644
index 0000000..8feb102
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Tenant
+  * @description Angular resource to fetch /api/core/tenant/:id/
+  **/
+  .service('Tenants', function($resource){
+    return $resource('/api/core/tenants/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/service_graph.service.js b/views/ngXosLib/xosHelpers/src/services/service_graph.service.js
new file mode 100644
index 0000000..8a732a2
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/service_graph.service.js
@@ -0,0 +1,44 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ServiceGraph
+  * @description This factory define a set of helper function to query the service tenancy graph
+  **/
+
+  angular
+  .module('xos.helpers')
+  .service('GraphService', function($q, Tenants, Services) {
+
+    this.loadCoarseData = () => {
+
+      let services;
+
+      let deferred = $q.defer();
+
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenants.query({kind: 'coarse'}).$promise;
+      })
+      .then((tenants) => {
+        deferred.resolve({
+          tenants: tenants,
+          services: services
+        });
+      })
+
+      return deferred.promise;
+    }
+
+    this.getCoarseGraph = () => {
+      this.loadCoarseData()
+      .then((res) => {
+        console.log(res);
+      })
+      return 'ciao';
+    };
+
+  })
+})();
diff --git a/views/ngXosViews/serviceGrid/bower.json b/views/ngXosViews/serviceGrid/bower.json
index f99dc98..0cac826 100644
--- a/views/ngXosViews/serviceGrid/bower.json
+++ b/views/ngXosViews/serviceGrid/bower.json
@@ -26,6 +26,7 @@
     "angular-resource": "1.4.7",
     "lodash": "~4.11.1",
     "bootstrap-css": "3.3.6",
-    "angular-chart.js": "~0.10.2"
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.13"
   }
 }
diff --git a/views/ngXosViews/serviceGrid/src/css/main.css b/views/ngXosViews/serviceGrid/src/css/main.css
index e69de29..ae13614 100644
--- a/views/ngXosViews/serviceGrid/src/css/main.css
+++ b/views/ngXosViews/serviceGrid/src/css/main.css
@@ -0,0 +1,15 @@
+#xosServiceGrid service-graph {
+  display: block;
+  width: 100%;
+  height: 600px; }
+
+#xosServiceGrid .node {
+  stroke: #337ab7;
+  fill: white; }
+
+#xosServiceGrid .node.xos {
+  fill: #d9534f; }
+
+#xosServiceGrid .link {
+  stroke: black;
+  stroke-width: 2px; }
diff --git a/views/ngXosViews/serviceGrid/src/index.html b/views/ngXosViews/serviceGrid/src/index.html
index 2e7f92e..d9e7fec 100644
--- a/views/ngXosViews/serviceGrid/src/index.html
+++ b/views/ngXosViews/serviceGrid/src/index.html
@@ -25,6 +25,7 @@
 <script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
 <script src="vendor/Chart.js/Chart.js"></script>
 <script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
 <!-- endbower -->
 <!-- endjs -->
 <!-- inject:js -->
diff --git a/views/ngXosViews/serviceGrid/src/js/service-graph.js b/views/ngXosViews/serviceGrid/src/js/service-graph.js
index a79aae9..51a711a 100644
--- a/views/ngXosViews/serviceGrid/src/js/service-graph.js
+++ b/views/ngXosViews/serviceGrid/src/js/service-graph.js
@@ -9,8 +9,103 @@
       bindToController: true,
       controllerAs: 'vm',
       templateUrl: 'templates/service-graph.tpl.html',
-      controller: function(){
+      controller: function($element, GraphService){
 
+        let svg;
+        let el = $element[0];
+        let node;
+        let link;
+
+        const tick = (e) => {
+          // Push different nodes in different directions for clustering.
+          
+          node
+            // .attr('cx', d => d.x)
+            //   .attr('cy', d => d.y)
+              .attr({
+                transform: d => `translate(${d.x}, ${d.y})`
+              });
+          
+          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);
+        }
+
+        GraphService.loadCoarseData()
+        .then((res) => {
+
+          // build links
+          res.tenants = res.tenants.map(t => {
+            return {
+              source: t.provider_service,
+              target: t.subscriber_service
+            }
+          });
+
+          // add xos as a node
+          res.services.push({
+            name: 'XOS',
+            class: 'xos',
+            x: el.clientWidth / 2,
+            y: el.clientHeight / 2,
+            fixed: true
+          })
+
+          handleSvg(el);
+
+          var force = d3.layout.force()
+            .nodes(res.services)
+            .links(res.tenants)
+            .charge(-1060)
+            .gravity(0.1)
+            .linkDistance(200)
+            .size([el.clientWidth, el.clientHeight])
+            .on('tick', tick)
+            .start();
+
+          link = svg.selectAll('.link')
+          .data(res.tenants).enter().insert('line')
+                .attr('class', 'link');
+
+          node = svg.selectAll('.node')
+            .data(res.services)
+            .enter().append('g')
+            .call(force.drag)
+            .on("mousedown", function() { d3.event.stopPropagation(); });
+
+          node.append('circle')
+            .attr({
+              class: d => `node ${d.class || ''}`,
+              r: 10
+            });
+
+          node.append('text')
+            .attr({
+              'text-anchor': 'middle'
+            })
+            .text(d => d.name)
+
+          node.select('circle')
+            .attr({
+              r: function(d){
+                let parent = d3.select(this).node().parentNode;
+                let sib = d3.select(parent).select('text').node().getBBox()
+                return (sib.width / 2) + 10
+                
+              }
+            })
+
+        })
+
+        const handleSvg = (el) => {
+          d3.select(el).select('svg').remove();
+
+          svg = d3.select(el)
+          .append('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+        }
       }
     };
   })
diff --git a/views/ngXosViews/serviceGrid/src/sass/main.scss b/views/ngXosViews/serviceGrid/src/sass/main.scss
index 6f4bfe1..bc8d14a 100644
--- a/views/ngXosViews/serviceGrid/src/sass/main.scss
+++ b/views/ngXosViews/serviceGrid/src/sass/main.scss
@@ -1,5 +1,23 @@
 @import '../../../../style/sass/lib/_variables.scss';
 
 #xosServiceGrid {
-  
+  service-graph {
+    display: block;
+    width: 100%;
+    height: 600px;
+  }
+
+  .node {
+    stroke: $brand-primary;
+    fill: white;
+  }
+
+  .node.xos {
+    fill: $brand-danger;
+  }
+
+  .link {
+    stroke: black;
+    stroke-width: 2px;
+  }
 }
\ No newline at end of file