blob: 9f72fe2917b10dc9390f2722c67a6599ef9ab05a [file] [log] [blame]
Paul Greyson2794ca62013-04-10 00:33:30 -07001function startFlowAnimation(flow) {
Paul Greysoneeb69962013-04-12 15:53:29 -07002// console.log('starting animation for flow: ' + flow.flowId);
3
4 var flowSelection = d3.select(document.getElementById(makeFlowKey(flow)));
5 if (flowSelection.select('animate').empty()) {
6 flowSelection.append('svg:animate')
Paul Greyson2794ca62013-04-10 00:33:30 -07007 .attr('attributeName', 'stroke-dashoffset')
8 .attr('attributeType', 'xml')
9 .attr('from', '500')
10 .attr('to', '-500')
11 .attr('dur', '20s')
12 .attr('repeatCount', 'indefinite');
13 }
14}
15
16function stopFlowAnimation(flow) {
Paul Greysoneeb69962013-04-12 15:53:29 -070017 var flowSelection = d3.select(document.getElementById(makeFlowKey(flow)));
18 flowSelection.select('animate').remove();
Paul Greyson2794ca62013-04-10 00:33:30 -070019}
20
21
Paul Greyson7a300822013-04-09 12:57:49 -070022function updateSelectedFlowsTopology() {
23 // DRAW THE FLOWS
24 var topologyFlows = [];
25 selectedFlows.forEach(function (flow) {
26 if (flow) {
27 topologyFlows.push(flow);
28 }
29 });
30
Paul Greysoneeb69962013-04-12 15:53:29 -070031 var flows = flowLayer.selectAll('.flow').data(topologyFlows, function (d) {
32 return d.flowId;
33 });
Paul Greyson7a300822013-04-09 12:57:49 -070034
35 flows.enter().append("svg:path").attr('class', 'flow')
36 .attr('stroke-dasharray', '4, 10')
Paul Greyson7a300822013-04-09 12:57:49 -070037
38 flows.exit().remove();
39
40 flows.attr('d', function (d) {
41 if (!d) {
42 return;
43 }
44 var pts = [];
Paul Greyson45aceb22013-04-09 22:17:03 -070045 if (d.createPending) {
Paul Greyson7a300822013-04-09 12:57:49 -070046 // create a temporary vector to indicate the pending flow
47 var s1 = d3.select(document.getElementById(d.srcDpid));
48 var s2 = d3.select(document.getElementById(d.dstDpid));
49
50 var pt1 = document.querySelector('svg').createSVGPoint();
51 pt1.x = s1.attr('x');
52 pt1.y = s1.attr('y');
Paul Greysonbbd708b2013-04-09 22:37:31 -070053 if (drawingRings) {
54 pt1 = pt1.matrixTransform(s1[0][0].getCTM());
55 }
Paul Greyson7a300822013-04-09 12:57:49 -070056 pts.push(pt1);
57
58 var pt2 = document.querySelector('svg').createSVGPoint();
59 pt2.x = s2.attr('x');
60 pt2.y = s2.attr('y');
Paul Greysonbbd708b2013-04-09 22:37:31 -070061 if (drawingRings) {
62 pt2 = pt2.matrixTransform(s2[0][0].getCTM());
63 }
Paul Greyson7a300822013-04-09 12:57:49 -070064 pts.push(pt2);
65
Paul Greyson45aceb22013-04-09 22:17:03 -070066 } else if (d.dataPath && d.dataPath.flowEntries) {
Paul Greyson7a300822013-04-09 12:57:49 -070067 d.dataPath.flowEntries.forEach(function (flowEntry) {
68 var s = d3.select(document.getElementById(flowEntry.dpid.value));
69 // s[0] is null if the flow entry refers to a non-existent switch
70 if (s[0][0]) {
71 var pt = document.querySelector('svg').createSVGPoint();
72 pt.x = s.attr('x');
73 pt.y = s.attr('y');
Paul Greysonbbd708b2013-04-09 22:37:31 -070074 if (drawingRings) {
75 pt = pt.matrixTransform(s[0][0].getCTM());
76 }
Paul Greyson7a300822013-04-09 12:57:49 -070077 pts.push(pt);
78 } else {
79 console.log('flow refers to non-existent switch: ' + flowEntry.dpid.value);
80 }
81 });
82 }
83 if (pts.length) {
84 return line(pts);
85 } else {
86 return "M0,0";
87 }
88 })
89 .attr('id', function (d) {
90 if (d) {
91 return makeFlowKey(d);
92 }
93 })
94 .classed('pending', function (d) {
95 return d && (d.createPending || d.deletePending);
96 });
Paul Greyson7a300822013-04-09 12:57:49 -070097}
98
99function updateSelectedFlowsTable() {
100 function rowEnter(d) {
101 var row = d3.select(this);
102 row.append('div').classed('deleteFlow', true);
103 row.append('div').classed('flowId', true);
104 row.append('div').classed('srcDPID', true);
105 row.append('div').classed('dstDPID', true);
106 row.append('div').classed('iperf', true);
107
108 row.select('.iperf')
109 .append('div')
110 .attr('class', 'iperf-container')
111 .append('svg:svg')
112 .attr('viewBox', '0 0 1000 32')
113 .attr('preserveAspectRatio', 'none')
114 .append('svg:g')
115 .append('svg:path')
116 .attr('class', 'iperfdata');
117
118 row.on('mouseover', function (d) {
119 if (d) {
120 var path = document.getElementById(makeFlowKey(d));
121 d3.select(path).classed('highlight', true);
122 }
123 });
124 row.on('mouseout', function (d) {
125 if (d) {
126 var path = document.getElementById(makeFlowKey(d));
127 d3.select(path).classed('highlight', false);
128 }
129 });
130 }
131
132 function rowUpdate(d) {
133 var row = d3.select(this);
134 row.attr('id', function (d) {
135 if (d) {
136 return makeSelectedFlowKey(d);
137 }
138 });
139
140 if (!d || !hasIPerf(d)) {
141 row.select('.iperfdata')
142 .attr('d', 'M0,0');
143 }
144
145 row.select('.deleteFlow').on('click', function () {
146 deselectFlow(d);
147 });
148 row.on('dblclick', function () {
149 if (d) {
150 var prompt = 'Delete flow ' + d.flowId + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700151 doConfirm(prompt, function (result) {
152 if (result) {
153 deleteFlow(d);
154 d.deletePending = true;
Paul Greyson7a300822013-04-09 12:57:49 -0700155 updateSelectedFlows();
Paul Greyson28cf92b2013-04-10 13:15:06 -0700156
157 setTimeout(function () {
158 d.deletePending = false;
159 updateSelectedFlows();
160 }, pendingTimeout)
161 };
162 });
Paul Greyson7a300822013-04-09 12:57:49 -0700163 }
164 });
165
166 row.select('.flowId')
167 .text(function (d) {
168 if (d) {
169 if (d.flowId) {
170 return d.flowId;
171 } else {
172 return '0x--';
173 }
174 }
175 })
176 .classed('pending', function (d) {
177 return d && (d.createPending || d.deletePending);
178 });
179
180 row.select('.srcDPID')
181 .text(function (d) {
182 if (d) {
183 return d.srcDpid;
184 }
185 });
186
187 row.select('.dstDPID')
188 .text(function (d) {
189 if (d) {
190 return d.dstDpid;
191 }
192 });
193 }
194
195 var flows = d3.select('#selectedFlows')
196 .selectAll('.selectedFlow')
197 .data(selectedFlows);
198
199 flows.enter()
200 .append('div')
201 .classed('selectedFlow', true)
202 .each(rowEnter);
203
204 flows.each(rowUpdate);
205
206 flows.exit().remove();
207}
208
Paul Greyson7a300822013-04-09 12:57:49 -0700209function updateSelectedFlows() {
210 // make sure that all of the selected flows are either
211 // 1) valid (meaning they are in the latest list of flows)
212 // 2) pending
213 if (model) {
214 var flowMap = {};
215 model.flows.forEach(function (flow) {
216 flowMap[makeFlowKey(flow)] = flow;
217 });
218
219 var newSelectedFlows = [];
220 selectedFlows.forEach(function (flow) {
221 if (flow) {
222 var liveFlow = flowMap[makeFlowKey(flow)];
223 if (liveFlow) {
Paul Greysone6532cd2013-04-12 14:53:34 -0700224 flow.flowId = liveFlow.flowId;
225 if (flow.createPending) {
226 startIPerfForFlow(flow);
227 flow.createPending = false;
228 }
Paul Greyson17f84472013-04-12 14:39:21 -0700229 flow.dataPath = liveFlow.dataPath;
230 newSelectedFlows.push(flow);
Paul Greyson7a300822013-04-09 12:57:49 -0700231 } else if (flow.createPending) {
232 newSelectedFlows.push(flow);
233 } else if (hasIPerf(flow)) {
234 clearIPerf(flow);
235 }
236 }
237 });
238 selectedFlows = newSelectedFlows;
239 }
240 selectedFlows.forEach(function (flow) {
241 if (!hasIPerf(flow)) {
242 startIPerfForFlow(flow);
243 }
244 });
245 while (selectedFlows.length < 3) {
246 selectedFlows.push(null);
247 }
248
249 updateSelectedFlowsTable();
Paul Greysonbbd708b2013-04-09 22:37:31 -0700250 // on app init, the table is updated before the svg is constructed
251 if (flowLayer) {
252 updateSelectedFlowsTopology();
253 }
Paul Greyson7a300822013-04-09 12:57:49 -0700254}
255
256function selectFlow(flow) {
257 var flowKey = makeFlowKey(flow);
258 var alreadySelected = false;
259 selectedFlows.forEach(function (f) {
260 if (f && makeFlowKey(f) === flowKey) {
261 alreadySelected = true;
262 }
263 });
264
265 if (!alreadySelected) {
266 selectedFlows.unshift(flow);
267 selectedFlows = selectedFlows.slice(0, 3);
268 updateSelectedFlows();
269 }
270}
271
Paul Greyson7a300822013-04-09 12:57:49 -0700272function deselectFlow(flow, ifCreatePending) {
Paul Greysonaf750bf2013-04-09 23:26:37 -0700273 if (!flow) {
274 return;
275 }
276
Paul Greyson7a300822013-04-09 12:57:49 -0700277 var flowKey = makeFlowKey(flow);
278 var newSelectedFlows = [];
279 selectedFlows.forEach(function (flow) {
280 if (!flow ||
281 flowKey !== makeFlowKey(flow) ||
282 flowKey === makeFlowKey(flow) && ifCreatePending && !flow.createPending ) {
283 newSelectedFlows.push(flow);
284 } else {
285 if (hasIPerf(flow)) {
286 clearIPerf(flow);
287 }
288 }
289 });
290 selectedFlows = newSelectedFlows;
291 while (selectedFlows.length < 3) {
292 selectedFlows.push(null);
293 }
294
295 updateSelectedFlows();
296}
297
298function deselectFlowIfCreatePending(flow) {
299 deselectFlow(flow, true);
300}
301
302function showFlowChooser() {
303 function rowEnter(d) {
304 var row = d3.select(this);
305
306 row.append('div')
307 .classed('black-eye', true).
308 on('click', function () {
309 selectFlow(d);
310 });
311
312 row.append('div')
313 .classed('flowId', true)
314 .text(function (d) {
315 return d.flowId;
316 });
317
318 row.append('div')
319 .classed('srcDPID', true)
320 .text(function (d) {
321 return d.srcDpid;
322 });
323
324
325 row.append('div')
326 .classed('dstDPID', true)
327 .text(function (d) {
328 return d.dstDpid;
329 });
330
331 }
332
Paul Greysonf3070172013-04-09 23:37:00 -0700333 var flowChooser = d3.select(document.getElementById('flowChooser'));
334 flowChooser.html('');
335 flowChooser.style('-webkit-transform', 'translate3d(-100%, 0, 0)')
336 .style('-webkit-transition');
337
338 var flows = flowChooser
Paul Greyson7a300822013-04-09 12:57:49 -0700339 .append('div')
340 .style('pointer-events', 'auto')
341 .selectAll('.selectedFlow')
342 .data(model.flows)
343 .enter()
344 .append('div')
345 .classed('selectedFlow', true)
346 .each(rowEnter);
347
Paul Greysonf3070172013-04-09 23:37:00 -0700348
Paul Greyson7a300822013-04-09 12:57:49 -0700349 setTimeout(function () {
Paul Greysonf3070172013-04-09 23:37:00 -0700350 flowChooser.style('-webkit-transition', '-webkit-transform .25s');
351 setTimeout(function () {
352 flowChooser.style('-webkit-transform', 'translate3d(0,0,0)');
353 }, 0);
354
355
Paul Greyson7a300822013-04-09 12:57:49 -0700356 d3.select(document.body).on('click', function () {
Paul Greysonf3070172013-04-09 23:37:00 -0700357 flowChooser.style('-webkit-transform', 'translate3d(-100%, 0, 0)')
Paul Greyson7a300822013-04-09 12:57:49 -0700358 d3.select(document.body).on('click', null);
359 });
360 }, 0);
361}