Animating Rack
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopology.js b/views/ngXosViews/diagnostic/src/js/logicTopology.js
index afe61a8..9d02829 100644
--- a/views/ngXosViews/diagnostic/src/js/logicTopology.js
+++ b/views/ngXosViews/diagnostic/src/js/logicTopology.js
@@ -11,7 +11,7 @@
       bindToController: true,
       controllerAs: 'vm',
       template: '',
-      controller: function($element, $log, $scope, d3, LogicTopologyHelper){
+      controller: function($element, $log, $scope, d3, LogicTopologyHelper, Node){
         $log.info('Logic Plane');
 
         var svg;
@@ -28,10 +28,14 @@
         $scope.$watch(() => this.subscribers, (subscribers) => {
           if(subscribers){
 
-            // TODO
-            // build here the full data structure
+            LogicTopologyHelper.addSubscribers(angular.copy(subscribers));
 
-            LogicTopologyHelper.addSubscribers(svg, angular.copy(subscribers));
+            Node.queryWithInstances().$promise
+            .then((computeNodes) => {
+              LogicTopologyHelper.addComputeNodes(computeNodes);
+              LogicTopologyHelper.updateTree(svg);
+            });
+            
           }
         });
 
@@ -42,7 +46,7 @@
         });
 
         handleSvg($element[0]);
