Service graph sketch
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