Paul Greyson | 15e5da2 | 2013-04-10 00:16:27 -0700 | [diff] [blame] | 1 | function 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 Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 10 | function 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 Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 21 | var highlighted = topology.selectAll('.highlight')[0]; |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 22 | 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 | |
| 44 | function 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 | |
| 56 | function mouseDownSwitch(data) { |
| 57 | mouseOverSwitch(data); |
| 58 | data.mouseDown = true; |
Paul Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 59 | d3.select('#topologyArea').classed('linking', true); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 60 | |
| 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 | |
| 89 | function mouseUpSwitch(data) { |
| 90 | if (data.mouseDown) { |
| 91 | data.mouseDown = false; |
Paul Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 92 | d3.select('#topologyArea').classed('linking', false); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 93 | d3.event.stopPropagation(); |
| 94 | d3.selectAll('.nodrop').classed('nodrop', false); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | function doubleClickSwitch(data) { |
Paul Greyson | 15e5da2 | 2013-04-10 00:16:27 -0700 | [diff] [blame] | 99 | clearHighlight(); |
| 100 | |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 101 | var circle = d3.select(document.getElementById(data.dpid)).select('circle'); |
| 102 | if (data.state == 'ACTIVE') { |
| 103 | var prompt = 'Deactivate ' + data.dpid + '?'; |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 104 | doConfirm(prompt, function(result) { |
| 105 | if (result) { |
| 106 | switchDown(data); |
| 107 | setPending(circle); |
| 108 | } |
| 109 | }); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 110 | } else { |
| 111 | var prompt = 'Activate ' + data.dpid + '?'; |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 112 | doConfirm(prompt, function (result) { |
| 113 | if (result) { |
| 114 | switchUp(data); |
| 115 | setPending(circle); |
| 116 | } |
| 117 | }); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 118 | } |
| 119 | } |
| 120 | |
Paul Greyson | 15e5da2 | 2013-04-10 00:16:27 -0700 | [diff] [blame] | 121 | d3.select(window).on('mouseup', function () { |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 122 | 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 Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 139 | var highlighted = topology.selectAll('.highlight')[0]; |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 140 | 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 Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 155 | doConfirm(prompt, function (result) { |
| 156 | if (result) { |
| 157 | addFlow(srcData, dstData); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 158 | |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 159 | var flow = { |
| 160 | dataPath: { |
| 161 | srcPort: { |
| 162 | dpid: { |
| 163 | value: srcData.dpid |
| 164 | } |
| 165 | }, |
| 166 | dstPort: { |
| 167 | dpid: { |
| 168 | value: dstData.dpid |
| 169 | } |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 170 | } |
| 171 | }, |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 172 | srcDpid: srcData.dpid, |
| 173 | dstDpid: dstData.dpid, |
| 174 | createPending: true |
| 175 | }; |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 176 | |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 177 | selectFlow(flow); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 178 | |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 179 | setTimeout(function () { |
| 180 | deselectFlowIfCreatePending(flow); |
| 181 | }, pendingTimeout); |
| 182 | } |
| 183 | }); |
| 184 | |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 185 | } 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 Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 189 | doConfirm(prompt, function (result) { |
| 190 | if (result) { |
| 191 | removeLink(map[dstData.dpid]); |
| 192 | } |
| 193 | }); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 194 | } else { |
| 195 | map = linkMap[dstData.dpid]; |
| 196 | if (map && map[srcData.dpid]) { |
| 197 | var prompt = 'Remove link between ' + dstData.dpid + ' and ' + srcData.dpid + '?'; |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 198 | doConfirm(prompt, function (result) { |
| 199 | if (result) { |
| 200 | removeLink(map[srcData.dpid]); |
| 201 | } |
| 202 | }); |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 203 | } else { |
| 204 | var prompt = 'Create link between ' + srcData.dpid + ' and ' + dstData.dpid + '?'; |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 205 | 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 Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 223 | updateTopology(); |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 224 | |
| 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 Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 236 | } |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | clearHighlight(); |
| 241 | } else { |
| 242 | clearHighlight(); |
| 243 | } |
Paul Greyson | 3063625 | 2013-04-09 15:22:04 -0700 | [diff] [blame] | 244 | }); |
| 245 | |
| 246 | d3.select(document.body).on('mousemove', function () { |
Paul Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 247 | if (!d3.select('#topologyArea').classed('linking')) { |
Paul Greyson | 3063625 | 2013-04-09 15:22:04 -0700 | [diff] [blame] | 248 | return; |
| 249 | } |
| 250 | var linkVector = document.getElementById('linkVector'); |
| 251 | if (!linkVector) { |
| 252 | return; |
| 253 | } |
| 254 | linkVector = d3.select(linkVector); |
| 255 | |
Paul Greyson | c090d14 | 2013-04-09 16:59:03 -0700 | [diff] [blame] | 256 | var highlighted = topology.selectAll('.highlight')[0]; |
Paul Greyson | 3063625 | 2013-04-09 15:22:04 -0700 | [diff] [blame] | 257 | 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 | }); |