Drawing logic layer shapes
diff --git a/views/ngXosViews/diagnostic/spec/sample.test.js b/views/ngXosViews/diagnostic/spec/sample.test.js
index e3d2052..dcd9da0 100644
--- a/views/ngXosViews/diagnostic/spec/sample.test.js
+++ b/views/ngXosViews/diagnostic/spec/sample.test.js
@@ -126,10 +126,10 @@
expect(tree.children[0].children[0].name).toBe('service-2');
expect(tree.children[0].children[0].children[0].name).toBe('service-3');
- expect(tree.children[0].children[0].children[0].children[0].name).toBe('Internet');
+ expect(tree.children[0].children[0].children[0].children[0].name).toBe('Router');
expect(tree.children[0].children[1].name).toBe('service-4');
- expect(tree.children[0].children[1].children[0].name).toBe('Internet');
+ expect(tree.children[0].children[1].children[0].name).toBe('Router');
});
});
diff --git a/views/ngXosViews/diagnostic/src/css/serviceTopology.css b/views/ngXosViews/diagnostic/src/css/serviceTopology.css
index d9b219d..634b6ed 100644
--- a/views/ngXosViews/diagnostic/src/css/serviceTopology.css
+++ b/views/ngXosViews/diagnostic/src/css/serviceTopology.css
@@ -4,6 +4,14 @@
height: 50%;
}
+diagnostic .subscriber-select{
+ max-width: 200px;
+ position: absolute;
+ top: 20px;
+ right: 20px;
+ z-index: 1;
+}
+
.half-height + .half-height {
border-top: 1px solid black;
}
@@ -24,6 +32,12 @@
stroke-width: 1px;
}
+logic-topology .network .cloud {
+ fill: #fff;
+ stroke: green;
+ stroke-width: 1px;
+}
+
/* LEGEND */
.legend {
@@ -49,7 +63,9 @@
}
.node.subscriber circle,
-.node.internet circle {
+.node.subscriber rect,
+.node.router circle,
+.node.router rect {
stroke: #05ffcb;
}
diff --git a/views/ngXosViews/diagnostic/src/index.html b/views/ngXosViews/diagnostic/src/index.html
index d9bfc1e..afe559c 100644
--- a/views/ngXosViews/diagnostic/src/index.html
+++ b/views/ngXosViews/diagnostic/src/index.html
@@ -36,6 +36,7 @@
<script src="/.tmp/serviceTopologyHelper.js"></script>
<script src="/.tmp/serviceTopology.js"></script>
<script src="/.tmp/rest_services.js"></script>
+<script src="/.tmp/nodeDrawer.js"></script>
<script src="/.tmp/logicTopologyHelper.js"></script>
<script src="/.tmp/logicTopology.js"></script>
<script src="/.tmp/diagnostic.js"></script>
diff --git a/views/ngXosViews/diagnostic/src/js/config.js b/views/ngXosViews/diagnostic/src/js/config.js
index 91ea0c2..7308995 100644
--- a/views/ngXosViews/diagnostic/src/js/config.js
+++ b/views/ngXosViews/diagnostic/src/js/config.js
@@ -8,6 +8,7 @@
duration: 750,
circle: {
radius: 10,
+ r: 10,
selectedRadius: 15
},
square: {
@@ -15,6 +16,12 @@
height: 20,
x: -10,
y: -10
+ },
+ rack: {
+ width: 50,
+ height: 50,
+ x: -25,
+ y: -25
}
})
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
index 56d1f56..d33de36 100644
--- a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
@@ -2,104 +2,7 @@
'use strict';
angular.module('xos.serviceTopology')
- .service('LogicTopologyHelper', function($window, $log, lodash, serviceTopologyConfig){
-
- var hStep, vStep;
-
- const createDevice = (container, device, xPos, yPos, target) => {
-
- const deviceGroup = container.append('g')
- .attr({
- class: 'device',
- transform: `translate(${xPos}, ${yPos})`
- });
-
- const deviceEl = deviceGroup.append('circle')
- .attr({
- r: serviceTopologyConfig.circle.radius
- });
-
- deviceGroup.append('text')
- .attr({
- x: - serviceTopologyConfig.circle.radius - 3,
- dy: '.35em',
- 'text-anchor': 'end'
- })
- .text(device.name)
-
- const [deviceX, deviceY] = d3.transform(deviceEl.attr('transform')).translate;
- const [deviceGroupX, deviceGroupY] = d3.transform(deviceGroup.attr('transform')).translate;
- let [targetX, targetY] = d3.transform(target.attr('transform')).translate;
-
- targetX = targetX - deviceGroupX;
- targetY = targetY - deviceGroupY;
-
- console.log('Device: ' + deviceX, deviceY);
- console.log('Subscriber: ' + targetX, targetY);
-
- var diagonal = d3.svg.diagonal()
- .source({x: deviceX, y: deviceY})
- .target({x: targetX, y: targetY})
- // .projection(d => {
- // return [d.y, d.x];
- // });
-
- deviceGroup
- .append('path')
- .attr('class', 'device-link')
- .attr('d', diagonal);
- }
-
- const createSubscriber = (container, subscriber, xPos, yPos) => {
-
- const subscriberGroup = container.append('g')
- .attr({
- class: 'subscriber',
- transform: `translate(${xPos * 2}, ${yPos})`
- });
-
- subscriberGroup.append('circle')
- .attr({
- r: serviceTopologyConfig.circle.radius
- });
-
- subscriberGroup.append('text')
- .attr({
- x: serviceTopologyConfig.circle.radius + 3,
- dy: '.35em',
- 'text-anchor': 'start'
- })
- .text(subscriber.humanReadableName)
-
- // TODO
- // starting from the subscriber position, we should center
- // the device goup based on his own height
- // const deviceContainer = container.append('g')
- // .attr({
- // class: 'devices-container',
- // transform: `translate(${xPos}, ${yPos -(vStep / 2)})`
- // });
-
- angular.forEach(subscriber.devices, (device, j) => {
- createDevice(container, device, xPos, ((vStep / subscriber.devices.length) * j) + (yPos - vStep / 2), subscriberGroup);
- });
- }
-
- this.handleSubscribers = (svg, subscribers) => {
-
- // HACKY
- hStep = angular.element(svg[0])[0].clientWidth / 7;
- vStep = angular.element(svg[0])[0].clientHeight / (subscribers.length + 1);
-
- const container = svg.append('g')
- .attr({
- class: 'subscribers-container'
- });
-
- lodash.forEach(subscribers, (subscriber, i) => {
- createSubscriber(container, subscriber, hStep, vStep * (i + 1));
- })
- }
+ .service('LogicTopologyHelper', function($window, $log, lodash, serviceTopologyConfig, NodeDrawer){
var diagonal, nodes, links, i = 0, svgWidth, svgHeight, layout;
@@ -127,6 +30,10 @@
]
};
+ /**
+ * from a nested data structure,
+ * create nodes and links for a D3 Tree Layout
+ */
const computeLayout = (data) => {
let nodes = layout.nodes(data);
@@ -138,41 +45,35 @@
});
let links = layout.links(nodes);
- console.log(nodes.length, links.length);
+
return [nodes, links];
};
+ /**
+ * Draw the containing group for any node or update the existing one
+ */
const drawNodes = (svg, nodes) => {
// Update the nodes…
var node = svg.selectAll('g.node')
- .data(nodes, d => {return d.id || (d.id = `tree-${i++}`)});
+ .data(nodes, d => {
+ if(!angular.isString(d.d3Id)){
+ d.d3Id = `tree-${++i}`;
+ }
+ return d.d3Id;
+ });
- // Enter any new nodes at the parent's previous position.
+ // Enter any new nodes
var nodeEnter = node.enter().append('g')
.attr({
class: d => `node ${d.type}`,
transform: `translate(${svgWidth / 2}, ${svgHeight / 2})`
});
- nodeEnter.append('circle')
- .attr('r', 10)
- .style('fill', d => d._children ? 'lightsteelblue' : '#fff');
-
- nodeEnter.append('text')
- .attr({
- x: d => d.children ? serviceTopologyConfig.circle.selectedRadius + 3 : -serviceTopologyConfig.circle.selectedRadius - 3,
- dy: '.35em',
- transform: d => {
- if (d.children && d.parent){
- if(d.parent.x < d.x){
- return 'rotate(-30)';
- }
- return 'rotate(30)';
- }
- },
- 'text-anchor': d => d.children ? 'start' : 'end'
- })
- .text(d => d.name);
+ NodeDrawer.addNetworks(nodeEnter.filter('.network'));
+ NodeDrawer.addRack(nodeEnter.filter('.rack'));
+ NodeDrawer.addPhisical(nodeEnter.filter('.router'));
+ NodeDrawer.addPhisical(nodeEnter.filter('.subscriber'));
+ NodeDrawer.addDevice(nodeEnter.filter('.device'));
// Transition nodes to their new position.
var nodeUpdate = node.transition()
@@ -184,6 +85,9 @@
// TODO handle node remove
};
+ /**
+ * Handle links in the tree layout
+ */
const drawLinks = (svg, links) => {
diagonal = d3.svg.diagonal()
@@ -192,7 +96,7 @@
// Update the links…
var link = svg.selectAll('path.link')
.data(links, d => {
- return d.target.id
+ return d.target.d3Id
});
// Enter any new links at the parent's previous position.
@@ -209,6 +113,9 @@
.attr('d', diagonal);
};
+ /**
+ * Calculate the svg size and setup tree layout
+ */
this.drawTree = (svg) => {
@@ -229,10 +136,11 @@
};
+ /**
+ * Add Subscribers to the tree
+ */
this.addSubscribers = (svg, subscribers) => {
- console.log(subscribers);
-
subscribers.map((subscriber) => {
subscriber.children = subscriber.devices;
});
@@ -240,8 +148,6 @@
// add subscriber to data tree
baseData.children[0].children[0].children[0].children = subscribers;
- console.log(baseData);
-
[nodes, links] = computeLayout(baseData);
drawNodes(svg, nodes);
diff --git a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
new file mode 100644
index 0000000..82349ea
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
@@ -0,0 +1,62 @@
+(function () {
+ 'use strict';
+
+ const shapes = {
+ cloud: ' M 79.72 49.60 C 86.00 37.29 98.57 29.01 111.96 26.42 C 124.27 24.11 137.53 26.15 148.18 32.90 C 158.08 38.78 165.39 48.87 167.65 60.20 C 176.20 57.90 185.14 56.01 194.00 57.73 C 206.08 59.59 217.92 66.01 224.37 76.66 C 227.51 81.54 228.85 87.33 229.23 93.06 C 237.59 93.33 246.22 95.10 253.04 100.19 C 256.69 103.13 259.87 107.67 258.91 112.59 C 257.95 118.43 252.78 122.38 247.78 124.82 C 235.27 130.43 220.23 130.09 207.98 123.93 C 199.33 127.88 189.76 129.43 180.30 128.57 C 173.70 139.92 161.70 147.65 148.86 149.93 C 133.10 153.26 116.06 148.15 104.42 137.08 C 92.98 143.04 78.96 143.87 66.97 139.04 C 57.75 135.41 49.70 128.00 46.60 118.43 C 43.87 109.95 45.81 100.29 51.30 93.32 C 57.38 85.18 67.10 80.44 76.99 78.89 C 74.38 69.20 74.87 58.52 79.72 49.60 Z'
+ }
+
+ angular.module('xos.serviceTopology')
+ .service('NodeDrawer', function(serviceTopologyConfig){
+ this.addNetworks = (nodes) => {
+ nodes.append('path')
+ .attr({
+ d: shapes.cloud,
+ transform: 'translate(-63, -52), scale(0.5)',
+ class: 'cloud'
+ });
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'middle'
+ })
+ .text(d => d.name)
+ }
+
+ this.addRack = (nodes) => {
+ nodes.append('rect')
+ .attr(serviceTopologyConfig.rack);
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'middle',
+ y: serviceTopologyConfig.rack.y - 10
+ })
+ .text(d => d.name)
+ }
+
+ this.addPhisical = (nodes) => {
+ nodes.append('rect')
+ .attr(serviceTopologyConfig.square);
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'middle',
+ y: serviceTopologyConfig.square.y - 10
+ })
+ .text(d => d.name);
+ }
+
+ this.addDevice = (nodes) => {
+ nodes.append('circle')
+ .attr(serviceTopologyConfig.circle);
+
+ nodes.append('text')
+ .attr({
+ 'text-anchor': 'end',
+ x: - serviceTopologyConfig.circle.r - 10,
+ y: serviceTopologyConfig.circle.r / 2
+ })
+ .text(d => d.name);
+ }
+ });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/rest_services.js b/views/ngXosViews/diagnostic/src/js/rest_services.js
index be523da..2673bfc 100644
--- a/views/ngXosViews/diagnostic/src/js/rest_services.js
+++ b/views/ngXosViews/diagnostic/src/js/rest_services.js
@@ -38,9 +38,16 @@
.then((list) => {
res.data.map((subscriber, i) => {
subscriber.devices = list[i];
+ subscriber.type = 'subscriber';
+
+ subscriber.devices.map(d => d.type = 'device')
+
return subscriber;
});
+ // faking to have 2 subscriber
+ res.data.push(angular.copy(res.data[0]));
+
deferred.resolve(res.data);
})
@@ -134,8 +141,8 @@
// if it is the last element append internet
if(tree.children.length === 0){
tree.children.push({
- name: 'Internet',
- type: 'internet',
+ name: 'Router',
+ type: 'router',
children: []
});
}
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
index f3cb2d2..045a393 100644
--- a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
@@ -124,7 +124,7 @@
});
const subscriberNodes = nodeEnter.filter('.subscriber');
- const internetNodes = nodeEnter.filter('.internet');
+ const internetNodes = nodeEnter.filter('.router');
const serviceNodes = nodeEnter.filter('.service');
const instanceNodes = nodeEnter.filter('.instance');
const sliceNodes = nodeEnter.filter('.slice');
diff --git a/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
index 5b8ce78..6754702 100644
--- a/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
+++ b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
@@ -3,14 +3,12 @@
<service-topology service-chain="vm.serviceChain"></service-topology>
</div>
<div class="half-height">
- <div class="row col-sm-offset-9 col-sm-3">
- <div class="panel panel-primary">
- <div class="panel-heading">Select a subscriber:</div>
- <div class="panel-body">
- <select class="form-control" ng-options="s as s.name for s in vm.subscribers" ng-model="vm.selectedSubscriber">
- <option value="">Select a subscriber...</option>
- </select>
- </div>
+ <div class="panel panel-primary subscriber-select">
+ <div class="panel-heading">Select a subscriber:</div>
+ <div class="panel-body">
+ <select class="form-control" ng-options="s as s.name for s in vm.subscribers" ng-model="vm.selectedSubscriber">
+ <option value="">Select a subscriber...</option>
+ </select>
</div>
</div>
<logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>