blob: d40c9cb4d64154a294680f67385d71542189fc54 [file] [log] [blame]
Paul Greysonc090d142013-04-09 16:59:03 -07001
2
3
4(function () {
5
Paul Greyson981e8c22013-04-09 17:43:59 -07006var projection = d3.geo.mercator()
Paul Greyson4e348b92013-04-09 21:02:06 -07007 .center([82, 46])
8 .scale(8000)
Paul Greyson981e8c22013-04-09 17:43:59 -07009 .rotate([-180,0]);
Paul Greysonc090d142013-04-09 16:59:03 -070010
Paul Greyson981e8c22013-04-09 17:43:59 -070011function createMap(svg, cb) {
Paul Greysonc090d142013-04-09 16:59:03 -070012 topology = svg.append('svg:svg').attr('id', 'viewBox').attr('viewBox', '0 0 1000 1000').
13 attr('id', 'viewbox');
14
15 var map = topology.append("g").attr('id', 'map');
16
Paul Greysonc090d142013-04-09 16:59:03 -070017 var path = d3.geo.path().projection(projection);
18
19 d3.json('data/world.json', function(error, topology) {
20 map.selectAll('path')
21 .data(topojson.object(topology, topology.objects.world).geometries)
22 .enter()
23 .append('path')
24 .attr('d', path)
25
26 cb();
27 });
Paul Greyson981e8c22013-04-09 17:43:59 -070028}
Paul Greysonc090d142013-04-09 16:59:03 -070029
Paul Greyson4e348b92013-04-09 21:02:06 -070030/***************************************************************************************************
Paul Greysonc090d142013-04-09 16:59:03 -070031
Paul Greyson4e348b92013-04-09 21:02:06 -070032***************************************************************************************************/
33var switchMap;
34function makeSwitchMap() {
35 switchMap = {};
36 model.coreSwitches.forEach(function (s) {
37 switchMap[s.dpid] = s;
38 });
39 model.aggregationSwitches.forEach(function (s) {
40 switchMap[s.dpid] = s;
41 });
42 model.edgeSwitches.forEach(function (s) {
43 switchMap[s.dpid] = s;
44 });
45}
46
47/***************************************************************************************************
48create a map from edge->aggregation and aggreation->core switches
49***************************************************************************************************/
50var switchAssociations;
51function makeAssociations() {
52 switchAssociations = {};
53
54 var key;
55 for (key in model.configuration.association) {
56 var aggregationSwitches = model.configuration.association[key];
57 aggregationSwitches.forEach(function (s) {
58 switchAssociations[s] = key;
59 });
60 }
61}
62
63/***************************************************************************************************
64get the upstream switch. this only makes sense for aggregation and edge switches
65***************************************************************************************************/
66function getUpstream(dpid, className) {
67 if (className === 'aggregation') {
68 return switchAssociations[dpid];
69 } else if (className === 'edge') {
70 var aggregationDpid = dpid.split(':');
71 aggregationDpid[7] = '01'; // the last component of the agg switch is always '01'
72 return aggregationDpid.join(':');
73 }
74}
75
76
77
78/*****************a**********************************************************************************
79create a map to hold the fanout information for the switches
80***************************************************************************************************/
81var fanouts;
82function makeFanouts() {
83 fanouts = {};
84 model.coreSwitches.forEach(function (s) {
85 fanouts[s.dpid] = model.configuration.geo[s.dpid];
86 fanouts[s.dpid].count = 0;
87 });
88
89 model.aggregationSwitches.forEach(function (s) {
90 fanouts[s.dpid] = {count: 0};
91 var upstreamFanout = fanouts[getUpstream(s.dpid, 'aggregation')];
92 upstreamFanout.count += 1;
93 });
94
95 model.edgeSwitches.forEach(function (s) {
96 fanouts[s.dpid] = {};
97 var upstreamFanout = fanouts[getUpstream(s.dpid, 'edge')];
98 upstreamFanout.count += 1;
99 });
100}
101
102
103var projection;
104var switchLayer;
105var labelsLayer;
106var linksLayer;
Paul Greyson981e8c22013-04-09 17:43:59 -0700107createTopologyView = function (cb) {
108 var svg = createRootSVG();
Paul Greysonc090d142013-04-09 16:59:03 -0700109
Paul Greyson4e348b92013-04-09 21:02:06 -0700110 createMap(svg, function () {
111 switchLayer = topology.append('g');
112 labelsLayer = topology.append('g');
113 linksLayer = topology.append('g');
114
115 cb();
116 });
Paul Greyson981e8c22013-04-09 17:43:59 -0700117}
Paul Greysonc090d142013-04-09 16:59:03 -0700118
Paul Greyson45aceb22013-04-09 22:17:03 -0700119function drawLinkLines() {
Paul Greyson4e348b92013-04-09 21:02:06 -0700120
121 // key on link dpids since these will come/go during demo
122 var linkLines = linksLayer.selectAll('.link').data(links, function (d) {
123 return d['src-switch']+'->'+d['dst-switch'];
124 });
125
126 // add new links
127 linkLines.enter().append("svg:path").attr("class", "link");
128
129 linkLines.attr('id', function (d) {
130 return makeLinkKey(d);
131 }).attr("d", function (d) {
132 var src = d3.select(document.getElementById(d['src-switch']));
133 var dst = d3.select(document.getElementById(d['dst-switch']));
134
135 if (src.empty() || dst.empty()) {
136 return "M0,0";
137 }
138
139 var srcPt = document.querySelector('svg').createSVGPoint();
140 srcPt.x = src.attr('x');
141 srcPt.y = src.attr('y');
142
143 var dstPt = document.querySelector('svg').createSVGPoint();
144 dstPt.x = dst.attr('x');
145 dstPt.y = dst.attr('y');
146
147 var midPt = document.querySelector('svg').createSVGPoint();
148 midPt.x = (srcPt.x + dstPt.x)/2;
149 midPt.y = (srcPt.y + dstPt.y)/2;
150
151 return line([srcPt, midPt, dstPt]);
152 })
153 .attr("marker-mid", function(d) { return "url(#arrow)"; })
154 .classed('pending', function (d) {
155 return d.pending;
156 });
157
158 // remove old links
159 linkLines.exit().remove();
160}
161
162var fanOutAngles = {
163 aggregation: 90,
164 edge: 7
165}
166
167function makeSwitchesModel(switches, className) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700168 var switchesModel = [];
169 switches.forEach(function (s) {
Paul Greyson4e348b92013-04-09 21:02:06 -0700170 var geo = model.configuration.geo[s.dpid];
171
172 var pos, label;
173 if (geo) {
174 pos = projection([geo.lng, geo.lat]);
175 label = geo.label;
176 } else {
177 var upstream = getUpstream(s.dpid, className);
178 if (upstream) {
179 var upstreamGeo = fanouts[upstream];
180 pos = projection([upstreamGeo.lng, upstreamGeo.lat]);
181
182 var fanOutAngle = upstreamGeo.fanOutAngle;
183 fanOutAngle -= (upstreamGeo.count - 1) * fanOutAngles[className]/2;
184
185 var angle = toRadians(fanOutAngle);
186 var xOff = Math.sin(angle) * widths[className] * 20;
187 var yOff = Math.cos(angle) * widths[className] * 20;
188
189 pos = [pos[0] + xOff, pos[1] + yOff];
190
191 var fakeGeo = projection.invert(pos);
192
193 var fanout = fanouts[s.dpid];
194 fanout.fanOutAngle = fanOutAngle;
195 fanout.lng = fakeGeo[0];
196 fanout.lat = fakeGeo[1];
197
198 upstreamGeo.fanOutAngle += fanOutAngles[className];
199
200 } else {
201 pos = projection([-98, 39]);
202 }
203 }
204
Paul Greyson981e8c22013-04-09 17:43:59 -0700205 switchesModel.push({
206 dpid: s.dpid,
207 state: s.state,
Paul Greyson4e348b92013-04-09 21:02:06 -0700208 className: className,
Paul Greyson981e8c22013-04-09 17:43:59 -0700209 controller: s.controller,
Paul Greyson4e348b92013-04-09 21:02:06 -0700210 label: label,
211 x: pos[0],
212 y: pos[1]
Paul Greyson981e8c22013-04-09 17:43:59 -0700213 });
214 });
215
216 return switchesModel;
Paul Greysonc090d142013-04-09 16:59:03 -0700217}
218
Paul Greyson4e348b92013-04-09 21:02:06 -0700219function switchEnter(d) {
220 var g = d3.select(this);
221 var width = widths[d.className];
Paul Greysonc090d142013-04-09 16:59:03 -0700222
Paul Greyson4e348b92013-04-09 21:02:06 -0700223 g.append('svg:circle').attr('r', width)
224 .classed(d.className, true)
225 .attr('cx', d.x)
226 .attr('cy', d.y);
Paul Greyson981e8c22013-04-09 17:43:59 -0700227
Paul Greyson4e348b92013-04-09 21:02:06 -0700228 if (d.label) {
229 g.append('svg:text')
Paul Greyson45aceb22013-04-09 22:17:03 -0700230 .classed('label', true)
Paul Greyson4e348b92013-04-09 21:02:06 -0700231 .text(d.label)
Paul Greyson45aceb22013-04-09 22:17:03 -0700232 .attr("text-anchor", "end")
233 .attr('x', d.x - width)
234 .attr('y', d.y - width);
Paul Greyson981e8c22013-04-09 17:43:59 -0700235 }
Paul Greyson4e348b92013-04-09 21:02:06 -0700236}
Paul Greyson981e8c22013-04-09 17:43:59 -0700237
Paul Greyson45aceb22013-04-09 22:17:03 -0700238function labelsEnter(switches) {
239 return labelsLayer.selectAll('g').data(switches, function (d) {
240 return d.dpid;
241 }).enter().append('svg:g')
242 .classed('nolabel', true)
243 .attr("id", function (data) {
244 return data.dpid + '-label';
245 })
246 .append("svg:text")
247 .text(function (data) {return data.dpid;})
248 .attr('x', function (d) {
249 return d.x;
250 })
251 .attr('y', function (d) {
252 return d.y;
253 })
254 .attr("text-anchor", function (d) {
255 return d.x > 500 ? "end" : "start";
256 })
257
258}
259
Paul Greyson4e348b92013-04-09 21:02:06 -0700260function switchesEnter(switches) {
261 return switchLayer.selectAll('g').data(switches, function (d) {
262 return d.dpid;
263 })
Paul Greyson981e8c22013-04-09 17:43:59 -0700264 .enter()
Paul Greyson4e348b92013-04-09 21:02:06 -0700265 .append('svg:g')
266 .attr("id", function (d) {
267 return d.dpid;
268 })
269 .attr('x', function (d) {
270 return d.x;
271 })
272 .attr('y', function (d) {
273 return d.y;
274 })
275 .each(switchEnter);
276}
277
Paul Greyson981e8c22013-04-09 17:43:59 -0700278
Paul Greyson4e348b92013-04-09 21:02:06 -0700279function switchesUpdate(switches) {
280 switches.each(function (d) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700281 // if there's a pending state changed and then the state changes, clear the pending class
282 var circle = d3.select(this);
Paul Greyson4e348b92013-04-09 21:02:06 -0700283 if (d.state === 'ACTIVE' && circle.classed('inactive') ||
284 d.state === 'INACTIVE' && circle.classed('active')) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700285 circle.classed('pending', false);
286 }
287 })
Paul Greyson4e348b92013-04-09 21:02:06 -0700288 .attr('class', function (d) {
289 if (d.state === 'ACTIVE' && d.controller) {
Paul Greysonb9e879e2013-04-09 21:16:16 -0700290 return 'active ' + controllerColorMap[d.controller];
Paul Greyson981e8c22013-04-09 17:43:59 -0700291 } else {
Paul Greysonb9e879e2013-04-09 21:16:16 -0700292 return 'inactive ' + 'colorInactive';
Paul Greyson981e8c22013-04-09 17:43:59 -0700293 }
294 });
Paul Greyson4e348b92013-04-09 21:02:06 -0700295}
Paul Greyson981e8c22013-04-09 17:43:59 -0700296
Paul Greyson4e348b92013-04-09 21:02:06 -0700297drawTopology = function () {
298
299 makeSwitchMap();
300 makeAssociations();
301 makeFanouts();
302
303 var coreSwitches = makeSwitchesModel(model.coreSwitches, 'core');
304 var aggregationSwitches = makeSwitchesModel(model.aggregationSwitches, 'aggregation');
305 var edgeSwitches = makeSwitchesModel(model.edgeSwitches, 'edge');
306
307 var switches = coreSwitches.concat(aggregationSwitches).concat(edgeSwitches);
308
309 switchesUpdate(switchesEnter(switches));
310
Paul Greyson45aceb22013-04-09 22:17:03 -0700311 drawLinkLines();
Paul Greyson4e348b92013-04-09 21:02:06 -0700312
Paul Greyson45aceb22013-04-09 22:17:03 -0700313 labelsEnter(switches);
Paul Greysonc090d142013-04-09 16:59:03 -0700314}
315
316})();