blob: d086f6a6a4991d20ed4dd8d88cbc0f9860438170 [file] [log] [blame]
Ubuntu82b8a832013-02-06 22:00:11 +00001function gui(data_source){
Masayoshi Kobayashia05f01f2013-03-15 01:27:22 +00002 var width = 1280,
3 height = 1280;
Ubuntuc016ba12013-02-27 21:53:41 +00004 var radius = 8;
Ubuntu82b8a832013-02-06 22:00:11 +00005 var color = d3.scale.category20();
6
Ubuntuc016ba12013-02-27 21:53:41 +00007 var svg = d3.select("#topology").append("svg:svg")
Ubuntu82b8a832013-02-06 22:00:11 +00008 .attr("width", width)
9 .attr("height", height);
10
11 var force = d3.layout.force()
12 .charge(-500)
13 .linkDistance(100)
14 .size([width, height]);
15
16 var path = svg.selectAll("path");
17 var circle = svg.selectAll("circle");
18 var text = svg.selectAll("g");
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +000019 var node_drag = d3.behavior.drag()
20 .on("dragstart", dragstart)
21 .on("drag", dragmove)
22 .on("dragend", dragend);
Ubuntu82b8a832013-02-06 22:00:11 +000023
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000024 d3.json(data_source, init);
Ubuntu82b8a832013-02-06 22:00:11 +000025
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000026/* For debugging
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000027 $("#more").click( function() {
28 $.ajax({
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000029 url: 'http://gui.onlab.us:8080/topology_more',
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000030 success: function(json) {
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000031 update(json);
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000032 },
33 dataType: "json"
34 });
35 });
36 $("#less").click( function() {
37 $.ajax({
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000038 url: 'http://gui.onlab.us:8080/topology_less',
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000039 success: function(json) {
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000040 update(json);
Masayoshi Kobayashi274c07d2013-02-20 21:38:16 +000041 },
42 dataType: "json"
43 });
44 });
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +000045*/
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +000046
47 function compare_link (a, b){
48 if (a.source > b.source) {return 1;}
49 else if (a.source < b.source) {return -1;}
50 else {
51 if (a.target > b.target) {return 1 ;}
52 if (a.target < b.target) {return -1;}
53 else {return 0;}
54 }
55 }
56
57 function init(json){
58 nodes = force.nodes();
59 links = force.links();
60
61 json.nodes.forEach(function(item) {
62 nodes.push(item);
63 });
64 json.links.forEach(function(item) {
65 links.push(item);
66 });
67
68 links.sort(compare_link);
69 for (var i=1; i<links.length; i++) {
70 if (links[i].source == links[i-1].source &&
71 links[i].target == links[i-1].target) {
72 links[i].linknum = links[i-1].linknum + 1;
73 }
74 else {
75 links[i].linknum = 1;
76 };
77 };
78 init_draw(nodes, links);
79 }
80
81 /* Return nodes that is not in the current list of nodes */
82 Array.prototype.node_diff = function(arr) {
83 return this.filter(function(i) {
84 for (var j = 0; j < arr.length ; j++) {
85 if (arr[j].name === i.name)
86 return false;
87 }
88 return true;
89 });
90 };
91
92 /* Return removed links */
93 function gone_links (json, links, gone) {
94 for (var i = 0; i < links.length ; i ++){
95 var found = 0;
96 for (var j = 0; j < json.links.length ; j ++){
97 if (links[i].source.name == json.nodes[json.links[j].source].name &&
98 links[i].target.name == json.nodes[json.links[j].target].name ){
99 found = 1;
100 break;
101 }
102 }
103 if ( found == 0 ){
104 gone.push(links[i]);
105 }
106 }
107 return gone;
108 }
109
110 /* Return added links */
111 function added_links (json, links, added) {
112 for (var j = 0; j < json.links.length ; j ++){
113 var found = 0;
114 for (var i = 0; i < links.length ; i ++){
115 if (links[i].source.name == json.nodes[json.links[j].source].name &&
116 links[i].target.name == json.nodes[json.links[j].target].name ){
117 found = 1;
118 break;
119 }
120 }
121 if ( found == 0 ){
122 added.push(json.links[j]);
123 }
124 }
125 return added;
126 }
127
128 function dragstart(d, i) {
129 force.stop() // stops the force auto positioning before you start dragging
130 }
131
132 function dragmove(d, i) {
133 d.px += d3.event.dx;
134 d.py += d3.event.dy;
135 d.x += d3.event.dx;
136 d.y += d3.event.dy;
137 tick(); // this is the key to make it work together with updating both px,py,x,y on d !
138 }
139
140 function dragend(d, i) {
141 d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
142 tick();
143 force.resume();
144 }
145
146 /* check if toplogy has changed and update node[] and link[] accordingly */
147 function cdiff(json) {
148 var changed = false;
149
150 var n_adds = json.nodes.node_diff(nodes);
151 var n_rems = nodes.node_diff(json.nodes);
152 for (var i = 0; i < n_adds.length; i++) {
153 nodes.push(n_adds[i]);
154 changed = true;
155 }
156 for (var i = 0; i < n_rems.length; i++) {
157 for (var j = 0; j < nodes.length; j++) {
158 if ( nodes[j].name == n_rems[i].name ){
159 nodes.splice(j,1);
160 changed = true;
161 break;
162 }
163 }
164 }
165 var l_adds = [];
166 var l_rems = [];
167 l_adds = added_links(json, links, l_adds);
168 l_rems = gone_links(json, links, l_rems);
169 for (var i = 0; i < l_rems.length ; i++) {
170 for (var j = 0; j < links.length; j++) {
171 if (links[j].source.name == l_rems[i].source.name &&
172 links[j].target.name == l_rems[i].target.name) {
173 links.splice(j,1);
174 changed = true;
175 break;
176 }
177 }
178 }
179 // Sorce/target of an element of l_adds[] are corresponding to the index of json.node[]
180 // which is different from the index of node[] (new nodes are always added to the last)
181 // So update soure/target node indexes of l_add[] need to be fixed to point to the proper
182 // node in node[];
183 for (var i = 0; i < l_adds.length; i++) {
184 for (var j = 0; j < nodes.length; j++) {
185 if ( json.nodes[l_adds[i].source].name == nodes[j].name ){
186 l_adds[i].source = j;
187 break;
188 }
189 }
190 for (var j = 0; j < nodes.length; j++) {
191 if ( json.nodes[l_adds[i].target].name == nodes[j].name ){
192 l_adds[i].target = j;
193 break;
194 }
195 }
196 links.push(l_adds[i]);
197 changed = true;
198 }
199
200 // Update "group" attribute of nodes
201 for (var i = 0; i < nodes.length; i++) {
202 for (var j = 0; j < json.nodes.length; j++) {
203 if ( nodes[i].name == json.nodes[j].name ){
204 if (nodes[i].group != json.nodes[j].group){
205 nodes[i].group = json.nodes[j].group;
206 changed = true;
207 }
208 }
209 }
210 }
Ubuntu765deff2013-02-28 18:39:13 +0000211 for (var i = 0; i < links.length; i++) {
212 for (var j = 0; j < json.links.length; j++) {
213 if (links[i].target.name == json.nodes[json.links[j].target].name &&
214 links[i].source.name == json.nodes[json.links[j].source].name ){
215 if (links[i].type != json.links[j].type){
216 links[i].type = json.links[j].type;
217 changed = true;
218 }
219 }
220 }
221 }
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000222 return changed
223 }
224
Masayoshi Kobayashibcb03c02014-01-22 15:18:49 -0800225 function nr_active_sw(){
226 var n=0;
227 var nodes = force.nodes();
228 for(var i=0;i<nodes.length;i++){
229 if(nodes[i].group!=0)
230 n++;
231 };
232 return n;
233 }
234
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000235 function draw(force, path, circle, text){
236 force.stop();
Masayoshi Kobayashibcb03c02014-01-22 15:18:49 -0800237 svg.append("svg:text")
238 .attr("x", 50)
239 .attr("y", 20)
240 .text(function(){return "Switch: " + force.nodes().length + " (Active: " + nr_active_sw() + ")/ Link: " + force.links().length});
241
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000242 path.enter().append("svg:path")
Ubuntu765deff2013-02-28 18:39:13 +0000243 .attr("class", function(d) { return "link"; })
244 .attr("marker-end", function(d) {
245 if(d.type == 1){
246 return "url(#TriangleRed)";
247 } else {
248 return "url(#Triangle)";
249 }
250 });
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000251
252 circle.enter().append("svg:circle")
Ubuntu37ebda62013-03-01 00:35:31 +0000253 .attr("r", function(d) {
254 if (d.group == 1000){
255 return radius/2;
256 }else{
257 return radius;
258 }
259 })
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000260 .call(node_drag);
261// .call(force.drag);
262
263 text.enter().append("svg:text")
Ubuntuc016ba12013-02-27 21:53:41 +0000264 .attr("x", radius)
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000265 .attr("y", ".31em")
Ubuntu37ebda62013-03-01 00:35:31 +0000266 .text(function(d) {
267 l=d.name.split(":").length
Masayoshi Kobayashi29d282c2013-03-21 22:27:22 +0000268 return d.name.split(":")[l-2] + ":" + d.name.split(":")[l-1]
Ubuntu37ebda62013-03-01 00:35:31 +0000269 });
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000270
271 circle.append("title")
272 .text(function(d) { return d.name; });
273
274 circle.attr("fill", function(d) {
Tim Lindberg86a85f62013-03-26 11:34:01 -0700275 if (d.group == 1){
276 return "red"
277 }else if (d.group == 2){
278 return "blue"
279 }else if (d.group == 3){
280 return "green"
281 }else if (d.group == 4){
282 return "orange"
283 }else if (d.group == 5){
284 return "cyan"
285 }else if (d.group == 6){
286 return "magenta"
287 }else if (d.group == 7){
288 return "yellow"
289 }else if (d.group == 8){
290 return "purple"
291 }else{
292 return "gray"
293 }
294
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000295 });
296
297 path.attr("stroke", function(d) {
298 if(d.type == 1){
299 return "red"
300 } else {
301 return "black"
302 }
303 }).attr("stroke-width", function(d) {
304 if(d.type == 1){
Ubuntu765deff2013-02-28 18:39:13 +0000305 return "2px";
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000306 } else {
307 return "1.5px";
308 }
309 }).attr("marker-end", function(d) {
310 if(d.type == 1){
311 return "url(#TriangleRed)";
312 } else {
313 return "url(#Triangle)";
314 }
315 });
316
317
318 path.exit().remove();
319 circle.exit().remove();
320 text.exit().remove();
321
322 force.on("tick", tick);
323 force.start();
324
325 }
326
327 function update(json) {
328 var changed = cdiff(json);
329
330 console.log("changed? " + changed);
Ubuntu765deff2013-02-28 18:39:13 +0000331 path = svg.selectAll("path").data(links)
332 circle = svg.selectAll("circle").data(nodes);
333 text = svg.selectAll("text").data(nodes);
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000334
Ubuntu765deff2013-02-28 18:39:13 +0000335 console.log(path)
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000336 if (changed){
337
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000338 draw(force, path, circle, text);
339 }
340 }
341
342 function init_draw(nodes, links){
Masayoshi Kobayashi1407a502013-02-27 06:23:08 +0000343 path = svg.append("svg:g").selectAll("path").data(links);
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000344 circle = svg.append("svg:g").selectAll("circle").data(nodes);
345 text = svg.append("svg:g").selectAll("text").data(nodes);
346
347 draw(force, path, circle, text);
348
349 setInterval(function() {
350 $.ajax({
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000351 url: data_source,
352 success: function(json) {
353 update(json)
354 },
355 dataType: "json"
356 });
357 }, 3000);
358 }
Ubuntu82b8a832013-02-06 22:00:11 +0000359 function tick() {
360 path.attr("d", function(d) {
361 var dx = d.target.x - d.source.x,
362 dy = d.target.y - d.source.y,
363 dr = 1/d.linknum; //linknum is defined above
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000364 dr = 0; // 0 for direct line
Ubuntu82b8a832013-02-06 22:00:11 +0000365 return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
366 });
Ubuntu765deff2013-02-28 18:39:13 +0000367 path.attr("stroke", function(d) {
368 if(d.type == 1){
369 return "red"
370 } else {
371 return "black"
372 }
373 }).attr("stroke-width", function(d) {
374 if(d.type == 1){
375 return "3px";
376 } else {
377 return "1.5px";
378 }
379 }).attr("marker-end", function(d) {
380 if(d.type == 1){
381 return "url(#TriangleRed)";
382 } else {
383 return "url(#Triangle)";
384 }
385 });
386
Ubuntu82b8a832013-02-06 22:00:11 +0000387// circle.attr("cx", function(d) { return d.x; }).attr("cy", function(d) { return d.y; });
388 circle.attr("transform", function(d) {
Ubuntuc016ba12013-02-27 21:53:41 +0000389 x = Math.max(radius, Math.min(width - radius, d.x));
390 y = Math.max(radius, Math.min(height - radius, d.y));
391// return "translate(" + d.x + "," + d.y + ")";
392 return "translate(" + x + "," + y + ")";
Ubuntu82b8a832013-02-06 22:00:11 +0000393 })
Ubuntuc016ba12013-02-27 21:53:41 +0000394
Ubuntuaea2a682013-02-08 08:30:10 +0000395 circle.attr("fill", function(d) {
Tim Lindberg86a85f62013-03-26 11:34:01 -0700396 if (d.group == 1){
397 return "red"
398 }else if (d.group == 2){
399 return "blue"
400 }else if (d.group == 3){
401 return "green"
402 }else if (d.group == 4){
403 return "orange"
404 }else if (d.group == 5){
405 return "cyan"
406 }else if (d.group == 6){
407 return "magenta"
408 }else if (d.group == 7){
409 return "yellow"
410 }else if (d.group == 8){
411 return "purple"
412 }else{
413 return "gray"
414 }
Ubuntuaea2a682013-02-08 08:30:10 +0000415 });
Ubuntu82b8a832013-02-06 22:00:11 +0000416// text.attr("x", function(d) { return d.x; }).attr("y", function(d) { return d.y; });
Ubuntu82b8a832013-02-06 22:00:11 +0000417 text.attr("transform", function(d) {
418 return "translate(" + d.x + "," + d.y + ")";
419 });
420 }
421}
Masayoshi Kobayashif63ef2f2013-02-20 21:47:21 +0000422