-        LogicTopologyHelper.drawTree(svg);
+        LogicTopologyHelper.setupTree(svg);
       }
     };
   });
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
index 4e00423..077ad6e 100644
--- a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
@@ -17,6 +17,7 @@
             {
               name: 'Rack',
               type: 'rack',
+              computeNodes: [],
               children: [
                 {
                   name: 'LAN',
@@ -154,7 +155,7 @@
     /**
     * Calculate the svg size and setup tree layout
     */
-    this.drawTree = (svg) => {
+    this.setupTree = (svg) => {
       
 
       svgWidth = svg.node().getBoundingClientRect().width;
@@ -165,19 +166,24 @@
 
       layout = d3.layout.tree()
       .size([height, width]);
+    };
 
+    /**
+    * Update the tree layout
+    */
+
+    this.updateTree = (svg) => {
       // Compute the new tree layout.
       [nodes, links] = computeLayout(baseData);
 
       drawNodes(svg, nodes);
       drawLinks(svg, links);
-      
-    };
+    }
 
     /**
     * Add Subscribers to the tree
     */
-    this.addSubscribers = (svg, subscribers) => {
+    this.addSubscribers = (subscribers) => {
 
       subscribers.map((subscriber) => {
         subscriber.children = subscriber.devices;
@@ -185,11 +191,16 @@
 
       // add subscriber to data tree
       baseData.children[0].children[0].children[0].children = subscribers;
+      
+      return baseData;
+    };
 
-      [nodes, links] = computeLayout(baseData);
-
-      drawNodes(svg, nodes);
-      drawLinks(svg, links);
+    /**
+    * Add compute nodes to the rack element
+    */
+   
+    this.addComputeNodes = (computeNodes) => {
+      baseData.children[0].children[0].computeNodes = computeNodes;
     }
   });
 
diff --git a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
index 5bf0dc8..f84524e 100644
--- a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
+++ b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
@@ -9,7 +9,7 @@
   var instanceId = 0;
 
   angular.module('xos.serviceTopology')
-  .service('NodeDrawer', function(d3, serviceTopologyConfig, Node, RackHelper){
+  .service('NodeDrawer', function(d3, serviceTopologyConfig, RackHelper){
     this.addNetworks = (nodes) => {
       nodes.append('path')
       .attr({
@@ -27,39 +27,59 @@
 
     this.addRack = (nodes) => {
 
-      // NOTE is good to request data here? Probably not.
-
-      Node.queryWithInstances().$promise
-      .then((computeNodes) => {
-        let [w, h] = RackHelper.getRackSize(computeNodes);
+      // loop because of D3
+      // rack will be only one
+      nodes.each(d => {
+        let [w, h] = RackHelper.getRackSize(d.computeNodes);
 
         let rack = nodes
-        .append('g').
-        attr({
+        .append('g');
+
+        rack
+        .attr({
+          transform: `translate(0,0)`
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
           transform: d => `translate(${- (w / 2)}, ${- (h / 2)})`
         });
 
         rack
         .append('rect')
         .attr({
+          width: 0,
+          height: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
           width: w,
           height: h
         });
 
-        nodes.append('text')
+        rack.append('text')
         .attr({
           'text-anchor': 'middle',
-          y: - (h / 2) - 10
+          y: - 10,
+          x: w / 2,
+          opacity: 0
         })
-        .text(d => d.name);
+        .text(d => d.name)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
 
-        this.drawComputeNodes(rack, computeNodes);
+        this.drawComputeNodes(rack, d.computeNodes);
+
       });
+
     };
 
     this.drawComputeNodes = (container, nodes) => {
       
-
       let elements = container.selectAll('.compute-nodes')
       .data(nodes, d => {
         if(!angular.isString(d.d3Id)){
@@ -68,14 +88,29 @@
         return d.d3Id;
       });
 
-      var nodeContainer = elements.enter().append('g')
+      let {width, height} = container.node().getBoundingClientRect();
+
+      var nodeContainer = elements.enter().append('g');
+
+      nodeContainer
       .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
         class: 'compute-node',
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
         transform: (d) => `translate(${RackHelper.getComputeNodePosition(nodes, d.d3Id.replace('compute-node-', '') - 1)})`
       });
 
       nodeContainer.append('rect')
       .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
         width: d => RackHelper.getComputeNodeSize(d.instances)[0],
         height: d => RackHelper.getComputeNodeSize(d.instances)[1],
       });
@@ -84,9 +119,15 @@
       .attr({
         'text-anchor': 'start',
         y: 15, //FIXME
-        x: 10 //FIXME
+        x: 10, //FIXME
+        opacity: 0
       })
-      .text(d => d.humanReadableName.split('.')[0]);
+      .text(d => d.humanReadableName.split('.')[0])
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      })
 
       // if there are Compute Nodes
       if(nodeContainer.length > 0){
@@ -110,17 +151,32 @@
 
     this.drawInstances = (container, instances) => {
 
+      let {width, height} = container.node().getBoundingClientRect();
+
       let elements = container.selectAll('.instances')
       .data(instances, d => angular.isString(d.d3Id) ? d.d3Id : d.d3Id = `instance-${++instanceId}`)
 
-      var instanceContainer = elements.enter().append('g')
+      var instanceContainer = elements.enter().append('g');
+
+      instanceContainer
       .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
         class: 'instance',
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
         transform: d => `translate(${RackHelper.getInstancePosition(d.d3Id.replace('instance-', '') - 1)})`
       });
 
       instanceContainer.append('rect')
       .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
         width: serviceTopologyConfig.instance.width,
         height: serviceTopologyConfig.instance.height
       });
@@ -129,9 +185,15 @@
       .attr({
         'text-anchor': 'middle',
         y: 23, //FIXME
-        x: 40 //FIXME
+        x: 40, //FIXME
+        opacity: 0
       })
-      .text(d => formatInstanceName(d.name));
+      .text(d => formatInstanceName(d.name))
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      });
 
       instanceContainer
       .on('click', d => {
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
index 045a393..4ff5516 100644
--- a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
@@ -2,7 +2,7 @@
   'use strict';
 
   angular.module('xos.serviceTopology')
-  .service('ServiceTopologyHelper', function($window, $log, lodash, ServiceRelation, serviceTopologyConfig){
+  .service('ServiceTopologyHelper', function($rootScope, $window, $log, lodash, ServiceRelation, serviceTopologyConfig, d3){
 
     const drawLegend = (svg) => {
       const legendContainer = svg.append('g')
@@ -126,8 +126,6 @@
       const subscriberNodes = nodeEnter.filter('.subscriber');
       const internetNodes = nodeEnter.filter('.router');
       const serviceNodes = nodeEnter.filter('.service');
-      const instanceNodes = nodeEnter.filter('.instance');
-      const sliceNodes = nodeEnter.filter('.slice');
 
       subscriberNodes.append('rect')
         .attr(serviceTopologyConfig.square);
@@ -140,23 +138,6 @@
         .style('fill', d => d._children ? 'lightsteelblue' : '#fff')
         .on('click', serviceClick);
 
-      sliceNodes.append('rect')
-        .attr({
-          width: 20,
-          height: 20,
-          x: -10,
-          y: -10
-        });
-
-      instanceNodes.append('rect')
-        .attr({
-          width: 20,
-          height: 20,
-          x: -10,
-          y: -10,
-          class: d => d.active ?'' : 'active'
-        });
-
       nodeEnter.append('text')
         .attr({
           x: d => d.children ? -serviceTopologyConfig.circle.selectedRadius -3 : serviceTopologyConfig.circle.selectedRadius + 3,
@@ -182,7 +163,9 @@
         });
 
       nodeUpdate.select('circle')
-        .attr('r', d => d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius)
+        .attr('r', d => {
+          return d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius
+        })
         .style('fill', d => d.selected ? 'lightsteelblue' : '#fff');
 
       nodeUpdate.select('text')
@@ -234,12 +217,20 @@
 
     const serviceClick = function(d) {
 
-      $log.info('TODO emit an event to highlight VMs');
+      $log.info('TODO emit an event to highlight VMs', d);
+
+      if(d.service.service_specific_attribute && d.service.service_specific_attribute.instance_id){
+        $rootScope.$emit('instance.detail', {id: d.service.service_specific_attribute.instance_id});
+      }
 
       if(!d.service){
         return;
       }
 
+      // unselect all
+      _svg.selectAll('circle')
+      .each(d => d.selected = false);
+
       // toggling selected status
       d.selected = !d.selected;
 
@@ -249,6 +240,8 @@
         .transition()
         .duration(serviceTopologyConfig.duration)
         .attr('r', serviceTopologyConfig.circle.selectedRadius);
+
+      updateTree(_svg, _layout, _source);
     };
 
     this.updateTree = updateTree;