X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=planetlab%2Fslices%2Fleases.js;h=4e45e4dd503d7526e42bf444070872bd53b60ee9;hb=dc7edf39ad96036cff8377cac70b20953502cd06;hp=60e7e6cbe1271ec07df302bbc0a7da1280d23860;hpb=17162ec98854a8c0fb3dd0eb89e55ec1c79809e2;p=plewww.git diff --git a/planetlab/slices/leases.js b/planetlab/slices/leases.js index 60e7e6c..4e45e4d 100644 --- a/planetlab/slices/leases.js +++ b/planetlab/slices/leases.js @@ -1,128 +1,498 @@ +/* Thierry Parmentelat -- INRIA */ + /* need to put some place else in CSS ? */ -var x_txt = {"font": 'Fontin-Sans, Arial', stroke: "none", fill: "#008"}, -var y_txt = {"font": 'Fontin-Sans, Arial', stroke: "none", fill: "#800"}, -var x_nodename = 200; -var x_grain = 20; -var x_sep=10; -var y_header = 10 +// space for the nodenames +var x_nodelabel = 200; +// right space after the nodename - removed from the above +var x_sep=20; +// height for the (two) rows of timelabels +var y_header = 12; +// space between nodes +var y_sep = 10; + +// 1-grain leases attributes +// leases_w is configurable from html +//var leases_w = 20; var y_node = 15; -var y_sep = 5 -var radius=5; - -var leases_namespace = { - - init_scheduler: function () { - // Grab the data - var data = [], - axisx = [], - axisy = [], - table = $$("table#leases_data")[0]; - // the nodenames +var radius= 6; + +var anim_delay=350; + +/* decorations / headers */ +/* note: looks like the 'font' attr is not effective... */ + +// vertical rules +var attr_rules={'fill':"#888", 'stroke-dasharray':'- ', 'stroke-width':0.5}; +// set font-size separately in here rather than depend on the height +var txt_timelabel = {"font": 'Times, "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', + stroke: "none", fill: "#008", 'font-size': 9}; +var txt_allnodes = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', stroke: "none", fill: "#404"}; +var txt_nodelabel = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', stroke: "none", fill: "#008"}; + +var attr_timebutton = {'fill':'#bbf', 'stroke': '#338','stroke-width':1, + 'stroke-linecap':'round', 'stroke-linejoin':'miter', 'stroke-miterlimit':3}; +var attr_daymarker = {'stroke':'#000','stroke-width':2}; +var attr_half_daymarker = {'stroke':'#444','stroke-width':2}; + +/* lease dimensions and colors */ +/* refrain from using gradient color, seems to not be animated properly */ +/* lease was originally free and is still free */ +var attr_lease_free_free={'fill':"#def", 'stroke-width':0.5, 'stroke-dasharray':''}; +/* lease was originally free and is now set for our usage */ +var attr_lease_free_mine={'fill':"green", 'stroke-width':1, 'stroke-dasharray':'-..'}; +/* was mine and is still mine */ +var attr_lease_mine_mine={'fill':"#beb", 'stroke-width':0.5, 'stroke-dasharray':''}; +/* was mine and is about to be released */ +var attr_lease_mine_free={'fill':"white", 'stroke-width':1, 'stroke-dasharray':'-..'}; +var attr_lease_other={'fill':"#f88"}; + +/* other slices name */ +var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', stroke: "none", fill: "#444", + "font-size": 12 }; + +//////////////////////////////////////////////////////////// +// the scheduler object +function Scheduler () { + + // xxx-hacky dunno how to retrieve this object from an ajax callback + Scheduler.scheduler=this; + + // the data contains slice names, and lease_id, we need this to find our own leases (mine) + this.paper=null; + + //////////////////// + // store the result of an ajax request in the leases_data table + this.set_html = function (html_data) { + var table_text = $$("table#leases_data")[0].innerHTML; + $$("table#leases_data")[0].innerHTML=html_data; + table_text = $$("table#leases_data")[0].innerHTML; + return true; + } + + //////////////////// + // the names of the hidden fields that hold the input to this class + // are hard-wired for now + this.parse_html = function () { + + var table = $$("table#leases_data")[0]; + // no reservable nodes - no data + if ( ! table) return false; + + // the nodelabels + var data = [], axisx = [], axisy = []; table.getElementsBySelector("tbody>tr>th").each(function (cell) { axisy.push(getInnerText(cell)); }); + // test for at least one entry; other wise this means we haven't retrieved + // the html dta yet + if (axisy.length <1) return false; + // the timeslot labels table.getElementsBySelector("thead>tr>th").each(function (cell) { - axisx.push(getInnerText(cell)); + /* [0]: timestamp -- [1]: displayable*/ + axisx.push(getInnerText(cell).split("&")); }); + // leases - expect colspan to describe length in grains + // the text contents is expected to be lease_id & slicename table.getElementsBySelector("tbody>tr>td").each(function (cell) { - data.push(new Array (getInnerText(cell),cell.colSpan)); + var cell_data; + var slice_attributes=getInnerText(cell).split('&'); + // booked leases come with lease id and slice name + if (slice_attributes.length == 2) { + // leases is booked : slice_id, slice_name, duration in grains + cell_data=new Array (slice_attributes[0], slice_attributes[1], cell.colSpan); + } else { + cell_data = new Array ('','',cell.colSpan); + } + data.push(cell_data); }); - // slicename : the upper-left cell - var this_slicename = getInnerText(table.getElementsBySelector("thead>tr>td")[0]); - table.hide(); - var nb_nodes = axisy.length, nb_grains = axisx.length; - var total_width = x_nodename + nb_grains*x_grain; - var total_height = y_header + nb_nodes*(y_node+y_sep); - paper = Raphael("leases_area", total_width, total_height,10); -// alert ('nodes=' + nb_nodes + ' grains=' + nb_grains + ' data items=' + data.length + ' slicename=' + this_slicename); - -// color = table.css("color"); - -// var top=y_sep; + + this.axisx=axisx; + this.axisy=axisy; + this.data=data; + return true; + } + + // how many time slots + this.nb_grains = function () { return this.axisx.length;} + + //////////////////// + // draw + this.draw_area = function (canvas_id) { + this.total_width = x_nodelabel + this.nb_grains()*this.leases_w; + this.total_height = 2*y_header /* the timelabels */ + + 2*y_sep /* extra space */ + + y_node /* all-nodes & timebuttons row */ + + (this.axisy.length)*(y_node+y_sep); /* the regular nodes and preceding space */ + // reuse for paper if exists with same size, or (re-)create otherwise + var paper; + if (this.paper == null) { + paper = Raphael (canvas_id, this.total_width+x_sep, this.total_height); + } else if (this.paper.width==this.total_width && this.paper.height==this.total_height) { + paper=this.paper; + paper.clear(); + } else { + $$("#"+canvas_id)[0].innerHTML=""; + paper = Raphael (canvas_id, this.total_width+x_sep, this.total_height); + } + this.paper=paper; + + // the path for the triangle-shaped buttons + this.timebutton_path="M1,0L"+(this.leases_w-1)+",0L"+(this.leases_w/2)+","+y_header+"L1,0"; + + var axisx=this.axisx; + + var axisy=this.axisy; + // maintain the list of nodelabels for the 'all nodes' button + this.nodelabels=[]; + + ////////// create the time slots legend var top=0; - var left=x_nodename; - axisx.each (function (timeslot) { - var label=paper.text(left,top+y_header/2,timeslot).attr(y_txt).attr("font-size",y_header); - left+=x_grain; - }); - top += y_header+y_sep; - + var left=x_nodelabel; + + var daymarker_height= 2*y_header+2*y_sep + (axisy.length+1)*(y_node+y_sep); + var daymarker_path="M0,0L0," + daymarker_height; + + var half_daymarker_off= 2*y_header+y_sep; + var half_daymarker_path="M0," + half_daymarker_off + "L0," + daymarker_height; + + var col=0; + for (var i=0, len=axisx.length; i < len; ++i) { + // pick the printable part + var timelabel=axisx[i][1]; + var y = top+y_header; + if (col%2 == 0) y += y_header; + col +=1; + // display time label + var timelabel=paper.text(left,y,timelabel).attr(txt_timelabel) + .attr({"text-anchor":"middle"}); + // draw vertical line + var path_spec="M"+left+" "+(y+y_header/2)+"L"+left+" "+this.total_height; + var rule=paper.path(path_spec).attr(attr_rules); + // show a day marker when relevant + var timestamp=parseInt(axisx[i][0]); + if ( (timestamp%(24*3600))==0) { + paper.path(daymarker_path).attr({'translation':left+','+top}).attr(attr_daymarker); + } else if ( (timestamp%(12*3600))==0) { + paper.path(half_daymarker_path).attr({'translation':left+','+top}).attr(attr_daymarker); + } + left+=(this.leases_w); + } + + ////////// the row with the timeslot buttons (the one labeled 'All nodes') + this.granularity=axisx[1][0]-axisx[0][0]; + + // move two lines down + top += 2*y_header+2*y_sep; + left=x_nodelabel; + // all nodes buttons + var allnodes = paper.text (x_nodelabel-x_sep,top+y_node/2,"All nodes").attr(txt_allnodes) + .attr ({"font-size":y_node, "text-anchor":"end","baseline":"bottom"}); + allnodes.scheduler=this; + allnodes.click(allnodes_methods.click); + // timeslot buttons + for (var i=0, len=axisx.length; i < len; ++i) { + var timebutton=paper.path(this.timebutton_path).attr({'translation':left+','+top}).attr(attr_timebutton); + timebutton.from_time=axisx[i][0]; + timebutton.scheduler=this; + timebutton.click(timebutton_methods.click); + left+=(this.leases_w); + } + + //////// the body of the scheduler : loop on nodes + top += y_node+y_sep; var data_index=0; - axisy.each(function (node) { + this.leases=[]; + for (var i=0, len=axisy.length; i0) ? 1 : 0; + for (var i=0, len=scheduler.nodelabels.length; i=until_time) { + if (scan.current == "free") relevant_free.push(scan); + else if (scan.current == "mine") relevant_mine.push(scan); + } + } +// window.console.log("Found " + relevant_free.length + " free and " + relevant_mine.length + " mine"); + /* decide what to do, whether book or release */ + if (relevant_mine.length==0 && relevant_free.length==0) { + alert ("Nothing to do in this timeslot on the selected nodes"); + return; + } + // if at least one is free, let's book + if (relevant_free.length > 0) { + for (var i=0, len=relevant_free.length; i