blob: 28d418b620130f397c208fd4a0209c2a42f9a51c [file] [log] [blame]
Paul Greyson15e5da22013-04-10 00:16:27 -07001function clearHighlight() {
2 topology.selectAll('circle').each(function (data) {
3 data.mouseDown = false;
4 d3.select('#topologyArea').classed('linking', false);
5 mouseOutSwitch(data);
6 });
7 d3.select('#linkVector').remove();
8};
9
Paul Greysone15c4392013-04-09 15:05:31 -070010function mouseOverSwitch(data) {
11
12 d3.event.preventDefault();
13
14 d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
15
16 if (data.highlighted) {
17 return;
18 }
19
20 // only highlight valid link or flow destination by checking for class of existing highlighted circle
Paul Greysonc090d142013-04-09 16:59:03 -070021 var highlighted = topology.selectAll('.highlight')[0];
Paul Greysone15c4392013-04-09 15:05:31 -070022 if (highlighted.length == 1) {
23 var s = d3.select(highlighted[0]).select('circle');
24 // only allow links
25 // edge->edge (flow)
26 // aggregation->core
27 // core->core
28 if (data.className == 'edge' && !s.classed('edge') ||
29 data.className == 'core' && !s.classed('core') && !s.classed('aggregation') ||
30 data.className == 'aggregation' && !s.classed('core')) {
31 return;
32 }
33
34 // the second highlighted switch is the target for a link or flow
35 data.target = true;
36 }
37
38 var node = d3.select(document.getElementById(data.dpid));
39 node.classed('highlight', true).select('circle').transition().duration(100).attr("r", widths.core);
40 data.highlighted = true;
41 node.moveToFront();
42}
43
44function mouseOutSwitch(data) {
45 d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
46
47 if (data.mouseDown)
48 return;
49
50 var node = d3.select(document.getElementById(data.dpid));
51 node.classed('highlight', false).select('circle').transition().duration(100).attr("r", widths[data.className]);
52 data.highlighted = false;
53 data.target = false;
54}
55
56function mouseDownSwitch(data) {
57 mouseOverSwitch(data);
58 data.mouseDown = true;
Paul Greysonc090d142013-04-09 16:59:03 -070059 d3.select('#topologyArea').classed('linking', true);
Paul Greysone15c4392013-04-09 15:05:31 -070060
61 d3.select('svg')
62 .append('svg:path')
63 .attr('id', 'linkVector')
64 .attr('d', function () {
65 var s = d3.select(document.getElementById(data.dpid));
66
67 var pt = document.querySelector('svg').createSVGPoint();
68 pt.x = s.attr('x');
69 pt.y = s.attr('y');
70 pt = pt.matrixTransform(s[0][0].getCTM());
71
72 return line([pt, pt]);
73 });
74
75
76 if (data.className === 'core') {
77 d3.selectAll('.edge').classed('nodrop', true);
78 }
79 if (data.className === 'edge') {
80 d3.selectAll('.core').classed('nodrop', true);
81 d3.selectAll('.aggregation').classed('nodrop', true);
82 }
83 if (data.className === 'aggregation') {
84 d3.selectAll('.edge').classed('nodrop', true);
85 d3.selectAll('.aggregation').classed('nodrop', true);
86 }
87}
88
89function mouseUpSwitch(data) {
90 if (data.mouseDown) {
91 data.mouseDown = false;
Paul Greysonc090d142013-04-09 16:59:03 -070092 d3.select('#topologyArea').classed('linking', false);
Paul Greysone15c4392013-04-09 15:05:31 -070093 d3.event.stopPropagation();
94 d3.selectAll('.nodrop').classed('nodrop', false);
95 }
96}
97
98function doubleClickSwitch(data) {
Paul Greyson15e5da22013-04-10 00:16:27 -070099 clearHighlight();
100
Paul Greysone15c4392013-04-09 15:05:31 -0700101 var circle = d3.select(document.getElementById(data.dpid)).select('circle');
102 if (data.state == 'ACTIVE') {
103 var prompt = 'Deactivate ' + data.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700104 doConfirm(prompt, function(result) {
105 if (result) {
106 switchDown(data);
107 setPending(circle);
108 }
109 });
Paul Greysone15c4392013-04-09 15:05:31 -0700110 } else {
111 var prompt = 'Activate ' + data.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700112 doConfirm(prompt, function (result) {
113 if (result) {
114 switchUp(data);
115 setPending(circle);
116 }
117 });
Paul Greysone15c4392013-04-09 15:05:31 -0700118 }
119}
120
Paul Greyson15e5da22013-04-10 00:16:27 -0700121d3.select(window).on('mouseup', function () {
Paul Greysone15c4392013-04-09 15:05:31 -0700122 d3.selectAll('.nodrop').classed('nodrop', false);
123
124 function removeLink(link) {
125 var path1 = document.getElementById(link['src-switch'] + '=>' + link['dst-switch']);
126 var path2 = document.getElementById(link['dst-switch'] + '=>' + link['src-switch']);
127
128 if (path1) {
129 setPending(d3.select(path1));
130 }
131 if (path2) {
132 setPending(d3.select(path2));
133 }
134
135 linkDown(link);
136 }
137
138
Paul Greysonc090d142013-04-09 16:59:03 -0700139 var highlighted = topology.selectAll('.highlight')[0];
Paul Greysone15c4392013-04-09 15:05:31 -0700140 if (highlighted.length == 2) {
141 var s1Data = highlighted[0].__data__;
142 var s2Data = highlighted[1].__data__;
143
144 var srcData, dstData;
145 if (s1Data.target) {
146 dstData = s1Data;
147 srcData = s2Data;
148 } else {
149 dstData = s2Data;
150 srcData = s1Data;
151 }
152
153 if (s1Data.className == 'edge' && s2Data.className == 'edge') {
154 var prompt = 'Create flow from ' + srcData.dpid + ' to ' + dstData.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700155 doConfirm(prompt, function (result) {
156 if (result) {
157 addFlow(srcData, dstData);
Paul Greysone15c4392013-04-09 15:05:31 -0700158
Paul Greyson28cf92b2013-04-10 13:15:06 -0700159 var flow = {
160 dataPath: {
161 srcPort: {
162 dpid: {
163 value: srcData.dpid
164 }
165 },
166 dstPort: {
167 dpid: {
168 value: dstData.dpid
169 }
Paul Greysone15c4392013-04-09 15:05:31 -0700170 }
171 },
Paul Greyson28cf92b2013-04-10 13:15:06 -0700172 srcDpid: srcData.dpid,
173 dstDpid: dstData.dpid,
174 createPending: true
175 };
Paul Greysone15c4392013-04-09 15:05:31 -0700176
Paul Greyson28cf92b2013-04-10 13:15:06 -0700177 selectFlow(flow);
Paul Greysone15c4392013-04-09 15:05:31 -0700178
Paul Greyson28cf92b2013-04-10 13:15:06 -0700179 setTimeout(function () {
180 deselectFlowIfCreatePending(flow);
181 }, pendingTimeout);
182 }
183 });
184
Paul Greysone15c4392013-04-09 15:05:31 -0700185 } else {
186 var map = linkMap[srcData.dpid];
187 if (map && map[dstData.dpid]) {
188 var prompt = 'Remove link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700189 doConfirm(prompt, function (result) {
190 if (result) {
191 removeLink(map[dstData.dpid]);
192 }
193 });
Paul Greysone15c4392013-04-09 15:05:31 -0700194 } else {
195 map = linkMap[dstData.dpid];
196 if (map && map[srcData.dpid]) {
197 var prompt = 'Remove link between ' + dstData.dpid + ' and ' + srcData.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700198 doConfirm(prompt, function (result) {
199 if (result) {
200 removeLink(map[srcData.dpid]);
201 }
202 });
Paul Greysone15c4392013-04-09 15:05:31 -0700203 } else {
204 var prompt = 'Create link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
Paul Greyson28cf92b2013-04-10 13:15:06 -0700205 doConfirm(prompt, function (result) {
206 if (result) {
207 var link1 = {
208 'src-switch': srcData.dpid,
209 'src-port': 1,
210 'dst-switch': dstData.dpid,
211 'dst-port': 1,
212 pending: true
213 };
214 pendingLinks[makeLinkKey(link1)] = link1;
215 var link2 = {
216 'src-switch': dstData.dpid,
217 'src-port': 1,
218 'dst-switch': srcData.dpid,
219 'dst-port': 1,
220 pending: true
221 };
222 pendingLinks[makeLinkKey(link2)] = link2;
Paul Greysone15c4392013-04-09 15:05:31 -0700223 updateTopology();
Paul Greyson28cf92b2013-04-10 13:15:06 -0700224
225 linkUp(link1);
226
227 // remove the pending links after 10s
228 setTimeout(function () {
229 delete pendingLinks[makeLinkKey(link1)];
230 delete pendingLinks[makeLinkKey(link2)];
231
232 updateTopology();
233 }, pendingTimeout);
234 }
235 });
Paul Greysone15c4392013-04-09 15:05:31 -0700236 }
237 }
238 }
239
240 clearHighlight();
241 } else {
242 clearHighlight();
243 }
Paul Greyson30636252013-04-09 15:22:04 -0700244});
245
246d3.select(document.body).on('mousemove', function () {
Paul Greysonc090d142013-04-09 16:59:03 -0700247 if (!d3.select('#topologyArea').classed('linking')) {
Paul Greyson30636252013-04-09 15:22:04 -0700248 return;
249 }
250 var linkVector = document.getElementById('linkVector');
251 if (!linkVector) {
252 return;
253 }
254 linkVector = d3.select(linkVector);
255
Paul Greysonc090d142013-04-09 16:59:03 -0700256 var highlighted = topology.selectAll('.highlight')[0];
Paul Greyson30636252013-04-09 15:22:04 -0700257 var s1 = null, s2 = null;
258 if (highlighted.length > 1) {
259 var s1 = d3.select(highlighted[0]);
260 var s2 = d3.select(highlighted[1]);
261
262 } else if (highlighted.length > 0) {
263 var s1 = d3.select(highlighted[0]);
264 }
265 var src = s1;
266 if (s2 && !s2.data()[0].target) {
267 src = s2;
268 }
269 if (src) {
270 linkVector.attr('d', function () {
271 var srcPt = document.querySelector('svg').createSVGPoint();
272 srcPt.x = src.attr('x');
273 srcPt.y = src.attr('y');
274 srcPt = srcPt.matrixTransform(src[0][0].getCTM());
275
276 var svg = document.getElementById('topology');
277 var mouse = d3.mouse(viewbox);
278 var dstPt = document.querySelector('svg').createSVGPoint();
279 dstPt.x = mouse[0];
280 dstPt.y = mouse[1];
281 dstPt = dstPt.matrixTransform(viewbox.getCTM());
282
283 return line([srcPt, dstPt]);
284 });
285 }
286});