blob: 35ca77d6c682e5b9262b7292447c40b9f7263e5f [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');
Paul Greysonbbd708b2013-04-09 22:37:31 -0700114 flowLayer = topology.append('g');
115
Paul Greyson4e348b92013-04-09 21:02:06 -0700116
117 cb();
118 });
Paul Greyson981e8c22013-04-09 17:43:59 -0700119}
Paul Greysonc090d142013-04-09 16:59:03 -0700120
Paul Greyson45aceb22013-04-09 22:17:03 -0700121function drawLinkLines() {
Paul Greyson4e348b92013-04-09 21:02:06 -0700122
123 // key on link dpids since these will come/go during demo
124 var linkLines = linksLayer.selectAll('.link').data(links, function (d) {
125 return d['src-switch']+'->'+d['dst-switch'];
126 });
127
128 // add new links
129 linkLines.enter().append("svg:path").attr("class", "link");
130
131 linkLines.attr('id', function (d) {
132 return makeLinkKey(d);
133 }).attr("d", function (d) {
134 var src = d3.select(document.getElementById(d['src-switch']));
135 var dst = d3.select(document.getElementById(d['dst-switch']));
136
137 if (src.empty() || dst.empty()) {
138 return "M0,0";
139 }
140
141 var srcPt = document.querySelector('svg').createSVGPoint();
142 srcPt.x = src.attr('x');
143 srcPt.y = src.attr('y');
144
145 var dstPt = document.querySelector('svg').createSVGPoint();
146 dstPt.x = dst.attr('x');
147 dstPt.y = dst.attr('y');
148
149 var midPt = document.querySelector('svg').createSVGPoint();
150 midPt.x = (srcPt.x + dstPt.x)/2;
151 midPt.y = (srcPt.y + dstPt.y)/2;
152
153 return line([srcPt, midPt, dstPt]);
154 })
155 .attr("marker-mid", function(d) { return "url(#arrow)"; })
156 .classed('pending', function (d) {
157 return d.pending;
158 });
159
160 // remove old links
161 linkLines.exit().remove();
162}
163
164var fanOutAngles = {
165 aggregation: 90,
166 edge: 7
167}
168
169function makeSwitchesModel(switches, className) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700170 var switchesModel = [];
171 switches.forEach(function (s) {
Paul Greyson4e348b92013-04-09 21:02:06 -0700172 var geo = model.configuration.geo[s.dpid];
173
174 var pos, label;
175 if (geo) {
176 pos = projection([geo.lng, geo.lat]);
177 label = geo.label;
178 } else {
179 var upstream = getUpstream(s.dpid, className);
180 if (upstream) {
181 var upstreamGeo = fanouts[upstream];
182 pos = projection([upstreamGeo.lng, upstreamGeo.lat]);
183
184 var fanOutAngle = upstreamGeo.fanOutAngle;
185 fanOutAngle -= (upstreamGeo.count - 1) * fanOutAngles[className]/2;
186
187 var angle = toRadians(fanOutAngle);
188 var xOff = Math.sin(angle) * widths[className] * 20;
189 var yOff = Math.cos(angle) * widths[className] * 20;
190
191 pos = [pos[0] + xOff, pos[1] + yOff];
192
193 var fakeGeo = projection.invert(pos);
194
195 var fanout = fanouts[s.dpid];
196 fanout.fanOutAngle = fanOutAngle;
197 fanout.lng = fakeGeo[0];
198 fanout.lat = fakeGeo[1];
199
200 upstreamGeo.fanOutAngle += fanOutAngles[className];
201
202 } else {
203 pos = projection([-98, 39]);
204 }
205 }
206
Paul Greyson981e8c22013-04-09 17:43:59 -0700207 switchesModel.push({
208 dpid: s.dpid,
209 state: s.state,
Paul Greyson4e348b92013-04-09 21:02:06 -0700210 className: className,
Paul Greyson981e8c22013-04-09 17:43:59 -0700211 controller: s.controller,
Paul Greyson4e348b92013-04-09 21:02:06 -0700212 label: label,
213 x: pos[0],
214 y: pos[1]
Paul Greyson981e8c22013-04-09 17:43:59 -0700215 });
216 });
217
218 return switchesModel;
Paul Greysonc090d142013-04-09 16:59:03 -0700219}
220
Paul Greyson4e348b92013-04-09 21:02:06 -0700221function switchEnter(d) {
222 var g = d3.select(this);
223 var width = widths[d.className];
Paul Greysonc090d142013-04-09 16:59:03 -0700224
Paul Greyson4e348b92013-04-09 21:02:06 -0700225 g.append('svg:circle').attr('r', width)
226 .classed(d.className, true)
227 .attr('cx', d.x)
228 .attr('cy', d.y);
Paul Greyson981e8c22013-04-09 17:43:59 -0700229
Paul Greyson4e348b92013-04-09 21:02:06 -0700230 if (d.label) {
231 g.append('svg:text')
Paul Greyson45aceb22013-04-09 22:17:03 -0700232 .classed('label', true)
Paul Greyson4e348b92013-04-09 21:02:06 -0700233 .text(d.label)
Paul Greyson45aceb22013-04-09 22:17:03 -0700234 .attr("text-anchor", "end")
235 .attr('x', d.x - width)
236 .attr('y', d.y - width);
Paul Greyson981e8c22013-04-09 17:43:59 -0700237 }
Paul Greyson4e348b92013-04-09 21:02:06 -0700238}
Paul Greyson981e8c22013-04-09 17:43:59 -0700239
Paul Greyson45aceb22013-04-09 22:17:03 -0700240function labelsEnter(switches) {
241 return labelsLayer.selectAll('g').data(switches, function (d) {
242 return d.dpid;
243 }).enter().append('svg:g')
244 .classed('nolabel', true)
245 .attr("id", function (data) {
246 return data.dpid + '-label';
247 })
248 .append("svg:text")
249 .text(function (data) {return data.dpid;})
250 .attr('x', function (d) {
251 return d.x;
252 })
253 .attr('y', function (d) {
254 return d.y;
255 })
256 .attr("text-anchor", function (d) {
257 return d.x > 500 ? "end" : "start";
258 })
259
260}
261
Paul Greyson4e348b92013-04-09 21:02:06 -0700262function switchesEnter(switches) {
263 return switchLayer.selectAll('g').data(switches, function (d) {
264 return d.dpid;
265 })
Paul Greyson981e8c22013-04-09 17:43:59 -0700266 .enter()
Paul Greyson4e348b92013-04-09 21:02:06 -0700267 .append('svg:g')
268 .attr("id", function (d) {
269 return d.dpid;
270 })
271 .attr('x', function (d) {
272 return d.x;
273 })
274 .attr('y', function (d) {
275 return d.y;
276 })
277 .each(switchEnter);
278}
279
Paul Greyson981e8c22013-04-09 17:43:59 -0700280
Paul Greyson4e348b92013-04-09 21:02:06 -0700281function switchesUpdate(switches) {
282 switches.each(function (d) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700283 // if there's a pending state changed and then the state changes, clear the pending class
284 var circle = d3.select(this);
Paul Greyson4e348b92013-04-09 21:02:06 -0700285 if (d.state === 'ACTIVE' && circle.classed('inactive') ||
286 d.state === 'INACTIVE' && circle.classed('active')) {
Paul Greyson981e8c22013-04-09 17:43:59 -0700287 circle.classed('pending', false);
288 }
289 })
Paul Greyson4e348b92013-04-09 21:02:06 -0700290 .attr('class', function (d) {
291 if (d.state === 'ACTIVE' && d.controller) {
Paul Greysonb9e879e2013-04-09 21:16:16 -0700292 return 'active ' + controllerColorMap[d.controller];
Paul Greyson981e8c22013-04-09 17:43:59 -0700293 } else {
Paul Greysonb9e879e2013-04-09 21:16:16 -0700294 return 'inactive ' + 'colorInactive';
Paul Greyson981e8c22013-04-09 17:43:59 -0700295 }
296 });
Paul Greyson4e348b92013-04-09 21:02:06 -0700297}
Paul Greyson981e8c22013-04-09 17:43:59 -0700298
Paul Greyson4e348b92013-04-09 21:02:06 -0700299drawTopology = function () {
300
301 makeSwitchMap();
302 makeAssociations();
303 makeFanouts();
304
305 var coreSwitches = makeSwitchesModel(model.coreSwitches, 'core');
306 var aggregationSwitches = makeSwitchesModel(model.aggregationSwitches, 'aggregation');
307 var edgeSwitches = makeSwitchesModel(model.edgeSwitches, 'edge');
308
309 var switches = coreSwitches.concat(aggregationSwitches).concat(edgeSwitches);
310
311 switchesUpdate(switchesEnter(switches));
312
Paul Greyson45aceb22013-04-09 22:17:03 -0700313 drawLinkLines();
Paul Greyson4e348b92013-04-09 21:02:06 -0700314
Paul Greyson45aceb22013-04-09 22:17:03 -0700315 labelsEnter(switches);
Paul Greysonc090d142013-04-09 16:59:03 -0700316}
317
318})();