Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into fibre
[unfold.git] / plugins / univbristopo / templates / spillout
diff --git a/plugins/univbristopo/templates/spillout b/plugins/univbristopo/templates/spillout
new file mode 100644 (file)
index 0000000..8b5e44b
--- /dev/null
@@ -0,0 +1,613 @@
+//$("#univbris_welcome").hide();
+         //jQuery("#univbris_flowspace_selection").show();
+
+         /* d3 data */
+         var nIslands=[], //replace
+             pad = 5,
+              width = parseInt($("#topologyContainer").css("width")), /* Obtain width from container */
+              height = 400;
+
+         //Islands area generation
+         var p = width/height
+              ny = Math.sqrt(nIslands/p),
+              nx = Math.ceil(p*ny),
+              ny = Math.ceil(ny),
+              foci = [];
+
+         if (nx*ny > nIslands){
+               if (nx > ny && (nx-1)*ny >= nIslands)
+               nx--;
+               else if( nx <= ny && nx*(ny-1) >= nIslands)
+               ny--;
+         }
+
+         var aw = Math.floor((width-(nx+1)*pad)/nx),
+              ah = Math.floor((height-(ny+1)*pad)/ny);
+
+         for (i=0; i<nIslands; i++){
+               tx0 = pad + (pad + aw)*(Math.floor(i%nx));
+               ty0 = pad + (pad + ah)*(Math.floor(i/nx));
+               foci[i] = {x0: tx0, x1: tx0 + aw, y0: ty0, y1: ty0 + ah};
+         }
+
+         function randomXToY(minVal,maxVal,floatVal){
+               var randVal = minVal+(Math.random()*(maxVal-minVal));
+               return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
+         };
+
+         
+          function pEllipse(set){
+               function getDistance(p){
+                       return Math.pow((p[0]-cx),2)/Math.pow(rx,2) + Math.pow((p[1]-cy),2)/Math.pow(ry,2);
+               };
+
+               d = 2;
+
+               try {
+                       cx = (set.x1 + set.x0)/2;
+                       rx = ((set.x1 - set.x0)/2 + (set.y1 - set.y0)/2)/2;
+                       cy = (set.y1 + set.y0)/2;
+                       ry = (set.y1 - set.y0)/2;
+       
+                       while (d>1) {
+                               p = [randomXToY(set.x0, set.x1), randomXToY(set.y0, set.y1) ];
+                               d = getDistance(p);     
+                       }
+               } catch(err) {
+                       p = [];
+               }
+
+               return p;
+         };
+
+         var epoints= [];
+         for (i=0;i<d3_nodes.length;i++){
+               epoints.push(d3_nodes[i]['group']);
+
+         };
+          
+          var data = {};
+
+         var nodes=[];
+         
+
+         for (i=0;i<d3_nodes.length;i++){
+               var node={};
+               node['nodeValue']=d3_nodes[i].value;
+               node['nodeName']=d3_nodes[i].name;
+               node['image']=d3_nodes[i].image;
+               node['color']= "";
+               node['group']=d3_nodes[i].group;
+               node['location']=d3_nodes[i].location;
+               node['description']= d3_nodes[i].description;
+               node['fixed']= false;
+               node['radius']= 10;
+               node['available']= d3_nodes[i].available;
+               nodes.push(node);
+         };
+
+         data["nodes"]=nodes;
+
+         var links=[];
+         for (i=0;i<d3_links.length;i++){
+               var link={};
+               link['source']= d3_links[i].source;
+               link['target']= d3_links[i].target;
+               link['value']= d3_links[i].value;
+               links.push(link);
+         }
+
+        data["links"]=links;
+       },
+       
+       function getLinkStyle(d, attr){
+               rsc_ids = d.value.split("-");
+               if(attr=="click"){
+                       id0 = rsc_ids[0];
+                       id1 = rsc_ids[1];
+                       if (id1.indexOf("eth") != -1){
+                            $(":checkbox#"+id0).click();
+                       }
+                       else{           
+                       if((! $(":checkbox#"+id0+":checked").length && ! $(":checkbox#"+id1+":checked").length) || ($(":checkbox#"+id0+":checked").length && $(":checkbox#"+id1+":checked").length)){
+                               $(":checkbox#"+id0).click();
+                               $(":checkbox#"+id1).click();
+                       }
+                       else if ($(":checkbox#"+id0+":checked").length){
+                               $(":checkbox#"+id1).click();
+                       }
+                       else{
+                               $(":checkbox#"+id0).click();    
+                       }
+                       }
+               }else if(attr=="mouseover"){
+                       var values = {stroke: "#00BFFF", strokewidth: "2" };
+                       return values;
+               }else{
+                       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)){
+                               if (attr == "stroke")
+                                       return "#666";
+                               else
+                                       return 2;
+                       }else{
+                               if (attr == "stroke")
+                                       return "#ccc";
+                               else
+                                       return 2;
+                       }
+               }
+       };
+
+       function getBaseNodeColor(d){
+               var group = 0;
+               group = d.group;
+               return d3.rgb(d.color.toString().toString()).darker(.15*group);
+       };
+
+       function getNodeCircleStyle(d, attr){
+               selected_len = $(":checkbox:checked.node_id_"+d.nodeValue).length;
+               all_len = $(":checkbox:.node_id_"+d.nodeValue).length;
+               selected_server = $(".server_node_"+d.nodeValue+".connected").length;
+               if(attr == "drag"){
+                       return d3.rgb(d.color.toString()).brighter(5);
+               }else if(attr=="click"){
+                        if(selected_len == all_len) {
+                               $(":checkbox:checked.node_id_"+d.nodeValue).click();
+                               return getBaseNodeColor(d);
+                        }else{
+                               $(":checkbox:not(:checked).node_id_"+d.nodeValue).click();
+                               return d3.rgb(d.color.toString()).darker(5);
+                       }
+               }else if (attr == "dragstop" && selected_len == 0){
+                       return getBaseNodeColor(d);
+               }else{
+                               if (attr == "fill"){
+                                       return getBaseNodeColor(d);
+                               } else{
+                                       if (selected_len != 0){
+                                               return d3.rgb(d.color.toString()).darker(5);
+                                       }else{
+                                               return getBaseNodeColor(d);
+                                       }
+                               }
+               }
+       };
+
+       function getNodesIsland(d){
+               var nNodes = 0;
+               data.nodes.forEach(function(o, i){
+                  if(o.group == d){
+                       nNodes++;
+                  }
+               });
+           return nNodes;
+       }
+
+       cur_zoom = 1;
+       zoom_in_active = false;
+       zoom_out_active = false;
+
+       
+       function zoomIn(zoom){
+           if(zoom_in_active == false && zoom_out_active == false){
+               $("#link_zoom_in img").css("background-color", "#666");
+               cur_zoom = cur_zoom + zoom;
+               zoom_in_active = true;
+           }
+
+           else if(zoom_in_active == true){
+               cur_zoom = cur_zoom - zoom;
+               $("#link_zoom_in img").css("background-color", "");
+               $("#target, svg, g").css("cursor", "move");
+               zoom_in_active = false;
+           }
+
+           else{
+               cur_zoom = cur_zoom + zoom + zoom;
+               $("#link_zoom_out img").css("background-color", "");
+               $("#link_zoom_in img").css("background-color", "#666");
+               zoom_out_active = false;
+               zoom_in_active = true;
+           }
+       };
+
+       
+       function zoomOut(zoom){
+           if(zoom_out_active == false && zoom_in_active == false){
+               if((cur_zoom - zoom) >0){
+                   $("#link_zoom_out img").css("background-color", "#666");
+                   cur_zoom = cur_zoom - zoom;
+                   zoom_out_active = true;
+               }
+               else{
+                   $("#target, svg, g").css("cursor", "move");
+               }
+           }   
+           else if(zoom_out_active == true){
+               cur_zoom = cur_zoom + zoom;
+               $("#link_zoom_out img").css("background-color", "");
+               $("#target, svg, g").css("cursor", "move");
+               zoom_out_active = false;
+           }
+
+           else{
+               cur_zoom = cur_zoom - zoom;
+               zoom_out_active = false;
+               $("#link_zoom_in img").css("background-color", "");
+               if((cur_zoom - zoom) > 0){
+                   $("#link_zoom_out img").css("background-color", "#666");
+                   zoom_out_active = true;
+               }
+               else{
+                   $("#target, svg, g").css("cursor", "move");
+               }
+           }
+       };
+
+       function zoomReset(){
+           cur_zoom = 0.99;
+           posx = 0;
+           posy = 0;
+           return redraw();
+       };
+
+       function click(){
+           if (zoom_in_active == true || zoom_out_active == true){
+               var mouseClick = d3.mouse(this);
+               _x = -mouseClick[0]/2;
+               _y = -mouseClick[1]/2;
+               if(zoom_out_active == true){
+                   _x = -_x/2;
+                   _y = -_y/2;
+               }
+               posx += _x;
+               posy += _y;
+               zoom_in_active = false;
+               zoom_out_active = false;
+               return redraw();
+           }
+       };
+
+       function redraw() {
+               //  trans=[(Math.round(width/cur_zoom) - width)/2, (Math.round(height/cur_zoom) - height)/2];
+                   trans = [posx, posy];
+                   svg.transition()
+                      .duration(500)
+                      .attr('x', function(d){ return d.x; })
+                      .attr('y', function(d){ return d.y; })
+                      .attr("transform", 
+                           "translate(" + trans +")"
+                           + "scale(" + cur_zoom + ")");
+                  $("#link_zoom_in img").css("background-color","");
+                  $("#link_zoom_out img").css("background-color","");
+                  $("#target, svg, g").css("cursor", "move"); 
+       };
+
+       //Global position of the canvas
+       var posx = 0;
+       var posy = 0;
+
+       /* Translation - bound to drag behavior */
+       dragMap = function(d) {
+       //No drag while zoom option active
+          if(zoom_in_active == false && zoom_out_active == false){
+             posx += d3.event.dx;
+             posy += d3.event.dy;
+             svg.attr('x', function(d) { return d.x; })
+                .attr('y', function(d) { return d.y; })
+                .attr("transform", "translate(" + posx + "," + posy + ") scale (" + cur_zoom + ")");
+          }
+       };
+
+       
+       /* Instantiation General parameters*/
+       var  padding = 6,
+            color = d3.scale.category10().domain(d3.range(nIslands)),
+            radius = d3.scale.sqrt().range([0, 12]);
+
+       var svg = d3.select("#target")
+           .on("click", click)
+           .append("svg")
+               .attr("pointer-events", "all")
+               .attr("width", width)
+               .attr("height", height)
+               .datum({x: 0, y: 0})
+               .call(d3.behavior.drag().on("drag", dragMap))
+           .append("svg:g").on("zoom", redraw)
+               .attr("cursor", "move")       
+       
+       // DATA VARIABLES
+       var nodes = data.nodes;
+       // Set color for each node
+       nodes.forEach(function(d) {
+           if (d.available != "False") {
+               d.color = color(d.group%nIslands);
+           } else {
+               d.color = "#CCC";
+           }
+       });
+
+       var links = data.links;
+
+       // Modified version (Carolina)
+       var force = d3.layout.force()
+           .gravity(1/(2*nIslands))
+           .distance(200/nIslands)
+           .friction(0.6)
+           .size([width, height])
+           .nodes(nodes)
+           .links(links)
+           .start();
+
+       var EMPTY_ISLAND = "Island with no resources";
+
+       //XXX:Very ugly, needs improvement
+       var islandsLocs = []
+       for (i = 0; i< nIslands; i++){
+               islandsLocs[i] = EMPTY_ISLAND;
+       }
+
+       nodeInitialPos = []
+       for (i = 0; i< nodes.length; i++){
+               nodeInitialPos[i] = [nodes[i].x, nodes[i].y];
+               if (islandsLocs[nodes[i].group] == EMPTY_ISLAND){
+                       islandsLocs[nodes[i].group] = nodes[i].location;
+               }
+       }
+
+       var dataislands = []
+       for (i = 0; i< nIslands; i++){
+               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]};
+       }
+
+       var islands = svg.selectAll(".island")
+           .data(dataislands)
+         .enter().append("g")
+               .attr("class", "island")
+
+       var iellipses = islands.append("ellipse")
+           .attr("rx", function(d) { return d.rx; })
+           .attr("ry", function(d) { return d.ry; })
+           .attr("cx",function(d) { return d.cx; })
+           .attr("cy", function(d) { return d.cy; })
+           .style("fill", function(d) { return color(d.group%nIslands); })
+           .style("stroke", function(d) { return color(d.group%nIslands);}) 
+           .style("opacity", 0.3)
+           .style("stroke-opacity", 0.7)
+
+       var ilabels = islands.append("text")
+             .attr("text-anchor", "middle")
+             .attr("y", function(d){ return d.cy + d.ry*0.9})
+             .attr("x", function(d){ return d.cx})
+             .attr("font-color", function(d) { return d3.rgb(color(d.group%nIslands)).darker(5); })
+             .style("opacity",1)
+             .style("cursor", "default")
+             .text(function(d) { return d.location });
+
+       //First ellipse animation on startup
+       animate();
+
+       var link = svg.selectAll(".link")
+           .data(links)
+         .enter().append("line")
+           .attr("class", "link");
+
+       link.on("click", function(d) {
+                       d3.select(this).style("stroke", function(d){return getLinkStyle(d, "click");})});
+
+       var node = svg.selectAll(".node")
+           .data(nodes)
+         .enter().append("g")
+           .attr("class", "node")
+           .call(force.drag)
+           .call(d3.behavior.drag()
+           .on("dragstart", function(d, i, e) {
+                   d.fixed = false;
+                   force.stop();
+           })
+           .on("drag", function(d, i) {
+                   d.px += d3.event.dx;
+                   d.py += d3.event.dy;
+                   d.x += d3.event.dx;
+                   d.y += d3.event.dy;
+                   d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "drag");}) 
+                   tick();
+           })
+           .on("dragend", function(d, i) {
+                 //  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
+                   d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "dragstop");})
+                   tick();
+                   force.stop();
+           })
+           );
+
+       
+       node.append("circle")
+           .attr("r", function(d) { return d.radius; })
+           .style("stroke", function(d){return getNodeCircleStyle(d, "stroke");})
+           .style("fill", function(d){return getNodeCircleStyle(d, "fill");});
+
+       node.append("image")
+           .attr("xlink:href", function (d) { return d.image; })
+           .attr("x", -8)
+           .attr("y", -8)
+           .attr("width", 16)
+           .attr("height", 16)
+           .attr("opacity", function(d) { return d.available=="False"?0.8:1; })
+
+       node.append("text")
+           .attr("dx", 12)
+           .attr("dy", ".35em")
+           .text(function(d) { return d.name });
+
+       node.on("mouseover", function (d, i){
+                       //tooltip.show(get_node_info_formated(d));
+                       // Ugly hack to decode HTML
+                       tooltip.show($('<div/>').html(d.description).text());
+                       $("#selected_node_info").html("Selected " + d.type + ": " + d.nodeName + " at " + d.location);
+                       $("#selected_node_info").css("background-color", d.color );
+                       $("#selected_node_info").css("text-shadow", "-3px 2px 4px #eee");
+                       $("#selected_node_info").show();
+               }
+               )
+               .on("mouseout", function() {
+                               $("#selected_node_info").css("background-color", "#ebf5ff");
+                               //$("#selected_node_info").hide()
+                               tooltip.hide();
+                       })
+               .on("click", function(d) {
+                   /* Only available AMs can be selected */
+                   if (d.available != "False") {
+                       //checkTopologyLoops(d);
+                       d3.select(this).selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "click");});
+                   }
+               })
+
+       //Number of nodes in each Island
+       var qNodes = [];
+       for(i=0; i<nIslands; i++){
+          qNodes[i] = getNodesIsland(i);
+       } 
+       var grav = 0.008 * nx * ny;
+
+       force.on("tick", function(e){
+           var k = grav * e.alpha;
+           var node_groups = {}
+
+           // Adjust K colliding factor
+           $.each(data.nodes, function(i, n){
+               if (node_groups[n.group] == undefined) {
+                   node_groups[n.group] = 1;
+               } else {
+                   node_groups[n.group] += 1;
+               }
+           });
+
+           data.nodes.forEach(function(o, i){
+               var fact = 1;
+               // Dumb hack: limit expansion through #nodes
+               if (node_groups[o.group] >= 10) {
+                   fact = Math.floor(node_groups[o.group]/10);
+               } else {
+                   fact = o.group+1;
+               }
+               // Carolina: when there are few nodes, avoid them to stay too far away from the center
+               // AND when there are so many nodes avoid them to stay too near each others 
+               if(qNodes[o.group] < 5){
+                   fact = fact * 2;
+               } else {
+                   fact = fact/2;
+               }
+               try {
+                   o.y += k * fact * qNodes[o.group] * ((dataislands[o.group].cy) - o.y);
+                   o.x += k * fact * qNodes[o.group] * ((dataislands[o.group].cx) - o.x);
+               } catch (err) {
+               }
+           });
+
+           node.each(collide(.5));
+           node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")";})
+               .attr("cx", function(d) { return d.x; })
+               .attr("cy", function(d) { return d.y; });
+
+           link.attr("x1", function(d) { return d.source.x; })
+               .attr("y1", function(d) { return d.source.y; })
+               .attr("x2", function(d) { return d.target.x; })
+               .attr("y2", function(d) { return d.target.y; });
+       });
+
+       function redrawNodes(){
+               node.selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "stroke");});
+               link.style("stroke", function(d) {return getLinkStyle(d, "stroke");});
+               link.style("stroke-width", function(d) {return getLinkStyle(d, "stroke-width");});
+       }
+
+       function tick() {
+         
+         link.attr("x1", function(d) { return d.source.x; })
+             .attr("y1", function(d) { return d.source.y; })
+             .attr("x2", function(d) { return d.target.x; })
+             .attr("y2", function(d) { return d.target.y; });
+         
+         node.each(collide(.5));
+         node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
+             .attr("cx", d.x)
+             .attr("cy", d.y);
+       };
+
+       function animate(){
+
+       iellipses.attr("rx", function(d) { return d.rx; })
+           .style("display","block")
+           .attr("ry", function(d) { return d.ry; })
+           .attr("cx",function(d) { return d.cx; })
+           .attr("cy", function(d) { return d.cy; })
+           .style("fill", function(d) { return color(d.group%nIslands); })
+           .style("stroke", function(d) { return color(d.group%nIslands);}) 
+           .style("opacity", 0.3)
+           .style("stroke-opacity", 0.7)
+
+       ilabels.attr("text-anchor", "middle")
+             .attr("y", function(d){ return d.cy + d.ry*0.9})
+             .attr("x", function(d){ return d.cx})
+             .attr("font-color", function(d) { return d3.rgb(color(d.group%nIslands)).darker(5); })
+             .style("opacity",1)
+             .text(function(d) { return d.location });
+
+       iellipses.transition()
+                       .style("stroke-width",3)
+                       .style("stroke", function(d) { return d3.rgb(color(d.group%nIslands)).brighter(10);})
+                       .duration(1500)
+       iellipses.transition()
+                  .delay(1500)
+                  .style("opacity",0)
+                  .duration(3000)
+       ilabels.transition()
+                  .delay(1500)
+                  .style("opacity",0)
+                  .duration(3000);
+       }
+
+       function regroup(){
+               force.resume();
+               animate();
+       }
+
+       function collide(alpha) {
+         var quadtree = d3.geom.quadtree(nodes);
+         return function(d) {
+           var r = d.radius + radius.domain()[1] + padding,
+               nx1 = d.x - r,
+               nx2 = d.x + r,
+               ny1 = d.y - r,
+               ny2 = d.y + r;
+           quadtree.visit(function(quad, x1, y1, x2, y2) {
+             if (quad.point && (quad.point !== d)) {
+               var x = d.x - quad.point.x,
+                   y = d.y - quad.point.y,
+                   l = Math.sqrt(x * x + y * y),
+                   r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
+               if (l < r) {
+                 l = (l - r) / l * alpha;
+                 d.x -= x *= l;
+                 d.y -= y *= l;
+                 quad.point.x += x;
+                 quad.point.y += y;
+               }
+             }
+             return x1 > nx2
+                 || x2 < nx1
+                 || y1 > ny2
+                 || y2 < ny1;
+           });
+         };
+       };
+
+       $("#link_zoom_in").click(function(){
+         $("#target, svg, g").css("cursor", "url({%url img_media 'zoomin.png' %}),auto");
+       });
+
+       $("#link_zoom_out").click(function(){
+         $("#target, svg, g").css("cursor", "url({%url img_media 'zoomout.png' %}),auto" );
+       });
+