--- /dev/null
+//$("#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" );
+ });
+