blob: 6501e5b24f3d1b645e7709e43656cf44f93be486 [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 + '?';
104 if (confirm(prompt)) {
105 switchDown(data);
106 setPending(circle);
107 }
108 } else {
109 var prompt = 'Activate ' + data.dpid + '?';
110 if (confirm(prompt)) {
111 switchUp(data);
112 setPending(circle);
113 }
114 }
115}
116
Paul Greyson15e5da22013-04-10 00:16:27 -0700117d3.select(window).on('mouseup', function () {
Paul Greysone15c4392013-04-09 15:05:31 -0700118 d3.selectAll('.nodrop').classed('nodrop', false);
119
120 function removeLink(link) {
121 var path1 = document.getElementById(link['src-switch'] + '=>' + link['dst-switch']);
122 var path2 = document.getElementById(link['dst-switch'] + '=>' + link['src-switch']);
123
124 if (path1) {
125 setPending(d3.select(path1));
126 }
127 if (path2) {
128 setPending(d3.select(path2));
129 }
130
131 linkDown(link);
132 }
133
134
Paul Greysonc090d142013-04-09 16:59:03 -0700135 var highlighted = topology.selectAll('.highlight')[0];
Paul Greysone15c4392013-04-09 15:05:31 -0700136 if (highlighted.length == 2) {
137 var s1Data = highlighted[0].__data__;
138 var s2Data = highlighted[1].__data__;
139
140 var srcData, dstData;
141 if (s1Data.target) {
142 dstData = s1Data;
143 srcData = s2Data;
144 } else {
145 dstData = s2Data;
146 srcData = s1Data;
147 }
148
149 if (s1Data.className == 'edge' && s2Data.className == 'edge') {
150 var prompt = 'Create flow from ' + srcData.dpid + ' to ' + dstData.dpid + '?';
151 if (confirm(prompt)) {
152 addFlow(srcData, dstData);
153
154 var flow = {
155 dataPath: {
156 srcPort: {
157 dpid: {
158 value: srcData.dpid
159 }
160 },
161 dstPort: {
162 dpid: {
163 value: dstData.dpid
164 }
165 }
166 },
167 srcDpid: srcData.dpid,
168 dstDpid: dstData.dpid,
169 createPending: true
170 };
171
172 selectFlow(flow);
173
174 setTimeout(function () {
175 deselectFlowIfCreatePending(flow);
176 }, pendingTimeout);
177 }
178 } else {
179 var map = linkMap[srcData.dpid];
180 if (map && map[dstData.dpid]) {
181 var prompt = 'Remove link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
182 if (confirm(prompt)) {
183 removeLink(map[dstData.dpid]);
184 }
185 } else {
186 map = linkMap[dstData.dpid];
187 if (map && map[srcData.dpid]) {
188 var prompt = 'Remove link between ' + dstData.dpid + ' and ' + srcData.dpid + '?';
189 if (confirm(prompt)) {
190 removeLink(map[srcData.dpid]);
191 }
192 } else {
193 var prompt = 'Create link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
194 if (confirm(prompt)) {
195 var link1 = {
196 'src-switch': srcData.dpid,
197 'src-port': 1,
198 'dst-switch': dstData.dpid,
199 'dst-port': 1,
200 pending: true
201 };
202 pendingLinks[makeLinkKey(link1)] = link1;
203 var link2 = {
204 'src-switch': dstData.dpid,
205 'src-port': 1,
206 'dst-switch': srcData.dpid,
207 'dst-port': 1,
208 pending: true
209 };
210 pendingLinks[makeLinkKey(link2)] = link2;
211 updateTopology();
212
213 linkUp(link1);
214
215 // remove the pending links after 10s
216 setTimeout(function () {
217 delete pendingLinks[makeLinkKey(link1)];
218 delete pendingLinks[makeLinkKey(link2)];
219
220 updateTopology();
221 }, pendingTimeout);
222 }
223 }
224 }
225 }
226
227 clearHighlight();
228 } else {
229 clearHighlight();
230 }
Paul Greyson30636252013-04-09 15:22:04 -0700231});
232
233d3.select(document.body).on('mousemove', function () {
Paul Greysonc090d142013-04-09 16:59:03 -0700234 if (!d3.select('#topologyArea').classed('linking')) {
Paul Greyson30636252013-04-09 15:22:04 -0700235 return;
236 }
237 var linkVector = document.getElementById('linkVector');
238 if (!linkVector) {
239 return;
240 }
241 linkVector = d3.select(linkVector);
242
Paul Greysonc090d142013-04-09 16:59:03 -0700243 var highlighted = topology.selectAll('.highlight')[0];
Paul Greyson30636252013-04-09 15:22:04 -0700244 var s1 = null, s2 = null;
245 if (highlighted.length > 1) {
246 var s1 = d3.select(highlighted[0]);
247 var s2 = d3.select(highlighted[1]);
248
249 } else if (highlighted.length > 0) {
250 var s1 = d3.select(highlighted[0]);
251 }
252 var src = s1;
253 if (s2 && !s2.data()[0].target) {
254 src = s2;
255 }
256 if (src) {
257 linkVector.attr('d', function () {
258 var srcPt = document.querySelector('svg').createSVGPoint();
259 srcPt.x = src.attr('x');
260 srcPt.y = src.attr('y');
261 srcPt = srcPt.matrixTransform(src[0][0].getCTM());
262
263 var svg = document.getElementById('topology');
264 var mouse = d3.mouse(viewbox);
265 var dstPt = document.querySelector('svg').createSVGPoint();
266 dstPt.x = mouse[0];
267 dstPt.y = mouse[1];
268 dstPt = dstPt.matrixTransform(viewbox.getCTM());
269
270 return line([srcPt, dstPt]);
271 });
272 }
273});