blob: 843f82953a94e9cd03d79473a165e48b6b3dcc7b [file] [log] [blame]
Paul Greysone15c4392013-04-09 15:05:31 -07001function mouseOverSwitch(data) {
2
3 d3.event.preventDefault();
4
5 d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', false);
6
7 if (data.highlighted) {
8 return;
9 }
10
11 // only highlight valid link or flow destination by checking for class of existing highlighted circle
Paul Greysonc090d142013-04-09 16:59:03 -070012 var highlighted = topology.selectAll('.highlight')[0];
Paul Greysone15c4392013-04-09 15:05:31 -070013 if (highlighted.length == 1) {
14 var s = d3.select(highlighted[0]).select('circle');
15 // only allow links
16 // edge->edge (flow)
17 // aggregation->core
18 // core->core
19 if (data.className == 'edge' && !s.classed('edge') ||
20 data.className == 'core' && !s.classed('core') && !s.classed('aggregation') ||
21 data.className == 'aggregation' && !s.classed('core')) {
22 return;
23 }
24
25 // the second highlighted switch is the target for a link or flow
26 data.target = true;
27 }
28
29 var node = d3.select(document.getElementById(data.dpid));
30 node.classed('highlight', true).select('circle').transition().duration(100).attr("r", widths.core);
31 data.highlighted = true;
32 node.moveToFront();
33}
34
35function mouseOutSwitch(data) {
36 d3.select(document.getElementById(data.dpid + '-label')).classed('nolabel', true);
37
38 if (data.mouseDown)
39 return;
40
41 var node = d3.select(document.getElementById(data.dpid));
42 node.classed('highlight', false).select('circle').transition().duration(100).attr("r", widths[data.className]);
43 data.highlighted = false;
44 data.target = false;
45}
46
47function mouseDownSwitch(data) {
48 mouseOverSwitch(data);
49 data.mouseDown = true;
Paul Greysonc090d142013-04-09 16:59:03 -070050 d3.select('#topologyArea').classed('linking', true);
Paul Greysone15c4392013-04-09 15:05:31 -070051
52 d3.select('svg')
53 .append('svg:path')
54 .attr('id', 'linkVector')
55 .attr('d', function () {
56 var s = d3.select(document.getElementById(data.dpid));
57
58 var pt = document.querySelector('svg').createSVGPoint();
59 pt.x = s.attr('x');
60 pt.y = s.attr('y');
61 pt = pt.matrixTransform(s[0][0].getCTM());
62
63 return line([pt, pt]);
64 });
65
66
67 if (data.className === 'core') {
68 d3.selectAll('.edge').classed('nodrop', true);
69 }
70 if (data.className === 'edge') {
71 d3.selectAll('.core').classed('nodrop', true);
72 d3.selectAll('.aggregation').classed('nodrop', true);
73 }
74 if (data.className === 'aggregation') {
75 d3.selectAll('.edge').classed('nodrop', true);
76 d3.selectAll('.aggregation').classed('nodrop', true);
77 }
78}
79
80function mouseUpSwitch(data) {
81 if (data.mouseDown) {
82 data.mouseDown = false;
Paul Greysonc090d142013-04-09 16:59:03 -070083 d3.select('#topologyArea').classed('linking', false);
Paul Greysone15c4392013-04-09 15:05:31 -070084 d3.event.stopPropagation();
85 d3.selectAll('.nodrop').classed('nodrop', false);
86 }
87}
88
89function doubleClickSwitch(data) {
90 var circle = d3.select(document.getElementById(data.dpid)).select('circle');
91 if (data.state == 'ACTIVE') {
92 var prompt = 'Deactivate ' + data.dpid + '?';
93 if (confirm(prompt)) {
94 switchDown(data);
95 setPending(circle);
96 }
97 } else {
98 var prompt = 'Activate ' + data.dpid + '?';
99 if (confirm(prompt)) {
100 switchUp(data);
101 setPending(circle);
102 }
103 }
104}
105
106d3.select(document.body).on('mouseup', function () {
107 function clearHighlight() {
Paul Greysonc090d142013-04-09 16:59:03 -0700108 topology.selectAll('circle').each(function (data) {
Paul Greysone15c4392013-04-09 15:05:31 -0700109 data.mouseDown = false;
Paul Greysonc090d142013-04-09 16:59:03 -0700110 d3.select('#topologyArea').classed('linking', false);
Paul Greysone15c4392013-04-09 15:05:31 -0700111 mouseOutSwitch(data);
112 });
113 d3.select('#linkVector').remove();
114 };
115
116 d3.selectAll('.nodrop').classed('nodrop', false);
117
118 function removeLink(link) {
119 var path1 = document.getElementById(link['src-switch'] + '=>' + link['dst-switch']);
120 var path2 = document.getElementById(link['dst-switch'] + '=>' + link['src-switch']);
121
122 if (path1) {
123 setPending(d3.select(path1));
124 }
125 if (path2) {
126 setPending(d3.select(path2));
127 }
128
129 linkDown(link);
130 }
131
132
Paul Greysonc090d142013-04-09 16:59:03 -0700133 var highlighted = topology.selectAll('.highlight')[0];
Paul Greysone15c4392013-04-09 15:05:31 -0700134 if (highlighted.length == 2) {
135 var s1Data = highlighted[0].__data__;
136 var s2Data = highlighted[1].__data__;
137
138 var srcData, dstData;
139 if (s1Data.target) {
140 dstData = s1Data;
141 srcData = s2Data;
142 } else {
143 dstData = s2Data;
144 srcData = s1Data;
145 }
146
147 if (s1Data.className == 'edge' && s2Data.className == 'edge') {
148 var prompt = 'Create flow from ' + srcData.dpid + ' to ' + dstData.dpid + '?';
149 if (confirm(prompt)) {
150 addFlow(srcData, dstData);
151
152 var flow = {
153 dataPath: {
154 srcPort: {
155 dpid: {
156 value: srcData.dpid
157 }
158 },
159 dstPort: {
160 dpid: {
161 value: dstData.dpid
162 }
163 }
164 },
165 srcDpid: srcData.dpid,
166 dstDpid: dstData.dpid,
167 createPending: true
168 };
169
170 selectFlow(flow);
171
172 setTimeout(function () {
173 deselectFlowIfCreatePending(flow);
174 }, pendingTimeout);
175 }
176 } else {
177 var map = linkMap[srcData.dpid];
178 if (map && map[dstData.dpid]) {
179 var prompt = 'Remove link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
180 if (confirm(prompt)) {
181 removeLink(map[dstData.dpid]);
182 }
183 } else {
184 map = linkMap[dstData.dpid];
185 if (map && map[srcData.dpid]) {
186 var prompt = 'Remove link between ' + dstData.dpid + ' and ' + srcData.dpid + '?';
187 if (confirm(prompt)) {
188 removeLink(map[srcData.dpid]);
189 }
190 } else {
191 var prompt = 'Create link between ' + srcData.dpid + ' and ' + dstData.dpid + '?';
192 if (confirm(prompt)) {
193 var link1 = {
194 'src-switch': srcData.dpid,
195 'src-port': 1,
196 'dst-switch': dstData.dpid,
197 'dst-port': 1,
198 pending: true
199 };
200 pendingLinks[makeLinkKey(link1)] = link1;
201 var link2 = {
202 'src-switch': dstData.dpid,
203 'src-port': 1,
204 'dst-switch': srcData.dpid,
205 'dst-port': 1,
206 pending: true
207 };
208 pendingLinks[makeLinkKey(link2)] = link2;
209 updateTopology();
210
211 linkUp(link1);
212
213 // remove the pending links after 10s
214 setTimeout(function () {
215 delete pendingLinks[makeLinkKey(link1)];
216 delete pendingLinks[makeLinkKey(link2)];
217
218 updateTopology();
219 }, pendingTimeout);
220 }
221 }
222 }
223 }
224
225 clearHighlight();
226 } else {
227 clearHighlight();
228 }
Paul Greyson30636252013-04-09 15:22:04 -0700229});
230
231d3.select(document.body).on('mousemove', function () {
Paul Greysonc090d142013-04-09 16:59:03 -0700232 if (!d3.select('#topologyArea').classed('linking')) {
Paul Greyson30636252013-04-09 15:22:04 -0700233 return;
234 }
235 var linkVector = document.getElementById('linkVector');
236 if (!linkVector) {
237 return;
238 }
239 linkVector = d3.select(linkVector);
240
Paul Greysonc090d142013-04-09 16:59:03 -0700241 var highlighted = topology.selectAll('.highlight')[0];
Paul Greyson30636252013-04-09 15:22:04 -0700242 var s1 = null, s2 = null;
243 if (highlighted.length > 1) {
244 var s1 = d3.select(highlighted[0]);
245 var s2 = d3.select(highlighted[1]);
246
247 } else if (highlighted.length > 0) {
248 var s1 = d3.select(highlighted[0]);
249 }
250 var src = s1;
251 if (s2 && !s2.data()[0].target) {
252 src = s2;
253 }
254 if (src) {
255 linkVector.attr('d', function () {
256 var srcPt = document.querySelector('svg').createSVGPoint();
257 srcPt.x = src.attr('x');
258 srcPt.y = src.attr('y');
259 srcPt = srcPt.matrixTransform(src[0][0].getCTM());
260
261 var svg = document.getElementById('topology');
262 var mouse = d3.mouse(viewbox);
263 var dstPt = document.querySelector('svg').createSVGPoint();
264 dstPt.x = mouse[0];
265 dstPt.y = mouse[1];
266 dstPt = dstPt.matrixTransform(viewbox.getCTM());
267
268 return line([srcPt, dstPt]);
269 });
270 }
271});