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;