X-Git-Url: http://git.onelab.eu/?p=unfold.git;a=blobdiff_plain;f=plugins%2Funivbristopo%2Fstatic%2Fjs%2Funivbristopo.js;fp=plugins%2Funivbristopo%2Fstatic%2Fjs%2Funivbristopo.js;h=c229c51dd52a1d484739499f2f98fcc8d986719d;hp=0000000000000000000000000000000000000000;hb=6a3f5d4949171451d5df2df5d0f96e9eb396f29c;hpb=583c62239bbf6be5222e170609e547349389c1c1 diff --git a/plugins/univbristopo/static/js/univbristopo.js b/plugins/univbristopo/static/js/univbristopo.js new file mode 100644 index 00000000..c229c51d --- /dev/null +++ b/plugins/univbristopo/static/js/univbristopo.js @@ -0,0 +1,1183 @@ +/** + * univbristopo: ofelia openflow topology plugin + * Version: 3.0 + * Description: plugin to view ofelia topology in myslice + * Requires: js/plugin.js + * URL: http://www.myslice.info + * Author: Frederic Francois + * Copyright: Copyright 2013-2014 Bristol University + * License: GPLv3 + */ + +(function($){ + + d3_nodes=[]; + d3_links=[]; + links_list=[]; + d=2; + window.query_itr=0; + topoviewer_state={mode:"edit",link_type:"non-optical"}; + //svg=d3; + + var UnivbrisTopo = Plugin.extend({ + + init: function(options, element) { + this._super(options, element); + this.listen_query(options.query_uuid); + jQuery('#topo_plugin').hide(); + //console.log("topo init called"); + }, + + new_record: function(record) + { + var urn = record['urn']; + var pos = urn.search('link'); + + if (pos!=-1){ + var link = urn.substring(pos+5); + pos = link.search("_"); + var head_node=link.substring(0,pos); + link=link.substring(pos+1); + pos = link.search("_"); + var head_port=link.substring(0,pos); + link=link.substring(pos+1); + pos = link.search("_"); + var tail_node=link.substring(0,pos); + link=link.substring(pos+1); + var tail_port=link; + + var link_type=0; + if (urn.search('opticalpacket')!=-1){ + link_type=4; + } + else if (urn.search('optical')!=-1){ + link_type=1; + } + else if (urn.search('compute')!=-1){ + link_type=2; + } + else if (urn.search('federation')!=-1){ + link_type=3; + } + + + //get island name + pos = urn.search('ofam'); + var testbed=urn.substring(pos+5); + testbed=testbed.substring(0, testbed.search('link')-1); + + switch (link_type){ + case 0: + var src_id=addNode(head_node,testbed,"packet"); + var dst_id=addNode(tail_node,testbed,"packet"); + //var tmp_link={}; + addLink(src_id,dst_id,head_port,tail_port,urn); + /*tmp_link['source']=src_id; + tmp_link['target']=dst_id; + tmp_link['src_port']=head_port; + tmp_link['dst_port']=tail_port; + tmp_link['value']=urn; + d3_links.push(tmp_link);*/ + break; + + case 1: + var src_id=addNode(head_node,testbed,"optical"); + var dst_id=addNode(tail_node,testbed,"optical"); + //var tmp_link={}; + addLink(src_id,dst_id,head_port,tail_port,urn); + /*tmp_link['source']=src_id; + tmp_link['target']=dst_id; + tmp_link['src_port']=head_port; + tmp_link['dst_port']=tail_port; + tmp_link['value']=urn; + d3_links.push(tmp_link);*/ + break; + + case 2: + var src_id=addNode(head_node,testbed,"packet"); + var dst_id=addNode(tail_node,testbed,"compute"); + //var tmp_link={}; + addLink(src_id,dst_id,head_port,tail_port,urn); + /*tmp_link['source']=src_id; + tmp_link['target']=dst_id; + tmp_link['src_port']=head_port; + tmp_link['dst_port']=tail_port; + tmp_link['value']=urn; + d3_links.push(tmp_link);*/ + break; + + case 3: + var src_id=addNode(head_node,testbed,"federation"); + var dst_id=addNode(tail_node,testbed,"packet"); + //var tmp_link={}; + addLink(src_id,dst_id,head_port,tail_port,urn); + /*tmp_link['source']=src_id; + tmp_link['target']=dst_id; + tmp_link['src_port']=head_port; + tmp_link['dst_port']=tail_port; + tmp_link['value']=urn; + d3_links.push(tmp_link);*/ + break; + + case 4: + var src_id=addNode(head_node,testbed,"optical"); + var dst_id=addNode(tail_node,testbed,"packet"); + //var tmp_link={}; + addLink(src_id,dst_id,head_port,tail_port,urn); + /*tmp_link['source']=src_id; + tmp_link['target']=dst_id; + tmp_link['src_port']=head_port; + tmp_link['dst_port']=tail_port; + tmp_link['value']=urn; + d3_links.push(tmp_link);*/ + break; + } + } + }, + + on_new_record: function(record) + { + //if (query_itr=2){ + this.new_record(record); + //} + }, + + + on_query_done: function() + { + query_itr=query_itr+1; + if (query_itr==2){ + return; + } + //console.log("graph all done called:"+query_itr); + describeNodes(); + calLinkNum(); + //console.log(d3_links); + //if (query_itr=2){ + //$("#univbris_welcome").hide(); + //jQuery("#univbris_flowspace_selection").show(); + //$("#link_zoom_in").click(zoomIn(0.25)); + /* d3 data */ + + + + var nIslands=1, //replace + pad = 5, + width = parseInt($("#topo_plugin_width").css("width")); //800,//parseInt($("#topologyContainer").css("width")), /* Obtain width from container */ + if(width==0){width=800;} + 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; i1) { + p = [randomXToY(set.x0, set.x1), randomXToY(set.y0, set.y1) ]; + d = getDistance(p); + } + } catch(err) { + p = []; + } + + return p; + }; + + + var epoints= []; + for (i=0;i0){ + $("#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(){ + //console.log('into target clicked with zoomin:'+zoom_in_active); + + 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(); + } + }; + + $('#target').click(function(){ + //console.log('target clicked'); + click(); + }); + + 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]); + + 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("path") + .attr("class", "link").style({'fill': 'black','stroke': "#ccc", 'stroke-width': "4px" }); + + link.on("click", function(d) { + d3.select(this).style(JSON.parse(getLinkStyle(d, "click"))); + } + ); + + link.on("mouseover", function(d) { + //console.log(getLinkStyle(d, "mouseover")); + d3.select(this).style(JSON.parse(getLinkStyle(d, "mouseover"))); + // d3.select(this).style({'stroke': "blue", 'stroke-width': "3px" }) + } + ); + + link.on("mouseout", function(d) { + //console.log("mouseout"); + d3.select(this).style(JSON.parse(getLinkStyle(d, "mouseout"))); + // d3.select(this).style({'stroke': "#CCC", 'stroke-width': "2px" }) + } + ); + + 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 + //$('
').html(d.description).text() + tooltip.show(d.description); + $("#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= 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; }); + */ + link.attr("d", function(d) { + var dx = d.target.x - d.source.x, + dy = d.target.y - d.source.y, + + //dr = 50/d.linknum; //linknum is defined above + dr = Math.sqrt(dx * dx + dy * dy)/d.linknum; + // console.log("printing d:"); + // console.log(d); + //return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; + return "M" + d.source.x + "," + d.source.y + + "A" + dr + "," + dr + " 0 0 1," + d.target.x + "," + d.target.y + + "A" + dr + "," + dr + " 0 0 0," + d.source.x + "," + d.source.y; + }); + }); + + function redrawNodes(){ + node.selectAll("circle").style("stroke", function(d){return getNodeCircleStyle(d, "stroke");}); + link.style({'fill': 'black','stroke': "#00BFFF", 'stroke-width': "5px" });//"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); + + link.attr("d", function(d) { + var dx = d.target.x - d.source.x, + dy = d.target.y - d.source.y, + dr = Math.sqrt(dx * dx + dy * dy)/d.linknum; + //dr = 50/d.linknum; //linknum is defined above + //console.log("target:"+d.target.nodeName+" source:" +d.source.nodeName+" link_no: "+dr); + //dr = 75;//Math.sqrt(dx * dx + dy * dy); + //return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; + return "M" + d.source.x + "," + d.source.y + + "A" + dr + "," + dr + " 0 0 1," + d.target.x + "," + d.target.y + + "A" + dr + "," + dr + " 0 0 0," + d.source.x + "," + d.source.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").onclick(zoomIn(0.25)); + + $("#topo_regroup").unbind('click'); + $("#topo_regroup").click(function(e){ + e.preventDefault(); + regroup(); + }); + + $("#link_zoom_reset").unbind('click'); + $("#link_zoom_reset").click(function(e){ + e.preventDefault(); + zoomReset(); + redraw(); + }); + + $("#link_zoom_in").unbind('click'); + $("#link_zoom_in").click(function(e){ + e.preventDefault(); + //console.log("zoom current value:"); + //console.log(cur_zoom); + $("#target, svg, g").css("cursor", "url('../../static/img/zoomin.png'),auto"); + zoomIn(0.25); + //console.log(zoom_in_active); + // redraw(); + }); + + $("#link_zoom_out").unbind('click'); + $("#link_zoom_out").click(function(e){ + e.preventDefault(); + $("#target, svg, g").css("cursor", "url('../../static/img/zoomout.png'),auto" ); + zoomOut(0.25); + //redraw(); + }); + $("#target, svg, g").css("cursor", "crosshair"); + //alert("called"); + //jQuery('#topo_plugin').hide(); + //}; + //} //if query_itr + }, //end of function of on all query done + + //jQuery('#complete-univbris_topology').hide(); + + }); + + $.plugin('UnivbrisTopo', UnivbrisTopo); + + function addNode(node_dpid,location,node_type){ + var found=false; + var i=0; + for(i=0;i b.source) {return 1;} + else if (a.source < b.source) {return -1;} + else { + if (a.target > b.target) {return 1;} + if (a.target < b.target) {return -1;} + else {return 0;} + } + });*/ + + for (var i=0; i
Connections:
" + for(i1=0;i1to Switch " + d3_nodes[d3_links[i1].target].nodeName + " at port "+ d3_links[i1].dst_port+"
"; + } + else if(d3_links[i1].target==i){ + d3_nodes[i].description+="• Port "+ d3_links[i1].dst_port + " to Switch " + d3_nodes[d3_links[i1].source].nodeName + " at port "+ d3_links[i1].src_port+"
"; + } + } + + + } + else if (d3_nodes[i].type=="compute"){ + d3_nodes[i].description="Virtualization server name:
"+d3_nodes[i].nodeName+"

Connections:
"; + for(i1=0;i1to Switch " + d3_nodes[d3_links[i1].target].nodeName + " at port "+ d3_links[i1].dst_port+"
"; + //console.log(d3_links[i1],d3_nodes[d3_links[i1].target]); + } + if(d3_links[i1].target==i){ + d3_nodes[i].description+="• Port "+ d3_links[i1].dst_port + " to Switch " + d3_nodes[d3_links[i1].source].nodeName + " at port "+ d3_links[i1].src_port+"
"; + //console.log(d3_links[i1],d3_nodes[d3_links[i1].source]); + } + } + } + + /*try{ + + + } + catch(err){ + console.log(err); + }*/ + + //if(d3_nodes[i].nodeName==node_dpid){ + // found=true; + // break; + //} + } + + + }; + + + +})(jQuery);