1 //$("#univbris_welcome").hide();
2 //jQuery("#univbris_flowspace_selection").show();
5 var nIslands=[], //replace
7 width = parseInt($("#topologyContainer").css("width")), /* Obtain width from container */
10 //Islands area generation
12 ny = Math.sqrt(nIslands/p),
17 if (nx*ny > nIslands){
18 if (nx > ny && (nx-1)*ny >= nIslands)
20 else if( nx <= ny && nx*(ny-1) >= nIslands)
24 var aw = Math.floor((width-(nx+1)*pad)/nx),
25 ah = Math.floor((height-(ny+1)*pad)/ny);
27 for (i=0; i<nIslands; i++){
28 tx0 = pad + (pad + aw)*(Math.floor(i%nx));
29 ty0 = pad + (pad + ah)*(Math.floor(i/nx));
30 foci[i] = {x0: tx0, x1: tx0 + aw, y0: ty0, y1: ty0 + ah};
33 function randomXToY(minVal,maxVal,floatVal){
34 var randVal = minVal+(Math.random()*(maxVal-minVal));
35 return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
39 function pEllipse(set){
40 function getDistance(p){
41 return Math.pow((p[0]-cx),2)/Math.pow(rx,2) + Math.pow((p[1]-cy),2)/Math.pow(ry,2);
47 cx = (set.x1 + set.x0)/2;
48 rx = ((set.x1 - set.x0)/2 + (set.y1 - set.y0)/2)/2;
49 cy = (set.y1 + set.y0)/2;
50 ry = (set.y1 - set.y0)/2;
53 p = [randomXToY(set.x0, set.x1), randomXToY(set.y0, set.y1) ];
64 for (i=0;i<d3_nodes.length;i++){
65 epoints.push(d3_nodes[i]['group']);
74 for (i=0;i<d3_nodes.length;i++){
76 node['nodeValue']=d3_nodes[i].value;
77 node['nodeName']=d3_nodes[i].name;
78 node['image']=d3_nodes[i].image;
80 node['group']=d3_nodes[i].group;
81 node['location']=d3_nodes[i].location;
82 node['description']= d3_nodes[i].description;
85 node['available']= d3_nodes[i].available;
92 for (i=0;i<d3_links.length;i++){
94 link['source']= d3_links[i].source;
95 link['target']= d3_links[i].target;
96 link['value']= d3_links[i].value;
103 function getLinkStyle(d, attr){
104 rsc_ids = d.value.split("-");
108 if (id1.indexOf("eth") != -1){
109 $(":checkbox#"+id0).click();
112 if((! $(":checkbox#"+id0+":checked").length && ! $(":checkbox#"+id1+":checked").length) || ($(":checkbox#"+id0+":checked").length && $(":checkbox#"+id1+":checked").length)){
113 $(":checkbox#"+id0).click();
114 $(":checkbox#"+id1).click();
116 else if ($(":checkbox#"+id0+":checked").length){
117 $(":checkbox#"+id1).click();
120 $(":checkbox#"+id0).click();
123 }else if(attr=="mouseover"){
124 var values = {stroke: "#00BFFF", strokewidth: "2" };
127 if( ($(":checkbox#"+rsc_ids[0]+":checked").length && rsc_ids[1].indexOf("eth") != -1) ||($(":checkbox#"+rsc_ids[0]+":checked").length && $(":checkbox#"+rsc_ids[1]+":checked").length)){
128 if (attr == "stroke")
133 if (attr == "stroke")
141 function getBaseNodeColor(d){
144 return d3.rgb(d.color.toString().toString()).darker(.15*group);
147 function getNodeCircleStyle(d, attr){
148 selected_len = $(":checkbox:checked.node_id_"+d.nodeValue).length;
149 all_len = $(":checkbox:.node_id_"+d.nodeValue).length;
150 selected_server = $(".server_node_"+d.nodeValue+".connected").length;
152 return d3.rgb(d.color.toString()).brighter(5);
153 }else if(attr=="click"){
154 if(selected_len == all_len) {
155 $(":checkbox:checked.node_id_"+d.nodeValue).click();
156 return getBaseNodeColor(d);
158 $(":checkbox:not(:checked).node_id_"+d.nodeValue).click();
159 return d3.rgb(d.color.toString()).darker(5);
161 }else if (attr == "dragstop" && selected_len == 0){
162 return getBaseNodeColor(d);
165 return getBaseNodeColor(d);
167 if (selected_len != 0){
168 return d3.rgb(d.color.toString()).darker(5);
170 return getBaseNodeColor(d);
176 function getNodesIsland(d){
178 data.nodes.forEach(function(o, i){
187 zoom_in_active = false;
188 zoom_out_active = false;
191 function zoomIn(zoom){
192 if(zoom_in_active == false && zoom_out_active == false){
193 $("#link_zoom_in img").css("background-color", "#666");
194 cur_zoom = cur_zoom + zoom;
195 zoom_in_active = true;
198 else if(zoom_in_active == true){
199 cur_zoom = cur_zoom - zoom;
200 $("#link_zoom_in img").css("background-color", "");
201 $("#target, svg, g").css("cursor", "move");
202 zoom_in_active = false;
206 cur_zoom = cur_zoom + zoom + zoom;
207 $("#link_zoom_out img").css("background-color", "");
208 $("#link_zoom_in img").css("background-color", "#666");
209 zoom_out_active = false;
210 zoom_in_active = true;
215 function zoomOut(zoom){
216 if(zoom_out_active == false && zoom_in_active == false){
217 if((cur_zoom - zoom) >0){
218 $("#link_zoom_out img").css("background-color", "#666");
219 cur_zoom = cur_zoom - zoom;
220 zoom_out_active = true;
223 $("#target, svg, g").css("cursor", "move");
226 else if(zoom_out_active == true){
227 cur_zoom = cur_zoom + zoom;
228 $("#link_zoom_out img").css("background-color", "");
229 $("#target, svg, g").css("cursor", "move");
230 zoom_out_active = false;
234 cur_zoom = cur_zoom - zoom;
235 zoom_out_active = false;
236 $("#link_zoom_in img").css("background-color", "");
237 if((cur_zoom - zoom) > 0){
238 $("#link_zoom_out img").css("background-color", "#666");
239 zoom_out_active = true;
242 $("#target, svg, g").css("cursor", "move");
247 function zoomReset(){
255 if (zoom_in_active == true || zoom_out_active == true){
256 var mouseClick = d3.mouse(this);
257 _x = -mouseClick[0]/2;
258 _y = -mouseClick[1]/2;
259 if(zoom_out_active == true){
265 zoom_in_active = false;
266 zoom_out_active = false;
272 // trans=[(Math.round(width/cur_zoom) - width)/2, (Math.round(height/cur_zoom) - height)/2];
273 trans = [posx, posy];
276 .attr('x', function(d){ return d.x; })
277 .attr('y', function(d){ return d.y; })
279 "translate(" + trans +")"
280 + "scale(" + cur_zoom + ")");
281 $("#link_zoom_in img").css("background-color","");
282 $("#link_zoom_out img").css("background-color","");
283 $("#target, svg, g").css("cursor", "move");
286 //Global position of the canvas
290 /* Translation - bound to drag behavior */
291 dragMap = function(d) {
292 //No drag while zoom option active
293 if(zoom_in_active == false && zoom_out_active == false){
296 svg.attr('x', function(d) { return d.x; })
297 .attr('y', function(d) { return d.y; })
298 .attr("transform", "translate(" + posx + "," + posy + ") scale (" + cur_zoom + ")");
303 /* Instantiation General parameters*/
305 color = d3.scale.category10().domain(d3.range(nIslands)),
306 radius = d3.scale.sqrt().range([0, 12]);
308 var svg = d3.select("#target")
311 .attr("pointer-events", "all")
312 .attr("width", width)
313 .attr("height", height)
315 .call(d3.behavior.drag().on("drag", dragMap))
316 .append("svg:g").on("zoom", redraw)
317 .attr("cursor", "move")
320 var nodes = data.nodes;
321 // Set color for each node
322 nodes.forEach(function(d) {
323 if (d.available != "False") {
324 d.color = color(d.group%nIslands);
330 var links = data.links;
332 // Modified version (Carolina)
333 var force = d3.layout.force()
334 .gravity(1/(2*nIslands))
335 .distance(200/nIslands)
337 .size([width, height])
342 var EMPTY_ISLAND = "Island with no resources";
344 //XXX:Very ugly, needs improvement
346 for (i = 0; i< nIslands; i++){
347 islandsLocs[i] = EMPTY_ISLAND;
351 for (i = 0; i< nodes.length; i++){
352 nodeInitialPos[i] = [nodes[i].x, nodes[i].y];
353 if (islandsLocs[nodes[i].group] == EMPTY_ISLAND){
354 islandsLocs[nodes[i].group] = nodes[i].location;
359 for (i = 0; i< nIslands; i++){
360 dataislands[i] = {rx: (aw/2 + ah/2)/2, ry: ah/2, cx:(foci[i].x0+foci[i].x1)/2, cy:(foci[i].y0+foci[i].y1)/2, group: i, location: islandsLocs[i]};
363 var islands = svg.selectAll(".island")
366 .attr("class", "island")
368 var iellipses = islands.append("ellipse")
369 .attr("rx", function(d) { return d.rx; })
370 .attr("ry", function(d) { return d.ry; })
371 .attr("cx",function(d) { return d.cx; })
372 .attr("cy", function(d) { return d.cy; })
373 .style("fill", function(d) { return color(d.group%nIslands); })
374 .style("stroke", function(d) { return color(d.group%nIslands);})
375 .style("opacity", 0.3)
376 .style("stroke-opacity", 0.7)
378 var ilabels = islands.append("text")
379 .attr("text-anchor", "middle")
380 .attr("y", function(d){ return d.cy + d.ry*0.9})
381 .attr("x", function(d){ return d.cx})
382 .attr("font-color", function(d) { return d3.rgb(color(d.group%nIslands)).darker(5); })
384 .style("cursor", "default")
385 .text(function(d) { return d.location });
387 //First ellipse animation on startup
390 var link = svg.selectAll(".link")
392 .enter().append("line")
393 .attr("class", "link");
395 link.on("click", function(d) {
396 d3.select(this).style("stroke", function(d){return getLinkStyle(d, "click");})});
398 var node = svg.selectAll(".node")
401 .attr("class", "node")
403 .call(d3.behavior.drag()
404 .on("dragstart", function(d, i, e) {
408 .on("drag", function(d, i) {
413 d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "drag");})
416 .on("dragend", function(d, i) {
417 // d.fixed = true; // of course set the node to fixed so the force does not include the node in its auto positioning stuff //with the force.stop() it won't autopositioning, allowing to regroup the nodes
418 d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "dragstop");})
425 node.append("circle")
426 .attr("r", function(d) { return d.radius; })
427 .style("stroke", function(d){return getNodeCircleStyle(d, "stroke");})
428 .style("fill", function(d){return getNodeCircleStyle(d, "fill");});
431 .attr("xlink:href", function (d) { return d.image; })
436 .attr("opacity", function(d) { return d.available=="False"?0.8:1; })
441 .text(function(d) { return d.name });
443 node.on("mouseover", function (d, i){
444 //tooltip.show(get_node_info_formated(d));
445 // Ugly hack to decode HTML
446 tooltip.show($('<div/>').html(d.description).text());
447 $("#selected_node_info").html("Selected " + d.type + ": " + d.nodeName + " at " + d.location);
448 $("#selected_node_info").css("background-color", d.color );
449 $("#selected_node_info").css("text-shadow", "-3px 2px 4px #eee");
450 $("#selected_node_info").show();
453 .on("mouseout", function() {
454 $("#selected_node_info").css("background-color", "#ebf5ff");
455 //$("#selected_node_info").hide()
458 .on("click", function(d) {
459 /* Only available AMs can be selected */
460 if (d.available != "False") {
461 //checkTopologyLoops(d);
462 d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "click");});
466 //Number of nodes in each Island
468 for(i=0; i<nIslands; i++){
469 qNodes[i] = getNodesIsland(i);
471 var grav = 0.008 * nx * ny;
473 force.on("tick", function(e){
474 var k = grav * e.alpha;
477 // Adjust K colliding factor
478 $.each(data.nodes, function(i, n){
479 if (node_groups[n.group] == undefined) {
480 node_groups[n.group] = 1;
482 node_groups[n.group] += 1;
486 data.nodes.forEach(function(o, i){
488 // Dumb hack: limit expansion through #nodes
489 if (node_groups[o.group] >= 10) {
490 fact = Math.floor(node_groups[o.group]/10);
494 // Carolina: when there are few nodes, avoid them to stay too far away from the center
495 // AND when there are so many nodes avoid them to stay too near each others
496 if(qNodes[o.group] < 5){
502 o.y += k * fact * qNodes[o.group] * ((dataislands[o.group].cy) - o.y);
503 o.x += k * fact * qNodes[o.group] * ((dataislands[o.group].cx) - o.x);
508 node.each(collide(.5));
509 node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")";})
510 .attr("cx", function(d) { return d.x; })
511 .attr("cy", function(d) { return d.y; });
513 link.attr("x1", function(d) { return d.source.x; })
514 .attr("y1", function(d) { return d.source.y; })
515 .attr("x2", function(d) { return d.target.x; })
516 .attr("y2", function(d) { return d.target.y; });
519 function redrawNodes(){
520 node.selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "stroke");});
521 link.style("stroke", function(d) {return getLinkStyle(d, "stroke");});
522 link.style("stroke-width", function(d) {return getLinkStyle(d, "stroke-width");});
527 link.attr("x1", function(d) { return d.source.x; })
528 .attr("y1", function(d) { return d.source.y; })
529 .attr("x2", function(d) { return d.target.x; })
530 .attr("y2", function(d) { return d.target.y; });
532 node.each(collide(.5));
533 node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
540 iellipses.attr("rx", function(d) { return d.rx; })
541 .style("display","block")
542 .attr("ry", function(d) { return d.ry; })
543 .attr("cx",function(d) { return d.cx; })
544 .attr("cy", function(d) { return d.cy; })
545 .style("fill", function(d) { return color(d.group%nIslands); })
546 .style("stroke", function(d) { return color(d.group%nIslands);})
547 .style("opacity", 0.3)
548 .style("stroke-opacity", 0.7)
550 ilabels.attr("text-anchor", "middle")
551 .attr("y", function(d){ return d.cy + d.ry*0.9})
552 .attr("x", function(d){ return d.cx})
553 .attr("font-color", function(d) { return d3.rgb(color(d.group%nIslands)).darker(5); })
555 .text(function(d) { return d.location });
557 iellipses.transition()
558 .style("stroke-width",3)
559 .style("stroke", function(d) { return d3.rgb(color(d.group%nIslands)).brighter(10);})
561 iellipses.transition()
576 function collide(alpha) {
577 var quadtree = d3.geom.quadtree(nodes);
579 var r = d.radius + radius.domain()[1] + padding,
584 quadtree.visit(function(quad, x1, y1, x2, y2) {
585 if (quad.point && (quad.point !== d)) {
586 var x = d.x - quad.point.x,
587 y = d.y - quad.point.y,
588 l = Math.sqrt(x * x + y * y),
589 r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
591 l = (l - r) / l * alpha;
606 $("#link_zoom_in").click(function(){
607 $("#target, svg, g").css("cursor", "url({%url img_media 'zoomin.png' %}),auto");
610 $("#link_zoom_out").click(function(){
611 $("#target, svg, g").css("cursor", "url({%url img_media 'zoomout.png' %}),auto" );