Paul Greyson | 7a30082 | 2013-04-09 12:57:49 -0700 | [diff] [blame] | 1 | /*************************************************************************************************** |
| 2 | extract url parameters into a map |
| 3 | ***************************************************************************************************/ |
Paul Greyson | bcd3c77 | 2013-03-21 13:16:44 -0700 | [diff] [blame] | 4 | function parseURLParameters() { |
| 5 | var parameters = {}; |
| 6 | |
| 7 | var search = location.href.split('?')[1]; |
| 8 | if (search) { |
| 9 | search.split('&').forEach(function (param) { |
| 10 | var key = param.split('=')[0]; |
| 11 | var value = param.split('=')[1]; |
| 12 | parameters[key] = decodeURIComponent(value); |
| 13 | }); |
| 14 | } |
| 15 | |
| 16 | return parameters; |
Paul Greyson | 5cc35f0 | 2013-03-28 10:07:36 -0700 | [diff] [blame] | 17 | } |
| 18 | |
Paul Greyson | 7a30082 | 2013-04-09 12:57:49 -0700 | [diff] [blame] | 19 | /*************************************************************************************************** |
| 20 | convenience function for moving an SVG element to the front so that it draws on top |
| 21 | ***************************************************************************************************/ |
| 22 | d3.selection.prototype.moveToFront = function() { |
| 23 | return this.each(function(){ |
| 24 | this.parentNode.appendChild(this); |
| 25 | }); |
| 26 | }; |
| 27 | |
| 28 | /*************************************************************************************************** |
| 29 | standard function for generating the 'd' attribute for a path from an array of points |
| 30 | ***************************************************************************************************/ |
| 31 | var line = d3.svg.line() |
| 32 | .x(function(d) { |
| 33 | return d.x; |
| 34 | }) |
| 35 | .y(function(d) { |
| 36 | return d.y; |
| 37 | }); |
| 38 | |
| 39 | |
| 40 | /*************************************************************************************************** |
| 41 | starts the "pending" animation |
| 42 | ***************************************************************************************************/ |
| 43 | function setPending(selection) { |
| 44 | selection.classed('pending', false); |
| 45 | setTimeout(function () { |
| 46 | selection.classed('pending', true); |
| 47 | }, 0); |
| 48 | } |
| 49 | |
| 50 | /*************************************************************************************************** |
| 51 | convert angle in degrees to radians |
| 52 | ***************************************************************************************************/ |
| 53 | function toRadians (degrees) { |
| 54 | return degrees * (Math.PI / 180); |
| 55 | } |
| 56 | |
| 57 | /*************************************************************************************************** |
| 58 | used to generate DOM element id for this link |
| 59 | ***************************************************************************************************/ |
| 60 | function makeLinkKey(link) { |
| 61 | return link['src-switch'] + '=>' + link['dst-switch']; |
| 62 | } |
| 63 | |
| 64 | /*************************************************************************************************** |
| 65 | used to generate DOM element id for this flow in the topology view |
| 66 | ***************************************************************************************************/ |
| 67 | function makeFlowKey(flow) { |
| 68 | return flow.srcDpid + '=>' + flow.dstDpid; |
| 69 | } |
| 70 | |
| 71 | /*************************************************************************************************** |
| 72 | used to generate DOM element id for this flow in the selected flows table |
| 73 | ***************************************************************************************************/ |
| 74 | function makeSelectedFlowKey(flow) { |
| 75 | return 'S' + makeFlowKey(flow); |
| 76 | } |
| 77 | |
| 78 | /*************************************************************************************************** |
| 79 | update the app header using the current model |
| 80 | ***************************************************************************************************/ |
| 81 | function updateHeader() { |
Jonathan Hart | e865f9b | 2013-04-13 12:08:42 -0700 | [diff] [blame] | 82 | d3.select('#lastUpdate').text(new Date().toLocaleString()); |
Paul Greyson | bbd708b | 2013-04-09 22:37:31 -0700 | [diff] [blame] | 83 | |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 84 | var activeSwitchCount = 0; |
Paul Greyson | bbd708b | 2013-04-09 22:37:31 -0700 | [diff] [blame] | 85 | model.edgeSwitches.forEach(function (s) { |
| 86 | if (s.state === 'ACTIVE') { |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 87 | activeSwitchCount += 1; |
Paul Greyson | bbd708b | 2013-04-09 22:37:31 -0700 | [diff] [blame] | 88 | } |
| 89 | }); |
| 90 | model.aggregationSwitches.forEach(function (s) { |
| 91 | if (s.state === 'ACTIVE') { |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 92 | activeSwitchCount += 1; |
Paul Greyson | bbd708b | 2013-04-09 22:37:31 -0700 | [diff] [blame] | 93 | } |
| 94 | }); |
| 95 | model.coreSwitches.forEach(function (s) { |
| 96 | if (s.state === 'ACTIVE') { |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 97 | activeSwitchCount += 1; |
Paul Greyson | bbd708b | 2013-04-09 22:37:31 -0700 | [diff] [blame] | 98 | } |
| 99 | }); |
| 100 | |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 101 | d3.select('#activeSwitches').text(activeSwitchCount); |
| 102 | |
| 103 | |
| 104 | |
Paul Greyson | 7a30082 | 2013-04-09 12:57:49 -0700 | [diff] [blame] | 105 | d3.select('#activeFlows').text(model.flows.length); |
| 106 | } |
| 107 | |
Paul Greyson | e15c439 | 2013-04-09 15:05:31 -0700 | [diff] [blame] | 108 | /*************************************************************************************************** |
| 109 | update the global linkmap |
| 110 | ***************************************************************************************************/ |
| 111 | function updateLinkMap(links) { |
| 112 | linkMap = {}; |
| 113 | links.forEach(function (link) { |
| 114 | var srcDPID = link['src-switch']; |
| 115 | var dstDPID = link['dst-switch']; |
| 116 | |
| 117 | var srcMap = linkMap[srcDPID] || {}; |
| 118 | |
| 119 | srcMap[dstDPID] = link; |
| 120 | |
| 121 | linkMap[srcDPID] = srcMap; |
| 122 | }); |
| 123 | } |
| 124 | |
| 125 | /*************************************************************************************************** |
| 126 | // removes links from the pending list that are now in the model |
| 127 | ***************************************************************************************************/ |
| 128 | function reconcilePendingLinks(model) { |
| 129 | links = []; |
| 130 | model.links.forEach(function (link) { |
| 131 | links.push(link); |
| 132 | delete pendingLinks[makeLinkKey(link)] |
| 133 | }) |
| 134 | var linkId; |
| 135 | for (linkId in pendingLinks) { |
| 136 | links.push(pendingLinks[linkId]); |
| 137 | } |
| 138 | } |
| 139 | |
Paul Greyson | 981e8c2 | 2013-04-09 17:43:59 -0700 | [diff] [blame] | 140 | /*************************************************************************************************** |
| 141 | used by both ring and map models |
| 142 | ***************************************************************************************************/ |
| 143 | function createRootSVG() { |
| 144 | var svg = d3.select('#svg-container').append('svg:svg'); |
| 145 | |
| 146 | svg.append("svg:defs").append("svg:marker") |
| 147 | .attr("id", "arrow") |
| 148 | .attr("viewBox", "0 -5 10 10") |
| 149 | .attr("refX", -1) |
| 150 | .attr("markerWidth", 5) |
| 151 | .attr("markerHeight", 5) |
| 152 | .attr("orient", "auto") |
| 153 | .append("svg:path") |
| 154 | .attr("d", "M0,-3L10,0L0,3"); |
| 155 | |
| 156 | return svg; |
| 157 | } |
| 158 | |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 159 | /*************************************************************************************************** |
| 160 | counts the number of flows which pass through each core<->core link |
| 161 | ***************************************************************************************************/ |
| 162 | function countCoreLinkFlows() { |
| 163 | var allCounts = {}; |
| 164 | model.flows.forEach(function (f) { |
| 165 | if (f.dataPath && f.dataPath.flowEntries && f.dataPath.flowEntries.length > 1) { |
| 166 | var flowEntries = f.dataPath.flowEntries; |
| 167 | var i; |
| 168 | |
| 169 | for (i = 0; i < flowEntries.length - 1; i += 1) { |
| 170 | var linkKey = flowEntries[i].dpid.value + '=>' + flowEntries[i+1].dpid.value; |
| 171 | if (!allCounts[linkKey]) { |
| 172 | allCounts[linkKey] = 1; |
| 173 | } else { |
| 174 | allCounts[linkKey] += 1; |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | }); |
| 179 | |
| 180 | var coreCounts = {}; |
| 181 | var i, j; |
| 182 | for (i = 0; i < model.coreSwitches.length - 1; i += 1) { |
| 183 | for (j = i + 1; j < model.coreSwitches.length; j += 1) { |
| 184 | var si = model.coreSwitches[i]; |
| 185 | var sj = model.coreSwitches[j]; |
| 186 | var key1 = si.dpid + '=>' + sj.dpid; |
| 187 | var key2 = sj.dpid + '=>' + si.dpid; |
| 188 | var linkCount = 0; |
| 189 | if (allCounts[key1]) { |
| 190 | linkCount += allCounts[key1]; |
| 191 | } |
| 192 | if (allCounts[key2]) { |
| 193 | linkCount += allCounts[key2]; |
| 194 | } |
| 195 | |
| 196 | coreCounts[key1] = linkCount; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | return d3.entries(coreCounts); |
| 201 | } |
| 202 | |
| 203 | |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 204 | /*************************************************************************************************** |
| 205 | |
| 206 | ***************************************************************************************************/ |
Paul Greyson | 0ad7520 | 2013-04-11 12:29:32 -0700 | [diff] [blame] | 207 | function doConfirm(prompt, cb, options) { |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 208 | var confirm = d3.select('#confirm'); |
| 209 | confirm.select('#confirm-prompt').text(prompt); |
| 210 | |
Paul Greyson | 0ad7520 | 2013-04-11 12:29:32 -0700 | [diff] [blame] | 211 | var select = d3.select(document.getElementById('confirm-select')); |
| 212 | if (options) { |
| 213 | select.style('display', 'block'); |
| 214 | select.text(''); |
| 215 | select.selectAll('option'). |
| 216 | data(options) |
| 217 | .enter() |
| 218 | .append('option') |
| 219 | .attr('value', function (d) {return d}) |
| 220 | .text(function (d) {return d}); |
| 221 | } else { |
| 222 | select.style('display', 'none'); |
| 223 | } |
| 224 | |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 225 | function show() { |
| 226 | confirm.style('display', '-webkit-box'); |
| 227 | confirm.style('opacity', 0); |
| 228 | setTimeout(function () { |
| 229 | confirm.style('opacity', 1); |
| 230 | }, 0); |
| 231 | } |
| 232 | |
| 233 | function dismiss() { |
| 234 | confirm.style('opacity', 0); |
| 235 | confirm.on('webkitTransitionEnd', function () { |
| 236 | confirm.style('display', 'none'); |
| 237 | confirm.on('webkitTransitionEnd', null); |
| 238 | }); |
| 239 | } |
| 240 | |
| 241 | confirm.select('#confirm-ok').on('click', function () { |
| 242 | d3.select(this).on('click', null); |
| 243 | dismiss(); |
Paul Greyson | 0ad7520 | 2013-04-11 12:29:32 -0700 | [diff] [blame] | 244 | if (options) { |
| 245 | cb(select[0][0].value); |
| 246 | } else { |
| 247 | cb(true); |
| 248 | } |
Paul Greyson | 28cf92b | 2013-04-10 13:15:06 -0700 | [diff] [blame] | 249 | }); |
| 250 | |
| 251 | confirm.select('#confirm-cancel').on('click', function () { |
| 252 | d3.select(this).on('click', null); |
| 253 | dismiss(); |
| 254 | cb(false); |
| 255 | }); |
| 256 | |
| 257 | show(); |
| 258 | } |
| 259 | |
| 260 | |
Paul Greyson | 4a73a8b | 2013-04-10 11:47:25 -0700 | [diff] [blame] | 261 | |
| 262 | |
Paul Greyson | 7a30082 | 2013-04-09 12:57:49 -0700 | [diff] [blame] | 263 | |