blob: 2318b48e854665f4c356e61de1a9ee4a18695c79 [file] [log] [blame]
Rizwan Haider8e5f4772016-08-17 18:04:35 -04001/**
2 * © OpenCORD
3 *
4 * Visit http://guide.xosproject.org/devguide/addview/ for more information
5 *
6 * Created by teone on 6/28/16.
7 */
8
9(function () {
10 'use strict';
11 angular.module('xos.ecordTopology')
12 .directive('serviceMap', function(){
13 return {
14 restrict: 'E',
15 scope: {
16 unis: '=',
17 services: '='
18 },
19 bindToController: true,
20 controllerAs: 'vm',
21 template: '',
22 controller: function($element, $scope, $rootScope, $timeout, $log, cordIcons){
23 const el = $element[0];
24 const layout = d3.layout.tree();
25 let duration = 500;
26 let margin = 40;
27
28 // count the mas depth of an object
29 const depthOf = (obj) => {
30 var depth = 0;
31 if (obj.children) {
32 obj.children.forEach(function (d) {
33 var tmpDepth = depthOf(d);
34 if (tmpDepth > depth) {
35 depth = tmpDepth
36 }
37 })
38 }
39 return 1 + depth
40 };
41
42 // create svg elements
43 const svg = d3.select(el)
44 .append('svg')
45 .style('width', `${el.clientWidth}px`)
46 .style('height', `${el.clientHeight}px`)
47
48 var diagonal = d3.svg.diagonal()
49 .projection(function(d) { return [d.y, d.x]; });
50
51 let i = 0;
52 const update = (tree) => {
53
54 let maxDepth = depthOf(tree);
55
56 layout
57 .size([el.clientHeight, el.clientWidth]);
58
59 var nodes = layout.nodes(tree);
60 var links = layout.links(nodes);
61
62 const step = ((el.clientWidth - margin) / (maxDepth - 1));
63 // Normalize for fixed-depth.
64 nodes.forEach(function(d, i) {
65 if(i === 0){
66 d.y = margin;
67 }
68 else{
69 d.y = d.depth * step;
70 }
71 });
72
73 // Update the nodes…
74 var node = svg.selectAll('g.node')
75 .data(nodes, (d) => {
76 return d.id || (d.id = ++i)
77 });
78
79
80 // Enter any new nodes at the parent's previous position.
81 var nodeEnter = node.enter().append('g')
82 .attr({
83 'class': d => `node ${d.type}`,
84 id: d => d.id
85 })
86 .attr('transform', () => `translate(${el.clientWidth / 2}, 50)`);
87
88 nodeEnter.append('rect')
89 .attr({
90 class: d => d.type,
91 width: 24,
92 height: 24,
93 x: -12,
94 y: -12
95 });
96
97 // unis
98 nodeEnter.filter('.uni')
99 .append('path')
100 .attr({
101 d: cordIcons.cordLogo,
102 transform: 'translate(-10, -10),scale(0.18)'
103 });
104
105 // services
106 nodeEnter.filter('.service')
107 .append('path')
108 .attr({
109 d: cordIcons.service,
110 transform: 'translate(-12, -12)'
111 });
112
113 nodeEnter.append('text')
114 .attr({
115 'text-anchor': 'middle',
116 x: 0,
117 y: 25
118 })
119 .text(d => {
120 return d.name
121 });
122
123 // Transition exiting nodes to the parent's new position.
124 var nodeExit = node.exit().transition()
125 .duration(duration)
126 .remove();
127
128 nodeExit.select('circle')
129 .attr('r', 1e-6);
130
131 nodeExit.select('text')
132 .style('fill-opacity', 1e-6);
133
134 var nodeUpdate = node.transition()
135 .duration(duration)
136 .attr('transform', (d) => `translate(${d.y},${d.x})`);
137
138 // Update the links…
139 var link = svg.selectAll('path.link')
140 .data(links, function(d) { return d.target.id; });
141
142 // Enter any new links at the parent's previous position.
143 link.enter().insert('path', 'g')
144 .attr('class', 'link')
145 .attr('d', function(d) {
146 var o = {x: d.source.x, y: d.source.y};
147 return diagonal({source: o, target: o});
148 });
149
150 // Transition links to their new position.
151 link.transition()
152 .duration(duration)
153 .attr('d', diagonal);
154
155 // Transition exiting nodes to the parent's new position.
156 link.exit().transition()
157 .duration(duration)
158 .attr('d', function(d) {
159 var o = {x: d.source.x, y: d.source.y};
160 return diagonal({source: o, target: o});
161 })
162 .remove();
163
164 // Stash the old positions for transition.
165 nodes.forEach(function(d) {
166 d.x0 = d.x;
167 d.y0 = d.y;
168 });
169 };
170
171 // format uni in the tree layout shape
172 this.formatUni = (unis) => {
173 return unis.reduce((list, item, i) => {
174 list.push({
175 name: item.scaEthFppUniN.name,
176 children: [],
177 id: `uni-${i}`
178 });
179 return list;
180 }, [])
181 return unis;
182 }
183
184 // add active services
185 this.addServices = (services, unis) => {
186
187 let list = [unis[0], ...services, unis[1]];
188
189
190 const addChildR = (base, list) => {
191
192 if(list.length === 0){
193 return [];
194 }
195
196 let el = list.shift();
197
198 let n = {
199 name: el.name || el.label,
200 type: el.name ? 'uni':'service',
201 children: addChildR(el, list),
202 id: el.id
203 };
204
205 return [n];
206 };
207
208 let tree = addChildR({}, list);
209
210 return tree[0];
211 };
212
213 $scope.$watch(() => this.services, (s) => {
214 if(s && this.unis){
215 update(this.addServices(s, this.formatUni(this.unis)))
216 }
217 }, true)
218 }
219 };
220 });
221})();
222