blob: f12ce5b02054bcee6448dcf631897fb8b3ad7f72 [file] [log] [blame]
Matteo Scandolo8a64fa42016-01-21 11:21:03 -08001(function () {
2 'use strict';
3
4 angular.module('xos.serviceTopology')
5 .factory('d3', function($window){
6 return $window.d3;
7 })
Matteo Scandolo071ef462016-01-25 12:00:42 -08008 .service('TreeLayout', function($window, lodash, ServiceRelation, serviceTopologyConfig, Slice, Instances){
Matteo Scandolof2c99012016-01-25 10:10:38 -08009
Matteo Scandolo071ef462016-01-25 12:00:42 -080010 var _svg, _layout, _source;
11
12 var i = 0;
13
14 // given a canvas, a layout and a data source, draw a tree layout
15 const updateTree = (svg, layout, source) => {
16
17 //cache data
18 _svg = svg;
19 _layout = layout;
20 _source = source;
21
22 const maxDepth = ServiceRelation.depthOf(source);
23
24 const diagonal = d3.svg.diagonal()
25 .projection(d => [d.y, d.x]);
26
27 // Compute the new tree layout.
28 var nodes = layout.nodes(source).reverse(),
29 links = layout.links(nodes);
30
31 // Normalize for fixed-depth.
32 nodes.forEach(function(d) {
33 // position the child node horizontally
Matteo Scandolo9ef3c842016-01-25 13:55:09 -080034 const step = (($window.innerWidth - (serviceTopologyConfig.widthMargin * 2)) / maxDepth);
35 d.y = d.depth * step;
36 if(d.type === 'slice' || d.type === 'instance'){
37 d.y = d.depth * step - (step / 2);
Matteo Scandolo071ef462016-01-25 12:00:42 -080038 }
39 });
40
41 // Update the nodes…
42 var node = svg.selectAll('g.node')
43 .data(nodes, function(d) { return d.id || (d.id = ++i); });
44
45 // Enter any new nodes at the parent's previous position.
46 var nodeEnter = node.enter().append('g')
47 .attr({
48 class: d => `node ${d.type}`,
49 transform: d => `translate(${source.y0},${source.x0})` // this is the starting position
50 });
51
Matteo Scandolo9ef3c842016-01-25 13:55:09 -080052 // TODO append different shapes base on type
Matteo Scandolo071ef462016-01-25 12:00:42 -080053 nodeEnter.append('circle')
54 .attr('r', 1e-6)
55 .style('fill', d => d._children ? 'lightsteelblue' : '#fff')
56 .on('click', serviceClick);
57
58 nodeEnter.append('text')
Matteo Scandolocb12a1a2016-01-25 14:11:10 -080059 .attr({
60 x: d => d.children ? -serviceTopologyConfig.circle.selectedRadius -3 : serviceTopologyConfig.circle.selectedRadius + 3,
61 dy: '.35em',
62 transform: d => {
63 if (d.children && d.parent){
64 if(d.parent.x < d.x){
65 return 'rotate(-30)';
66 }
67 return 'rotate(30)';
68 }
69 },
70 'text-anchor': d => d.children ? 'end' : 'start'
Matteo Scandolo071ef462016-01-25 12:00:42 -080071 })
Matteo Scandolocb12a1a2016-01-25 14:11:10 -080072 .text(d => d.name)
Matteo Scandolo071ef462016-01-25 12:00:42 -080073 .style('fill-opacity', 1e-6);
74
75 // Transition nodes to their new position.
76 var nodeUpdate = node.transition()
77 .duration(serviceTopologyConfig.duration)
Matteo Scandolocb12a1a2016-01-25 14:11:10 -080078 .attr({
79 'transform': d => `translate(${d.y},${d.x})`
Matteo Scandolo071ef462016-01-25 12:00:42 -080080 });
81
82 nodeUpdate.select('circle')
Matteo Scandolocb12a1a2016-01-25 14:11:10 -080083 .attr('r', d => d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius)
84 .style('fill', d => d.selected ? 'lightsteelblue' : '#fff');
Matteo Scandolo071ef462016-01-25 12:00:42 -080085
86 nodeUpdate.select('text')
87 .style('fill-opacity', 1);
88
89 // Transition exiting nodes to the parent's new position.
90 var nodeExit = node.exit().transition()
91 .duration(serviceTopologyConfig.duration)
Matteo Scandolocb12a1a2016-01-25 14:11:10 -080092 .attr({
93 'transform': d => `translate(${source.y},${source.x})`
94 })
Matteo Scandolo071ef462016-01-25 12:00:42 -080095 .remove();
96
97 nodeExit.select('circle')
98 .attr('r', 1e-6);
99
100 nodeExit.select('text')
101 .style('fill-opacity', 1e-6);
102
103 // Update the links…
104 var link = svg.selectAll('path.link')
105 .data(links, function(d) { return d.target.id; });
106
107 // Enter any new links at the parent's previous position.
108 link.enter().insert('path', 'g')
Matteo Scandolo9ef3c842016-01-25 13:55:09 -0800109 .attr('class', d => `link ${d.target.type}`)
Matteo Scandolo071ef462016-01-25 12:00:42 -0800110 .attr('d', function(d) {
111 var o = {x: source.x0, y: source.y0};
112 return diagonal({source: o, target: o});
113 });
114
115 // Transition links to their new position.
116 link.transition()
117 .duration(serviceTopologyConfig.duration)
118 .attr('d', diagonal);
119
120 // Transition exiting nodes to the parent's new position.
121 link.exit().transition()
122 .duration(serviceTopologyConfig.duration)
123 .attr('d', function(d) {
124 var o = {x: source.x, y: source.y};
125 return diagonal({source: o, target: o});
126 })
127 .remove();
128
129 // Stash the old positions for transition.
130 nodes.forEach(function(d) {
131 d.x0 = d.x;
132 d.y0 = d.y;
133 });
134 };
135
136 const serviceClick = function(d) {
137
Matteo Scandolocb12a1a2016-01-25 14:11:10 -0800138 if(!d.service){
139 return;
140 }
141
Matteo Scandolo9ef3c842016-01-25 13:55:09 -0800142 // toggling selected status
143 d.selected = !d.selected;
Matteo Scandolo071ef462016-01-25 12:00:42 -0800144
Matteo Scandolo071ef462016-01-25 12:00:42 -0800145 var selectedNode = d3.select(this);
146
147 selectedNode
148 .transition()
149 .duration(serviceTopologyConfig.duration)
Matteo Scandolocb12a1a2016-01-25 14:11:10 -0800150 .attr('r', serviceTopologyConfig.circle.selectedRadius);
Matteo Scandolo071ef462016-01-25 12:00:42 -0800151
Matteo Scandolo071ef462016-01-25 12:00:42 -0800152 ServiceRelation.getServiceInterfaces(d.service.id)
153 .then(interfaceTree => {
154
155 const isDetailed = lodash.find(d.children, {type: 'slice'});
156 if(isDetailed){
Matteo Scandolo071ef462016-01-25 12:00:42 -0800157 lodash.remove(d.children, {type: 'slice'});
158 }
159 else {
Matteo Scandolo071ef462016-01-25 12:00:42 -0800160 d.children = d.children.concat(interfaceTree);
161 }
162
163 updateTree(_svg, _layout, _source);
Matteo Scandolo071ef462016-01-25 12:00:42 -0800164 });
165 };
166
167 this.updateTree = updateTree;
Matteo Scandolof2c99012016-01-25 10:10:38 -0800168 });
Matteo Scandolo8a64fa42016-01-21 11:21:03 -0800169
170}());