blob: e9349720ecd9843e3bb6ade7b6bb6458acefb2c6 [file] [log] [blame]
Paul Greyson7a300822013-04-09 12:57:49 -07001/***************************************************************************************************
2functions for creating and interacting with the topology view of the webui
3
4flow related topology is in flows.js
5***************************************************************************************************/
6
Paul Greysone15c4392013-04-09 15:05:31 -07007(function () {
Paul Greyson7a300822013-04-09 12:57:49 -07008
9updateTopology = function() {
10
11 // DRAW THE SWITCHES
Paul Greysone15c4392013-04-09 15:05:31 -070012 var rings = svg.selectAll('.ring').data(createTopologyModel(model));
Paul Greyson7a300822013-04-09 12:57:49 -070013
14 function ringEnter(data, i) {
15 if (!data.length) {
16 return;
17 }
18
19 // create the nodes
20 var nodes = d3.select(this).selectAll("g")
21 .data(data, function (data) {
22 return data.dpid;
23 })
24 .enter().append("svg:g")
25 .attr("id", function (data, i) {
26 return data.dpid;
27 })
28 .attr("transform", function(data, i) {
29 return "rotate(" + data.angle+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angle) + ")";
30 });
31
32 // add the cirles representing the switches
33 nodes.append("svg:circle")
34 .attr("transform", function(data, i) {
35 var m = document.querySelector('#viewbox').getTransformToElement().inverse();
36 if (data.scale) {
37 m = m.scale(data.scale);
38 }
39 return "matrix( " + m.a + " " + m.b + " " + m.c + " " + m.d + " " + m.e + " " + m.f + " )";
40 })
41 .attr("x", function (data) {
42 return -data.width / 2;
43 })
44 .attr("y", function (data) {
45 return -data.width / 2;
46 })
47 .attr("r", function (data) {
48 return data.width;
49 });
50
51 // setup the mouseover behaviors
52 nodes.on('mouseover', mouseOverSwitch);
53 nodes.on('mouseout', mouseOutSwitch);
54 nodes.on('mouseup', mouseUpSwitch);
55 nodes.on('mousedown', mouseDownSwitch);
56
57 // only do switch up/down for core switches
58 if (i == 2) {
59 nodes.on('dblclick', doubleClickSwitch);
60 }
61 }
62
63 // append switches
64 rings.enter().append("svg:g")
65 .attr("class", "ring")
66 .each(ringEnter);
67
68
69 function ringUpdate(data, i) {
70 var nodes = d3.select(this).selectAll("g")
71 .data(data, function (data) {
72 return data.dpid;
73 });
74 nodes.select('circle')
75 .each(function (data) {
76 // if there's a pending state changed and then the state changes, clear the pending class
77 var circle = d3.select(this);
78 if (data.state === 'ACTIVE' && circle.classed('inactive') ||
79 data.state === 'INACTIVE' && circle.classed('active')) {
80 circle.classed('pending', false);
81 }
82 })
83 .attr('class', function (data) {
84 if (data.state === 'ACTIVE' && data.controller) {
85 return data.className + ' active ' + controllerColorMap[data.controller];
86 } else {
87 return data.className + ' inactive ' + 'colorInactive';
88 }
89 });
90 }
91
92 // update switches
93 rings.each(ringUpdate);
94
95
96 // Now setup the labels
97 // This is done separately because SVG draws in node order and we want the labels
98 // always on top
Paul Greysone15c4392013-04-09 15:05:31 -070099 var labelRings = svg.selectAll('.labelRing').data(createTopologyModel(model));
Paul Greyson7a300822013-04-09 12:57:49 -0700100
101 d3.select(document.body).on('mousemove', function () {
102 if (!d3.select('#topology').classed('linking')) {
103 return;
104 }
105 var linkVector = document.getElementById('linkVector');
106 if (!linkVector) {
107 return;
108 }
109 linkVector = d3.select(linkVector);
110
111 var highlighted = svg.selectAll('.highlight')[0];
112 var s1 = null, s2 = null;
113 if (highlighted.length > 1) {
114 var s1 = d3.select(highlighted[0]);
115 var s2 = d3.select(highlighted[1]);
116
117 } else if (highlighted.length > 0) {
118 var s1 = d3.select(highlighted[0]);
119 }
120 var src = s1;
121 if (s2 && !s2.data()[0].target) {
122 src = s2;
123 }
124 if (src) {
125 linkVector.attr('d', function () {
126 var srcPt = document.querySelector('svg').createSVGPoint();
127 srcPt.x = src.attr('x');
128 srcPt.y = src.attr('y');
129 srcPt = srcPt.matrixTransform(src[0][0].getCTM());
130
131 var svg = document.getElementById('topology');
132 var mouse = d3.mouse(viewbox);
133 var dstPt = document.querySelector('svg').createSVGPoint();
134 dstPt.x = mouse[0];
135 dstPt.y = mouse[1];
136 dstPt = dstPt.matrixTransform(viewbox.getCTM());
137
138 return line([srcPt, dstPt]);
139 });
140 }
141 });
142
Paul Greyson7a300822013-04-09 12:57:49 -0700143 function labelRingEnter(data) {
144 if (!data.length) {
145 return;
146 }
147
148 // create the nodes
149 var nodes = d3.select(this).selectAll("g")
150 .data(data, function (data) {
151 return data.dpid;
152 })
153 .enter().append("svg:g")
154 .classed('nolabel', true)
155 .attr("id", function (data) {
156 return data.dpid + '-label';
157 })
158 .attr("transform", function(data, i) {
159 return "rotate(" + data.angle+ ")translate(" + data.radius * 150 + ")rotate(" + (-data.angle) + ")";
160 })
161
162 // add the text nodes which show on mouse over
163 nodes.append("svg:text")
164 .text(function (data) {return data.dpid;})
165 .attr("x", function (data) {
166 if (data.angle <= 90 || data.angle >= 270 && data.angle <= 360) {
167 if (data.className == 'edge') {
168 return - data.width*3 - 4;
169 } else {
170 return - data.width - 4;
171 }
172 } else {
173 if (data.className == 'edge') {
174 return data.width*3 + 4;
175 } else {
176 return data.width + 4;
177 }
178 }
179 })
180 .attr("y", function (data) {
181 var y;
182 if (data.angle <= 90 || data.angle >= 270 && data.angle <= 360) {
183 if (data.className == 'edge') {
184 y = data.width*3/2 + 4;
185 } else {
186 y = data.width/2 + 4;
187 }
188 } else {
189 if (data.className == 'edge') {
190 y = data.width*3/2 + 4;
191 } else {
192 y = data.width/2 + 4;
193 }
194 }
195 return y - 6;
196 })
197 .attr("text-anchor", function (data) {
198 if (data.angle <= 90 || data.angle >= 270 && data.angle <= 360) {
199 return "end";
200 } else {
201 return "start";
202 }
203 })
204 .attr("transform", function(data) {
205 var m = document.querySelector('#viewbox').getTransformToElement().inverse();
206 if (data.scale) {
207 m = m.scale(data.scale);
208 }
209 return "matrix( " + m.a + " " + m.b + " " + m.c + " " + m.d + " " + m.e + " " + m.f + " )";
210 })
211 }
212
213 labelRings.enter().append("svg:g")
214 .attr("class", "textRing")
215 .each(labelRingEnter);
216
217 // switches should not change during operation of the ui so no
218 // rings.exit()
219
220
221 // DRAW THE LINKS
222
223 // key on link dpids since these will come/go during demo
Paul Greysone15c4392013-04-09 15:05:31 -0700224 var linkLines = d3.select('svg').selectAll('.link').data(links, function (d) {
Paul Greyson7a300822013-04-09 12:57:49 -0700225 return d['src-switch']+'->'+d['dst-switch'];
226 });
227
228 // add new links
Paul Greysone15c4392013-04-09 15:05:31 -0700229 linkLines.enter().append("svg:path")
Paul Greyson7a300822013-04-09 12:57:49 -0700230 .attr("class", "link");
231
Paul Greysone15c4392013-04-09 15:05:31 -0700232 linkLines.attr('id', function (d) {
Paul Greyson7a300822013-04-09 12:57:49 -0700233 return makeLinkKey(d);
234 })
235 .attr("d", function (d) {
236 var src = d3.select(document.getElementById(d['src-switch']));
237 var dst = d3.select(document.getElementById(d['dst-switch']));
238
239 var srcPt = document.querySelector('svg').createSVGPoint();
240 srcPt.x = src.attr('x');
241 srcPt.y = src.attr('y');
242 srcPt = srcPt.matrixTransform(src[0][0].getCTM());
243
244 var dstPt = document.querySelector('svg').createSVGPoint();
245 dstPt.x = dst.attr('x');
246 dstPt.y = dst.attr('y');
247 dstPt = dstPt.matrixTransform(dst[0][0].getCTM());
248
249 var midPt = document.querySelector('svg').createSVGPoint();
250 midPt.x = (srcPt.x + dstPt.x)/2;
251 midPt.y = (srcPt.y + dstPt.y)/2;
252
253 return line([srcPt, midPt, dstPt]);
254 })
255 .attr("marker-mid", function(d) { return "url(#arrow)"; })
256 .classed('pending', function (d) {
257 return d.pending;
258 });
259
260
261 // remove old links
Paul Greysone15c4392013-04-09 15:05:31 -0700262 linkLines.exit().remove();
263}
264
265})();