blob: 7c76e612492ccf8975aead1090f555a92864ad01 [file] [log] [blame]
Matteo Scandolo9fe01af2016-02-09 16:01:49 -08001(function () {
2 'use strict';
3
4 const shapes = {
5 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'
6 }
7
Matteo Scandolo170d3be2016-02-11 08:58:04 -08008 var computeNodeId = 0;
9 var instanceId = 0;
10
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080011 angular.module('xos.serviceTopology')
Matteo Scandolo35d53c82016-02-16 14:44:51 -080012 .service('NodeDrawer', function(d3, serviceTopologyConfig, RackHelper){
Matteo Scandolo51031482016-02-17 13:54:11 -080013
14 var _this = this;
15
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080016 this.addNetworks = (nodes) => {
17 nodes.append('path')
18 .attr({
19 d: shapes.cloud,
20 transform: 'translate(-63, -52), scale(0.5)',
21 class: 'cloud'
22 });
23
24 nodes.append('text')
25 .attr({
26 'text-anchor': 'middle'
27 })
28 .text(d => d.name)
Matteo Scandolo45fba732016-02-22 14:53:44 -080029
30 nodes.each(function(n){
31 let currentNode = d3.select(this);
32 // cicle trouch node to add Tags and Public IP
33 if(n.name === 'LAN' && angular.isDefined(n.subscriberTag)){
34 currentNode.append('text')
35 .attr({
36 'text-anchor': 'middle',
37 y: 40
38 })
39 .text(() => `C-Tag: ${n.subscriberTag.cTag}`);
40
41 currentNode.append('text')
42 .attr({
43 'text-anchor': 'middle',
44 y: 60
45 })
46 .text(() => `S-Tag: ${n.subscriberTag.sTag}`);
47 }
Matteo Scandolo012dddb2016-02-22 16:53:22 -080048
49 if(n.name === 'WAN' && angular.isDefined(n.subscriberIP)){
50 currentNode.append('text')
51 .attr({
52 'text-anchor': 'middle',
53 y: 40
54 })
55 .text(() => `Public IP: ${n.subscriberIP}`);
56 }
Matteo Scandolo45fba732016-02-22 14:53:44 -080057 });
Matteo Scandolo9fe01af2016-02-09 16:01:49 -080058 }
59
60 this.addRack = (nodes) => {
Matteo Scandolo170d3be2016-02-11 08:58:04 -080061
Matteo Scandolo35d53c82016-02-16 14:44:51 -080062 // loop because of D3
63 // rack will be only one
64 nodes.each(d => {
65 let [w, h] = RackHelper.getRackSize(d.computeNodes);
Matteo Scandoload5b2282016-02-16 11:50:51 -080066
67 let rack = nodes
Matteo Scandolo35d53c82016-02-16 14:44:51 -080068 .append('g');
69
70 rack
71 .attr({
72 transform: `translate(0,0)`
73 })
74 .transition()
75 .duration(serviceTopologyConfig.duration)
76 .attr({
Matteo Scandoload5b2282016-02-16 11:50:51 -080077 transform: d => `translate(${- (w / 2)}, ${- (h / 2)})`
78 });
79
80 rack
81 .append('rect')
82 .attr({
Matteo Scandolo35d53c82016-02-16 14:44:51 -080083 width: 0,
84 height: 0
85 })
86 .transition()
87 .duration(serviceTopologyConfig.duration)
88 .attr({
Matteo Scandoload5b2282016-02-16 11:50:51 -080089 width: w,
90 height: h
91 });
92
Matteo Scandolo35d53c82016-02-16 14:44:51 -080093 rack.append('text')
Matteo Scandoload5b2282016-02-16 11:50:51 -080094 .attr({
95 'text-anchor': 'middle',
Matteo Scandolo35d53c82016-02-16 14:44:51 -080096 y: - 10,
97 x: w / 2,
98 opacity: 0
Matteo Scandoload5b2282016-02-16 11:50:51 -080099 })
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800100 .text(d => d.name)
101 .transition()
102 .duration(serviceTopologyConfig.duration)
103 .attr({
104 opacity: 1
105 })
Matteo Scandoload5b2282016-02-16 11:50:51 -0800106
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800107 this.drawComputeNodes(rack, d.computeNodes);
108
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800109 });
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800110
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800111 };
112
113 this.drawComputeNodes = (container, nodes) => {
Matteo Scandoload5b2282016-02-16 11:50:51 -0800114
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800115 let elements = container.selectAll('.compute-nodes')
116 .data(nodes, d => {
117 if(!angular.isString(d.d3Id)){
118 d.d3Id = `compute-node-${++computeNodeId}`;
119 }
120 return d.d3Id;
121 });
122
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800123 let {width, height} = container.node().getBoundingClientRect();
124
125 var nodeContainer = elements.enter().append('g');
126
127 nodeContainer
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800128 .attr({
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800129 transform: `translate(${width / 2}, ${ height / 2})`,
Matteo Scandoload5b2282016-02-16 11:50:51 -0800130 class: 'compute-node',
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800131 })
132 .transition()
133 .duration(serviceTopologyConfig.duration)
134 .attr({
Matteo Scandoload5b2282016-02-16 11:50:51 -0800135 transform: (d) => `translate(${RackHelper.getComputeNodePosition(nodes, d.d3Id.replace('compute-node-', '') - 1)})`
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800136 });
137
138 nodeContainer.append('rect')
Matteo Scandoload5b2282016-02-16 11:50:51 -0800139 .attr({
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800140 width: 0,
141 height: 0
142 })
143 .transition()
144 .duration(serviceTopologyConfig.duration)
145 .attr({
Matteo Scandoload5b2282016-02-16 11:50:51 -0800146 width: d => RackHelper.getComputeNodeSize(d.instances)[0],
147 height: d => RackHelper.getComputeNodeSize(d.instances)[1],
148 });
149
150 nodeContainer.append('text')
151 .attr({
152 'text-anchor': 'start',
153 y: 15, //FIXME
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800154 x: 10, //FIXME
155 opacity: 0
Matteo Scandoload5b2282016-02-16 11:50:51 -0800156 })
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800157 .text(d => d.humanReadableName.split('.')[0])
158 .transition()
159 .duration(serviceTopologyConfig.duration)
160 .attr({
161 opacity: 1
162 })
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800163
164 // if there are Compute Nodes
165 if(nodeContainer.length > 0){
Matteo Scandolo51031482016-02-17 13:54:11 -0800166 // draw instances for each compute node
167 nodeContainer.each(function(a){
168 _this.drawInstances(d3.select(this), a.instances);
169 })
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800170 }
171
172 };
173
Matteo Scandolo7030ceb2016-02-16 13:29:26 -0800174 // NOTE Stripping unuseful names to shorten labels.
175 // This is not elegant
176 const formatInstanceName = (name) => {
177 return name
178 .replace('app_', '')
179 .replace('service_', '')
180 .replace('ovs_', '')
181 .replace('mysite_', '')
182 .replace('_instance', '');
183 };
184
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800185 this.drawInstances = (container, instances) => {
Matteo Scandolo51031482016-02-17 13:54:11 -0800186
Matteo Scandoloc49ff702016-02-17 15:11:33 -0800187 // TODO check for stats field in instance and draw popup
188
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800189 let {width, height} = container.node().getBoundingClientRect();
190
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800191 let elements = container.selectAll('.instances')
192 .data(instances, d => angular.isString(d.d3Id) ? d.d3Id : d.d3Id = `instance-${++instanceId}`)
193
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800194 var instanceContainer = elements.enter().append('g');
195
196 instanceContainer
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800197 .attr({
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800198 transform: `translate(${width / 2}, ${ height / 2})`,
Matteo Scandolo7e67a9a2016-02-16 16:33:26 -0800199 class: d => `instance ${d.selected ? 'active' : ''}`,
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800200 })
201 .transition()
202 .duration(serviceTopologyConfig.duration)
203 .attr({
Matteo Scandolo51031482016-02-17 13:54:11 -0800204 transform: (d, i) => `translate(${RackHelper.getInstancePosition(i)})`
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800205 });
206
207 instanceContainer.append('rect')
Matteo Scandoload5b2282016-02-16 11:50:51 -0800208 .attr({
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800209 width: 0,
210 height: 0
211 })
212 .transition()
213 .duration(serviceTopologyConfig.duration)
214 .attr({
Matteo Scandoload5b2282016-02-16 11:50:51 -0800215 width: serviceTopologyConfig.instance.width,
216 height: serviceTopologyConfig.instance.height
217 });
218
219 instanceContainer.append('text')
220 .attr({
Matteo Scandolo7030ceb2016-02-16 13:29:26 -0800221 'text-anchor': 'middle',
222 y: 23, //FIXME
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800223 x: 40, //FIXME
224 opacity: 0
Matteo Scandoload5b2282016-02-16 11:50:51 -0800225 })
Matteo Scandolo35d53c82016-02-16 14:44:51 -0800226 .text(d => formatInstanceName(d.name))
227 .transition()
228 .duration(serviceTopologyConfig.duration)
229 .attr({
230 opacity: 1
231 });
Matteo Scandolo7030ceb2016-02-16 13:29:26 -0800232
233 instanceContainer
234 .on('click', d => {
235 console.log(d);
236 });
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800237 };
Matteo Scandolo9fe01af2016-02-09 16:01:49 -0800238
239 this.addPhisical = (nodes) => {
240 nodes.append('rect')
241 .attr(serviceTopologyConfig.square);
242
243 nodes.append('text')
244 .attr({
245 'text-anchor': 'middle',
246 y: serviceTopologyConfig.square.y - 10
247 })
248 .text(d => d.name);
249 }
250
251 this.addDevice = (nodes) => {
252 nodes.append('circle')
253 .attr(serviceTopologyConfig.circle);
254
255 nodes.append('text')
256 .attr({
257 'text-anchor': 'end',
258 x: - serviceTopologyConfig.circle.r - 10,
259 y: serviceTopologyConfig.circle.r / 2
260 })
261 .text(d => d.name);
262 }
263 });
264})();