flot-rails 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/README.md +57 -0
- data/Rakefile +4 -0
- data/flot-rails.gemspec +22 -0
- data/lib/flot-rails.rb +1 -0
- data/lib/flot/rails.rb +6 -0
- data/lib/flot/rails/engine.rb +7 -0
- data/lib/flot/rails/version.rb +6 -0
- data/vendor/assets/javascripts/excanvas.js +1427 -0
- data/vendor/assets/javascripts/excanvas.min.js +1 -0
- data/vendor/assets/javascripts/jquery.colorhelpers.js +179 -0
- data/vendor/assets/javascripts/jquery.colorhelpers.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.crosshair.js +167 -0
- data/vendor/assets/javascripts/jquery.flot.crosshair.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.fillbetween.js +183 -0
- data/vendor/assets/javascripts/jquery.flot.fillbetween.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.image.js +238 -0
- data/vendor/assets/javascripts/jquery.flot.image.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.js +2599 -0
- data/vendor/assets/javascripts/jquery.flot.min.js +6 -0
- data/vendor/assets/javascripts/jquery.flot.navigate.js +336 -0
- data/vendor/assets/javascripts/jquery.flot.navigate.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.pie.js +750 -0
- data/vendor/assets/javascripts/jquery.flot.pie.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.resize.js +60 -0
- data/vendor/assets/javascripts/jquery.flot.resize.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.selection.js +344 -0
- data/vendor/assets/javascripts/jquery.flot.selection.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.stack.js +184 -0
- data/vendor/assets/javascripts/jquery.flot.stack.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.symbol.js +70 -0
- data/vendor/assets/javascripts/jquery.flot.symbol.min.js +1 -0
- data/vendor/assets/javascripts/jquery.flot.threshold.js +103 -0
- data/vendor/assets/javascripts/jquery.flot.threshold.min.js +1 -0
- metadata +41 -6
@@ -0,0 +1,6 @@
|
|
1
|
+
/* Javascript plotting library for jQuery, v. 0.7.
|
2
|
+
*
|
3
|
+
* Released under the MIT license by IOLA, December 2007.
|
4
|
+
*
|
5
|
+
*/
|
6
|
+
(function(b){b.color={};b.color.make=function(d,e,g,f){var c={};c.r=d||0;c.g=e||0;c.b=g||0;c.a=f!=null?f:1;c.add=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]+=j}return c.normalize()};c.scale=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]*=j}return c.normalize()};c.toString=function(){if(c.a>=1){return"rgb("+[c.r,c.g,c.b].join(",")+")"}else{return"rgba("+[c.r,c.g,c.b,c.a].join(",")+")"}};c.normalize=function(){function h(k,j,l){return j<k?k:(j>l?l:j)}c.r=h(0,parseInt(c.r),255);c.g=h(0,parseInt(c.g),255);c.b=h(0,parseInt(c.b),255);c.a=h(0,c.a,1);return c};c.clone=function(){return b.color.make(c.r,c.b,c.g,c.a)};return c.normalize()};b.color.extract=function(d,e){var c;do{c=d.css(e).toLowerCase();if(c!=""&&c!="transparent"){break}d=d.parent()}while(!b.nodeName(d.get(0),"body"));if(c=="rgba(0, 0, 0, 0)"){c="transparent"}return b.color.parse(c)};b.color.parse=function(c){var d,f=b.color.make;if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c)){return f(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c)){return f(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}var e=b.trim(c).toLowerCase();if(e=="transparent"){return f(255,255,255,0)}else{d=a[e]||[0,0,0];return f(d[0],d[1],d[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function(c){function b(av,ai,J,af){var Q=[],O={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{show:null,position:"bottom",mode:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},hooks:{}},az=null,ad=null,y=null,H=null,A=null,p=[],aw=[],q={left:0,right:0,top:0,bottom:0},G=0,I=0,h=0,w=0,ak={processOptions:[],processRawData:[],processDatapoints:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},aq=this;aq.setData=aj;aq.setupGrid=t;aq.draw=W;aq.getPlaceholder=function(){return av};aq.getCanvas=function(){return az};aq.getPlotOffset=function(){return q};aq.width=function(){return h};aq.height=function(){return w};aq.offset=function(){var aB=y.offset();aB.left+=q.left;aB.top+=q.top;return aB};aq.getData=function(){return Q};aq.getAxes=function(){var aC={},aB;c.each(p.concat(aw),function(aD,aE){if(aE){aC[aE.direction+(aE.n!=1?aE.n:"")+"axis"]=aE}});return aC};aq.getXAxes=function(){return p};aq.getYAxes=function(){return aw};aq.c2p=C;aq.p2c=ar;aq.getOptions=function(){return O};aq.highlight=x;aq.unhighlight=T;aq.triggerRedrawOverlay=f;aq.pointOffset=function(aB){return{left:parseInt(p[aA(aB,"x")-1].p2c(+aB.x)+q.left),top:parseInt(aw[aA(aB,"y")-1].p2c(+aB.y)+q.top)}};aq.shutdown=ag;aq.resize=function(){B();g(az);g(ad)};aq.hooks=ak;F(aq);Z(J);X();aj(ai);t();W();ah();function an(aD,aB){aB=[aq].concat(aB);for(var aC=0;aC<aD.length;++aC){aD[aC].apply(this,aB)}}function F(){for(var aB=0;aB<af.length;++aB){var aC=af[aB];aC.init(aq);if(aC.options){c.extend(true,O,aC.options)}}}function Z(aC){var aB;c.extend(true,O,aC);if(O.xaxis.color==null){O.xaxis.color=O.grid.color}if(O.yaxis.color==null){O.yaxis.color=O.grid.color}if(O.xaxis.tickColor==null){O.xaxis.tickColor=O.grid.tickColor}if(O.yaxis.tickColor==null){O.yaxis.tickColor=O.grid.tickColor}if(O.grid.borderColor==null){O.grid.borderColor=O.grid.color}if(O.grid.tickColor==null){O.grid.tickColor=c.color.parse(O.grid.color).scale("a",0.22).toString()}for(aB=0;aB<Math.max(1,O.xaxes.length);++aB){O.xaxes[aB]=c.extend(true,{},O.xaxis,O.xaxes[aB])}for(aB=0;aB<Math.max(1,O.yaxes.length);++aB){O.yaxes[aB]=c.extend(true,{},O.yaxis,O.yaxes[aB])}if(O.xaxis.noTicks&&O.xaxis.ticks==null){O.xaxis.ticks=O.xaxis.noTicks}if(O.yaxis.noTicks&&O.yaxis.ticks==null){O.yaxis.ticks=O.yaxis.noTicks}if(O.x2axis){O.xaxes[1]=c.extend(true,{},O.xaxis,O.x2axis);O.xaxes[1].position="top"}if(O.y2axis){O.yaxes[1]=c.extend(true,{},O.yaxis,O.y2axis);O.yaxes[1].position="right"}if(O.grid.coloredAreas){O.grid.markings=O.grid.coloredAreas}if(O.grid.coloredAreasColor){O.grid.markingsColor=O.grid.coloredAreasColor}if(O.lines){c.extend(true,O.series.lines,O.lines)}if(O.points){c.extend(true,O.series.points,O.points)}if(O.bars){c.extend(true,O.series.bars,O.bars)}if(O.shadowSize!=null){O.series.shadowSize=O.shadowSize}for(aB=0;aB<O.xaxes.length;++aB){V(p,aB+1).options=O.xaxes[aB]}for(aB=0;aB<O.yaxes.length;++aB){V(aw,aB+1).options=O.yaxes[aB]}for(var aD in ak){if(O.hooks[aD]&&O.hooks[aD].length){ak[aD]=ak[aD].concat(O.hooks[aD])}}an(ak.processOptions,[O])}function aj(aB){Q=Y(aB);ax();z()}function Y(aE){var aC=[];for(var aB=0;aB<aE.length;++aB){var aD=c.extend(true,{},O.series);if(aE[aB].data!=null){aD.data=aE[aB].data;delete aE[aB].data;c.extend(true,aD,aE[aB]);aE[aB].data=aD.data}else{aD.data=aE[aB]}aC.push(aD)}return aC}function aA(aC,aD){var aB=aC[aD+"axis"];if(typeof aB=="object"){aB=aB.n}if(typeof aB!="number"){aB=1}return aB}function m(){return c.grep(p.concat(aw),function(aB){return aB})}function C(aE){var aC={},aB,aD;for(aB=0;aB<p.length;++aB){aD=p[aB];if(aD&&aD.used){aC["x"+aD.n]=aD.c2p(aE.left)}}for(aB=0;aB<aw.length;++aB){aD=aw[aB];if(aD&&aD.used){aC["y"+aD.n]=aD.c2p(aE.top)}}if(aC.x1!==undefined){aC.x=aC.x1}if(aC.y1!==undefined){aC.y=aC.y1}return aC}function ar(aF){var aD={},aC,aE,aB;for(aC=0;aC<p.length;++aC){aE=p[aC];if(aE&&aE.used){aB="x"+aE.n;if(aF[aB]==null&&aE.n==1){aB="x"}if(aF[aB]!=null){aD.left=aE.p2c(aF[aB]);break}}}for(aC=0;aC<aw.length;++aC){aE=aw[aC];if(aE&&aE.used){aB="y"+aE.n;if(aF[aB]==null&&aE.n==1){aB="y"}if(aF[aB]!=null){aD.top=aE.p2c(aF[aB]);break}}}return aD}function V(aC,aB){if(!aC[aB-1]){aC[aB-1]={n:aB,direction:aC==p?"x":"y",options:c.extend(true,{},aC==p?O.xaxis:O.yaxis)}}return aC[aB-1]}function ax(){var aG;var aM=Q.length,aB=[],aE=[];for(aG=0;aG<Q.length;++aG){var aJ=Q[aG].color;if(aJ!=null){--aM;if(typeof aJ=="number"){aE.push(aJ)}else{aB.push(c.color.parse(Q[aG].color))}}}for(aG=0;aG<aE.length;++aG){aM=Math.max(aM,aE[aG]+1)}var aC=[],aF=0;aG=0;while(aC.length<aM){var aI;if(O.colors.length==aG){aI=c.color.make(100,100,100)}else{aI=c.color.parse(O.colors[aG])}var aD=aF%2==1?-1:1;aI.scale("rgb",1+aD*Math.ceil(aF/2)*0.2);aC.push(aI);++aG;if(aG>=O.colors.length){aG=0;++aF}}var aH=0,aN;for(aG=0;aG<Q.length;++aG){aN=Q[aG];if(aN.color==null){aN.color=aC[aH].toString();++aH}else{if(typeof aN.color=="number"){aN.color=aC[aN.color].toString()}}if(aN.lines.show==null){var aL,aK=true;for(aL in aN){if(aN[aL]&&aN[aL].show){aK=false;break}}if(aK){aN.lines.show=true}}aN.xaxis=V(p,aA(aN,"x"));aN.yaxis=V(aw,aA(aN,"y"))}}function z(){var aO=Number.POSITIVE_INFINITY,aI=Number.NEGATIVE_INFINITY,aB=Number.MAX_VALUE,aU,aS,aR,aN,aD,aJ,aT,aP,aH,aG,aC,a0,aX,aL;function aF(a3,a2,a1){if(a2<a3.datamin&&a2!=-aB){a3.datamin=a2}if(a1>a3.datamax&&a1!=aB){a3.datamax=a1}}c.each(m(),function(a1,a2){a2.datamin=aO;a2.datamax=aI;a2.used=false});for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aJ.datapoints={points:[]};an(ak.processRawData,[aJ,aJ.data,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];var aZ=aJ.data,aW=aJ.datapoints.format;if(!aW){aW=[];aW.push({x:true,number:true,required:true});aW.push({y:true,number:true,required:true});if(aJ.bars.show||(aJ.lines.show&&aJ.lines.fill)){aW.push({y:true,number:true,required:false,defaultValue:0});if(aJ.bars.horizontal){delete aW[aW.length-1].y;aW[aW.length-1].x=true}}aJ.datapoints.format=aW}if(aJ.datapoints.pointsize!=null){continue}aJ.datapoints.pointsize=aW.length;aP=aJ.datapoints.pointsize;aT=aJ.datapoints.points;insertSteps=aJ.lines.show&&aJ.lines.steps;aJ.xaxis.used=aJ.yaxis.used=true;for(aS=aR=0;aS<aZ.length;++aS,aR+=aP){aL=aZ[aS];var aE=aL==null;if(!aE){for(aN=0;aN<aP;++aN){a0=aL[aN];aX=aW[aN];if(aX){if(aX.number&&a0!=null){a0=+a0;if(isNaN(a0)){a0=null}else{if(a0==Infinity){a0=aB}else{if(a0==-Infinity){a0=-aB}}}}if(a0==null){if(aX.required){aE=true}if(aX.defaultValue!=null){a0=aX.defaultValue}}}aT[aR+aN]=a0}}if(aE){for(aN=0;aN<aP;++aN){a0=aT[aR+aN];if(a0!=null){aX=aW[aN];if(aX.x){aF(aJ.xaxis,a0,a0)}if(aX.y){aF(aJ.yaxis,a0,a0)}}aT[aR+aN]=null}}else{if(insertSteps&&aR>0&&aT[aR-aP]!=null&&aT[aR-aP]!=aT[aR]&&aT[aR-aP+1]!=aT[aR+1]){for(aN=0;aN<aP;++aN){aT[aR+aP+aN]=aT[aR+aN]}aT[aR+1]=aT[aR-aP+1];aR+=aP}}}}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];an(ak.processDatapoints,[aJ,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aT=aJ.datapoints.points,aP=aJ.datapoints.pointsize;var aK=aO,aQ=aO,aM=aI,aV=aI;for(aS=0;aS<aT.length;aS+=aP){if(aT[aS]==null){continue}for(aN=0;aN<aP;++aN){a0=aT[aS+aN];aX=aW[aN];if(!aX||a0==aB||a0==-aB){continue}if(aX.x){if(a0<aK){aK=a0}if(a0>aM){aM=a0}}if(aX.y){if(a0<aQ){aQ=a0}if(a0>aV){aV=a0}}}}if(aJ.bars.show){var aY=aJ.bars.align=="left"?0:-aJ.bars.barWidth/2;if(aJ.bars.horizontal){aQ+=aY;aV+=aY+aJ.bars.barWidth}else{aK+=aY;aM+=aY+aJ.bars.barWidth}}aF(aJ.xaxis,aK,aM);aF(aJ.yaxis,aQ,aV)}c.each(m(),function(a1,a2){if(a2.datamin==aO){a2.datamin=null}if(a2.datamax==aI){a2.datamax=null}})}function j(aB,aC){var aD=document.createElement("canvas");aD.className=aC;aD.width=G;aD.height=I;if(!aB){c(aD).css({position:"absolute",left:0,top:0})}c(aD).appendTo(av);if(!aD.getContext){aD=window.G_vmlCanvasManager.initElement(aD)}aD.getContext("2d").save();return aD}function B(){G=av.width();I=av.height();if(G<=0||I<=0){throw"Invalid dimensions for plot, width = "+G+", height = "+I}}function g(aC){if(aC.width!=G){aC.width=G}if(aC.height!=I){aC.height=I}var aB=aC.getContext("2d");aB.restore();aB.save()}function X(){var aC,aB=av.children("canvas.base"),aD=av.children("canvas.overlay");if(aB.length==0||aD==0){av.html("");av.css({padding:0});if(av.css("position")=="static"){av.css("position","relative")}B();az=j(true,"base");ad=j(false,"overlay");aC=false}else{az=aB.get(0);ad=aD.get(0);aC=true}H=az.getContext("2d");A=ad.getContext("2d");y=c([ad,az]);if(aC){av.data("plot").shutdown();aq.resize();A.clearRect(0,0,G,I);y.unbind();av.children().not([az,ad]).remove()}av.data("plot",aq)}function ah(){if(O.grid.hoverable){y.mousemove(aa);y.mouseleave(l)}if(O.grid.clickable){y.click(R)}an(ak.bindEvents,[y])}function ag(){if(M){clearTimeout(M)}y.unbind("mousemove",aa);y.unbind("mouseleave",l);y.unbind("click",R);an(ak.shutdown,[y])}function r(aG){function aC(aH){return aH}var aF,aB,aD=aG.options.transform||aC,aE=aG.options.inverseTransform;if(aG.direction=="x"){aF=aG.scale=h/Math.abs(aD(aG.max)-aD(aG.min));aB=Math.min(aD(aG.max),aD(aG.min))}else{aF=aG.scale=w/Math.abs(aD(aG.max)-aD(aG.min));aF=-aF;aB=Math.max(aD(aG.max),aD(aG.min))}if(aD==aC){aG.p2c=function(aH){return(aH-aB)*aF}}else{aG.p2c=function(aH){return(aD(aH)-aB)*aF}}if(!aE){aG.c2p=function(aH){return aB+aH/aF}}else{aG.c2p=function(aH){return aE(aB+aH/aF)}}}function L(aD){var aB=aD.options,aF,aJ=aD.ticks||[],aI=[],aE,aK=aB.labelWidth,aG=aB.labelHeight,aC;function aH(aM,aL){return c('<div style="position:absolute;top:-10000px;'+aL+'font-size:smaller"><div class="'+aD.direction+"Axis "+aD.direction+aD.n+'Axis">'+aM.join("")+"</div></div>").appendTo(av)}if(aD.direction=="x"){if(aK==null){aK=Math.floor(G/(aJ.length>0?aJ.length:1))}if(aG==null){aI=[];for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel" style="float:left;width:'+aK+'px">'+aE+"</div>")}}if(aI.length>0){aI.push('<div style="clear:left"></div>');aC=aH(aI,"width:10000px;");aG=aC.height();aC.remove()}}}else{if(aK==null||aG==null){for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel">'+aE+"</div>")}}if(aI.length>0){aC=aH(aI,"");if(aK==null){aK=aC.children().width()}if(aG==null){aG=aC.find("div.tickLabel").height()}aC.remove()}}}if(aK==null){aK=0}if(aG==null){aG=0}aD.labelWidth=aK;aD.labelHeight=aG}function au(aD){var aC=aD.labelWidth,aL=aD.labelHeight,aH=aD.options.position,aF=aD.options.tickLength,aG=O.grid.axisMargin,aJ=O.grid.labelMargin,aK=aD.direction=="x"?p:aw,aE;var aB=c.grep(aK,function(aN){return aN&&aN.options.position==aH&&aN.reserveSpace});if(c.inArray(aD,aB)==aB.length-1){aG=0}if(aF==null){aF="full"}var aI=c.grep(aK,function(aN){return aN&&aN.reserveSpace});var aM=c.inArray(aD,aI)==0;if(!aM&&aF=="full"){aF=5}if(!isNaN(+aF)){aJ+=+aF}if(aD.direction=="x"){aL+=aJ;if(aH=="bottom"){q.bottom+=aL+aG;aD.box={top:I-q.bottom,height:aL}}else{aD.box={top:q.top+aG,height:aL};q.top+=aL+aG}}else{aC+=aJ;if(aH=="left"){aD.box={left:q.left+aG,width:aC};q.left+=aC+aG}else{q.right+=aC+aG;aD.box={left:G-q.right,width:aC}}}aD.position=aH;aD.tickLength=aF;aD.box.padding=aJ;aD.innermost=aM}function U(aB){if(aB.direction=="x"){aB.box.left=q.left;aB.box.width=h}else{aB.box.top=q.top;aB.box.height=w}}function t(){var aC,aE=m();c.each(aE,function(aF,aG){aG.show=aG.options.show;if(aG.show==null){aG.show=aG.used}aG.reserveSpace=aG.show||aG.options.reserveSpace;n(aG)});allocatedAxes=c.grep(aE,function(aF){return aF.reserveSpace});q.left=q.right=q.top=q.bottom=0;if(O.grid.show){c.each(allocatedAxes,function(aF,aG){S(aG);P(aG);ap(aG,aG.ticks);L(aG)});for(aC=allocatedAxes.length-1;aC>=0;--aC){au(allocatedAxes[aC])}var aD=O.grid.minBorderMargin;if(aD==null){aD=0;for(aC=0;aC<Q.length;++aC){aD=Math.max(aD,Q[aC].points.radius+Q[aC].points.lineWidth/2)}}for(var aB in q){q[aB]+=O.grid.borderWidth;q[aB]=Math.max(aD,q[aB])}}h=G-q.left-q.right;w=I-q.bottom-q.top;c.each(aE,function(aF,aG){r(aG)});if(O.grid.show){c.each(allocatedAxes,function(aF,aG){U(aG)});k()}o()}function n(aE){var aF=aE.options,aD=+(aF.min!=null?aF.min:aE.datamin),aB=+(aF.max!=null?aF.max:aE.datamax),aH=aB-aD;if(aH==0){var aC=aB==0?1:0.01;if(aF.min==null){aD-=aC}if(aF.max==null||aF.min!=null){aB+=aC}}else{var aG=aF.autoscaleMargin;if(aG!=null){if(aF.min==null){aD-=aH*aG;if(aD<0&&aE.datamin!=null&&aE.datamin>=0){aD=0}}if(aF.max==null){aB+=aH*aG;if(aB>0&&aE.datamax!=null&&aE.datamax<=0){aB=0}}}}aE.min=aD;aE.max=aB}function S(aG){var aM=aG.options;var aH;if(typeof aM.ticks=="number"&&aM.ticks>0){aH=aM.ticks}else{aH=0.3*Math.sqrt(aG.direction=="x"?G:I)}var aT=(aG.max-aG.min)/aH,aO,aB,aN,aR,aS,aQ,aI;if(aM.mode=="time"){var aJ={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var aK=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];var aC=0;if(aM.minTickSize!=null){if(typeof aM.tickSize=="number"){aC=aM.tickSize}else{aC=aM.minTickSize[0]*aJ[aM.minTickSize[1]]}}for(var aS=0;aS<aK.length-1;++aS){if(aT<(aK[aS][0]*aJ[aK[aS][1]]+aK[aS+1][0]*aJ[aK[aS+1][1]])/2&&aK[aS][0]*aJ[aK[aS][1]]>=aC){break}}aO=aK[aS][0];aN=aK[aS][1];if(aN=="year"){aQ=Math.pow(10,Math.floor(Math.log(aT/aJ.year)/Math.LN10));aI=(aT/aJ.year)/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ}aG.tickSize=aM.tickSize||[aO,aN];aB=function(aX){var a2=[],a0=aX.tickSize[0],a3=aX.tickSize[1],a1=new Date(aX.min);var aW=a0*aJ[a3];if(a3=="second"){a1.setUTCSeconds(a(a1.getUTCSeconds(),a0))}if(a3=="minute"){a1.setUTCMinutes(a(a1.getUTCMinutes(),a0))}if(a3=="hour"){a1.setUTCHours(a(a1.getUTCHours(),a0))}if(a3=="month"){a1.setUTCMonth(a(a1.getUTCMonth(),a0))}if(a3=="year"){a1.setUTCFullYear(a(a1.getUTCFullYear(),a0))}a1.setUTCMilliseconds(0);if(aW>=aJ.minute){a1.setUTCSeconds(0)}if(aW>=aJ.hour){a1.setUTCMinutes(0)}if(aW>=aJ.day){a1.setUTCHours(0)}if(aW>=aJ.day*4){a1.setUTCDate(1)}if(aW>=aJ.year){a1.setUTCMonth(0)}var a5=0,a4=Number.NaN,aY;do{aY=a4;a4=a1.getTime();a2.push(a4);if(a3=="month"){if(a0<1){a1.setUTCDate(1);var aV=a1.getTime();a1.setUTCMonth(a1.getUTCMonth()+1);var aZ=a1.getTime();a1.setTime(a4+a5*aJ.hour+(aZ-aV)*a0);a5=a1.getUTCHours();a1.setUTCHours(0)}else{a1.setUTCMonth(a1.getUTCMonth()+a0)}}else{if(a3=="year"){a1.setUTCFullYear(a1.getUTCFullYear()+a0)}else{a1.setTime(a4+aW)}}}while(a4<aX.max&&a4!=aY);return a2};aR=function(aV,aY){var a0=new Date(aV);if(aM.timeformat!=null){return c.plot.formatDate(a0,aM.timeformat,aM.monthNames)}var aW=aY.tickSize[0]*aJ[aY.tickSize[1]];var aX=aY.max-aY.min;var aZ=(aM.twelveHourClock)?" %p":"";if(aW<aJ.minute){fmt="%h:%M:%S"+aZ}else{if(aW<aJ.day){if(aX<2*aJ.day){fmt="%h:%M"+aZ}else{fmt="%b %d %h:%M"+aZ}}else{if(aW<aJ.month){fmt="%b %d"}else{if(aW<aJ.year){if(aX<aJ.year){fmt="%b"}else{fmt="%b %y"}}else{fmt="%y"}}}}return c.plot.formatDate(a0,fmt,aM.monthNames)}}else{var aU=aM.tickDecimals;var aP=-Math.floor(Math.log(aT)/Math.LN10);if(aU!=null&&aP>aU){aP=aU}aQ=Math.pow(10,-aP);aI=aT/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2;if(aI>2.25&&(aU==null||aP+1<=aU)){aO=2.5;++aP}}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ;if(aM.minTickSize!=null&&aO<aM.minTickSize){aO=aM.minTickSize}aG.tickDecimals=Math.max(0,aU!=null?aU:aP);aG.tickSize=aM.tickSize||aO;aB=function(aX){var aZ=[];var a0=a(aX.min,aX.tickSize),aW=0,aV=Number.NaN,aY;do{aY=aV;aV=a0+aW*aX.tickSize;aZ.push(aV);++aW}while(aV<aX.max&&aV!=aY);return aZ};aR=function(aV,aW){return aV.toFixed(aW.tickDecimals)}}if(aM.alignTicksWithAxis!=null){var aF=(aG.direction=="x"?p:aw)[aM.alignTicksWithAxis-1];if(aF&&aF.used&&aF!=aG){var aL=aB(aG);if(aL.length>0){if(aM.min==null){aG.min=Math.min(aG.min,aL[0])}if(aM.max==null&&aL.length>1){aG.max=Math.max(aG.max,aL[aL.length-1])}}aB=function(aX){var aY=[],aV,aW;for(aW=0;aW<aF.ticks.length;++aW){aV=(aF.ticks[aW].v-aF.min)/(aF.max-aF.min);aV=aX.min+aV*(aX.max-aX.min);aY.push(aV)}return aY};if(aG.mode!="time"&&aM.tickDecimals==null){var aE=Math.max(0,-Math.floor(Math.log(aT)/Math.LN10)+1),aD=aB(aG);if(!(aD.length>1&&/\..*0$/.test((aD[1]-aD[0]).toFixed(aE)))){aG.tickDecimals=aE}}}}aG.tickGenerator=aB;if(c.isFunction(aM.tickFormatter)){aG.tickFormatter=function(aV,aW){return""+aM.tickFormatter(aV,aW)}}else{aG.tickFormatter=aR}}function P(aF){var aH=aF.options.ticks,aG=[];if(aH==null||(typeof aH=="number"&&aH>0)){aG=aF.tickGenerator(aF)}else{if(aH){if(c.isFunction(aH)){aG=aH({min:aF.min,max:aF.max})}else{aG=aH}}}var aE,aB;aF.ticks=[];for(aE=0;aE<aG.length;++aE){var aC=null;var aD=aG[aE];if(typeof aD=="object"){aB=+aD[0];if(aD.length>1){aC=aD[1]}}else{aB=+aD}if(aC==null){aC=aF.tickFormatter(aB,aF)}if(!isNaN(aB)){aF.ticks.push({v:aB,label:aC})}}}function ap(aB,aC){if(aB.options.autoscaleMargin&&aC.length>0){if(aB.options.min==null){aB.min=Math.min(aB.min,aC[0].v)}if(aB.options.max==null&&aC.length>1){aB.max=Math.max(aB.max,aC[aC.length-1].v)}}}function W(){H.clearRect(0,0,G,I);var aC=O.grid;if(aC.show&&aC.backgroundColor){N()}if(aC.show&&!aC.aboveData){ac()}for(var aB=0;aB<Q.length;++aB){an(ak.drawSeries,[H,Q[aB]]);d(Q[aB])}an(ak.draw,[H]);if(aC.show&&aC.aboveData){ac()}}function D(aB,aI){var aE,aH,aG,aD,aF=m();for(i=0;i<aF.length;++i){aE=aF[i];if(aE.direction==aI){aD=aI+aE.n+"axis";if(!aB[aD]&&aE.n==1){aD=aI+"axis"}if(aB[aD]){aH=aB[aD].from;aG=aB[aD].to;break}}}if(!aB[aD]){aE=aI=="x"?p[0]:aw[0];aH=aB[aI+"1"];aG=aB[aI+"2"]}if(aH!=null&&aG!=null&&aH>aG){var aC=aH;aH=aG;aG=aC}return{from:aH,to:aG,axis:aE}}function N(){H.save();H.translate(q.left,q.top);H.fillStyle=am(O.grid.backgroundColor,w,0,"rgba(255, 255, 255, 0)");H.fillRect(0,0,h,w);H.restore()}function ac(){var aF;H.save();H.translate(q.left,q.top);var aH=O.grid.markings;if(aH){if(c.isFunction(aH)){var aK=aq.getAxes();aK.xmin=aK.xaxis.min;aK.xmax=aK.xaxis.max;aK.ymin=aK.yaxis.min;aK.ymax=aK.yaxis.max;aH=aH(aK)}for(aF=0;aF<aH.length;++aF){var aD=aH[aF],aC=D(aD,"x"),aI=D(aD,"y");if(aC.from==null){aC.from=aC.axis.min}if(aC.to==null){aC.to=aC.axis.max}if(aI.from==null){aI.from=aI.axis.min}if(aI.to==null){aI.to=aI.axis.max}if(aC.to<aC.axis.min||aC.from>aC.axis.max||aI.to<aI.axis.min||aI.from>aI.axis.max){continue}aC.from=Math.max(aC.from,aC.axis.min);aC.to=Math.min(aC.to,aC.axis.max);aI.from=Math.max(aI.from,aI.axis.min);aI.to=Math.min(aI.to,aI.axis.max);if(aC.from==aC.to&&aI.from==aI.to){continue}aC.from=aC.axis.p2c(aC.from);aC.to=aC.axis.p2c(aC.to);aI.from=aI.axis.p2c(aI.from);aI.to=aI.axis.p2c(aI.to);if(aC.from==aC.to||aI.from==aI.to){H.beginPath();H.strokeStyle=aD.color||O.grid.markingsColor;H.lineWidth=aD.lineWidth||O.grid.markingsLineWidth;H.moveTo(aC.from,aI.from);H.lineTo(aC.to,aI.to);H.stroke()}else{H.fillStyle=aD.color||O.grid.markingsColor;H.fillRect(aC.from,aI.to,aC.to-aC.from,aI.from-aI.to)}}}var aK=m(),aM=O.grid.borderWidth;for(var aE=0;aE<aK.length;++aE){var aB=aK[aE],aG=aB.box,aQ=aB.tickLength,aN,aL,aP,aJ;if(!aB.show||aB.ticks.length==0){continue}H.strokeStyle=aB.options.tickColor||c.color.parse(aB.options.color).scale("a",0.22).toString();H.lineWidth=1;if(aB.direction=="x"){aN=0;if(aQ=="full"){aL=(aB.position=="top"?0:w)}else{aL=aG.top-q.top+(aB.position=="top"?aG.height:0)}}else{aL=0;if(aQ=="full"){aN=(aB.position=="left"?0:h)}else{aN=aG.left-q.left+(aB.position=="left"?aG.width:0)}}if(!aB.innermost){H.beginPath();aP=aJ=0;if(aB.direction=="x"){aP=h}else{aJ=w}if(H.lineWidth==1){aN=Math.floor(aN)+0.5;aL=Math.floor(aL)+0.5}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ);H.stroke()}H.beginPath();for(aF=0;aF<aB.ticks.length;++aF){var aO=aB.ticks[aF].v;aP=aJ=0;if(aO<aB.min||aO>aB.max||(aQ=="full"&&aM>0&&(aO==aB.min||aO==aB.max))){continue}if(aB.direction=="x"){aN=aB.p2c(aO);aJ=aQ=="full"?-w:aQ;if(aB.position=="top"){aJ=-aJ}}else{aL=aB.p2c(aO);aP=aQ=="full"?-h:aQ;if(aB.position=="left"){aP=-aP}}if(H.lineWidth==1){if(aB.direction=="x"){aN=Math.floor(aN)+0.5}else{aL=Math.floor(aL)+0.5}}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ)}H.stroke()}if(aM){H.lineWidth=aM;H.strokeStyle=O.grid.borderColor;H.strokeRect(-aM/2,-aM/2,h+aM,w+aM)}H.restore()}function k(){av.find(".tickLabels").remove();var aG=['<div class="tickLabels" style="font-size:smaller">'];var aJ=m();for(var aD=0;aD<aJ.length;++aD){var aC=aJ[aD],aF=aC.box;if(!aC.show){continue}aG.push('<div class="'+aC.direction+"Axis "+aC.direction+aC.n+'Axis" style="color:'+aC.options.color+'">');for(var aE=0;aE<aC.ticks.length;++aE){var aH=aC.ticks[aE];if(!aH.label||aH.v<aC.min||aH.v>aC.max){continue}var aK={},aI;if(aC.direction=="x"){aI="center";aK.left=Math.round(q.left+aC.p2c(aH.v)-aC.labelWidth/2);if(aC.position=="bottom"){aK.top=aF.top+aF.padding}else{aK.bottom=I-(aF.top+aF.height-aF.padding)}}else{aK.top=Math.round(q.top+aC.p2c(aH.v)-aC.labelHeight/2);if(aC.position=="left"){aK.right=G-(aF.left+aF.width-aF.padding);aI="right"}else{aK.left=aF.left+aF.padding;aI="left"}}aK.width=aC.labelWidth;var aB=["position:absolute","text-align:"+aI];for(var aL in aK){aB.push(aL+":"+aK[aL]+"px")}aG.push('<div class="tickLabel" style="'+aB.join(";")+'">'+aH.label+"</div>")}aG.push("</div>")}aG.push("</div>");av.append(aG.join(""))}function d(aB){if(aB.lines.show){at(aB)}if(aB.bars.show){e(aB)}if(aB.points.show){ao(aB)}}function at(aE){function aD(aP,aQ,aI,aU,aT){var aV=aP.points,aJ=aP.pointsize,aN=null,aM=null;H.beginPath();for(var aO=aJ;aO<aV.length;aO+=aJ){var aL=aV[aO-aJ],aS=aV[aO-aJ+1],aK=aV[aO],aR=aV[aO+1];if(aL==null||aK==null){continue}if(aS<=aR&&aS<aT.min){if(aR<aT.min){continue}aL=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.min}else{if(aR<=aS&&aR<aT.min){if(aS<aT.min){continue}aK=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.min}}if(aS>=aR&&aS>aT.max){if(aR>aT.max){continue}aL=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.max}else{if(aR>=aS&&aR>aT.max){if(aS>aT.max){continue}aK=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.max}}if(aL<=aK&&aL<aU.min){if(aK<aU.min){continue}aS=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.min}else{if(aK<=aL&&aK<aU.min){if(aL<aU.min){continue}aR=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.min}}if(aL>=aK&&aL>aU.max){if(aK>aU.max){continue}aS=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.max}else{if(aK>=aL&&aK>aU.max){if(aL>aU.max){continue}aR=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.max}}if(aL!=aN||aS!=aM){H.moveTo(aU.p2c(aL)+aQ,aT.p2c(aS)+aI)}aN=aK;aM=aR;H.lineTo(aU.p2c(aK)+aQ,aT.p2c(aR)+aI)}H.stroke()}function aF(aI,aQ,aP){var aW=aI.points,aV=aI.pointsize,aN=Math.min(Math.max(0,aP.min),aP.max),aX=0,aU,aT=false,aM=1,aL=0,aR=0;while(true){if(aV>0&&aX>aW.length+aV){break}aX+=aV;var aZ=aW[aX-aV],aK=aW[aX-aV+aM],aY=aW[aX],aJ=aW[aX+aM];if(aT){if(aV>0&&aZ!=null&&aY==null){aR=aX;aV=-aV;aM=2;continue}if(aV<0&&aX==aL+aV){H.fill();aT=false;aV=-aV;aM=1;aX=aL=aR+aV;continue}}if(aZ==null||aY==null){continue}if(aZ<=aY&&aZ<aQ.min){if(aY<aQ.min){continue}aK=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.min}else{if(aY<=aZ&&aY<aQ.min){if(aZ<aQ.min){continue}aJ=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.min}}if(aZ>=aY&&aZ>aQ.max){if(aY>aQ.max){continue}aK=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.max}else{if(aY>=aZ&&aY>aQ.max){if(aZ>aQ.max){continue}aJ=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.max}}if(!aT){H.beginPath();H.moveTo(aQ.p2c(aZ),aP.p2c(aN));aT=true}if(aK>=aP.max&&aJ>=aP.max){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.max));H.lineTo(aQ.p2c(aY),aP.p2c(aP.max));continue}else{if(aK<=aP.min&&aJ<=aP.min){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.min));H.lineTo(aQ.p2c(aY),aP.p2c(aP.min));continue}}var aO=aZ,aS=aY;if(aK<=aJ&&aK<aP.min&&aJ>=aP.min){aZ=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.min}else{if(aJ<=aK&&aJ<aP.min&&aK>=aP.min){aY=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.min}}if(aK>=aJ&&aK>aP.max&&aJ<=aP.max){aZ=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.max}else{if(aJ>=aK&&aJ>aP.max&&aK<=aP.max){aY=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.max}}if(aZ!=aO){H.lineTo(aQ.p2c(aO),aP.p2c(aK))}H.lineTo(aQ.p2c(aZ),aP.p2c(aK));H.lineTo(aQ.p2c(aY),aP.p2c(aJ));if(aY!=aS){H.lineTo(aQ.p2c(aY),aP.p2c(aJ));H.lineTo(aQ.p2c(aS),aP.p2c(aJ))}}}H.save();H.translate(q.left,q.top);H.lineJoin="round";var aG=aE.lines.lineWidth,aB=aE.shadowSize;if(aG>0&&aB>0){H.lineWidth=aB;H.strokeStyle="rgba(0,0,0,0.1)";var aH=Math.PI/18;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/2),Math.cos(aH)*(aG/2+aB/2),aE.xaxis,aE.yaxis);H.lineWidth=aB/2;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/4),Math.cos(aH)*(aG/2+aB/4),aE.xaxis,aE.yaxis)}H.lineWidth=aG;H.strokeStyle=aE.color;var aC=ae(aE.lines,aE.color,0,w);if(aC){H.fillStyle=aC;aF(aE.datapoints,aE.xaxis,aE.yaxis)}if(aG>0){aD(aE.datapoints,0,0,aE.xaxis,aE.yaxis)}H.restore()}function ao(aE){function aH(aN,aM,aU,aK,aS,aT,aQ,aJ){var aR=aN.points,aI=aN.pointsize;for(var aL=0;aL<aR.length;aL+=aI){var aP=aR[aL],aO=aR[aL+1];if(aP==null||aP<aT.min||aP>aT.max||aO<aQ.min||aO>aQ.max){continue}H.beginPath();aP=aT.p2c(aP);aO=aQ.p2c(aO)+aK;if(aJ=="circle"){H.arc(aP,aO,aM,0,aS?Math.PI:Math.PI*2,false)}else{aJ(H,aP,aO,aM,aS)}H.closePath();if(aU){H.fillStyle=aU;H.fill()}H.stroke()}}H.save();H.translate(q.left,q.top);var aG=aE.points.lineWidth,aC=aE.shadowSize,aB=aE.points.radius,aF=aE.points.symbol;if(aG>0&&aC>0){var aD=aC/2;H.lineWidth=aD;H.strokeStyle="rgba(0,0,0,0.1)";aH(aE.datapoints,aB,null,aD+aD/2,true,aE.xaxis,aE.yaxis,aF);H.strokeStyle="rgba(0,0,0,0.2)";aH(aE.datapoints,aB,null,aD/2,true,aE.xaxis,aE.yaxis,aF)}H.lineWidth=aG;H.strokeStyle=aE.color;aH(aE.datapoints,aB,ae(aE.points,aE.color),0,false,aE.xaxis,aE.yaxis,aF);H.restore()}function E(aN,aM,aV,aI,aQ,aF,aD,aL,aK,aU,aR,aC){var aE,aT,aJ,aP,aG,aB,aO,aH,aS;if(aR){aH=aB=aO=true;aG=false;aE=aV;aT=aN;aP=aM+aI;aJ=aM+aQ;if(aT<aE){aS=aT;aT=aE;aE=aS;aG=true;aB=false}}else{aG=aB=aO=true;aH=false;aE=aN+aI;aT=aN+aQ;aJ=aV;aP=aM;if(aP<aJ){aS=aP;aP=aJ;aJ=aS;aH=true;aO=false}}if(aT<aL.min||aE>aL.max||aP<aK.min||aJ>aK.max){return}if(aE<aL.min){aE=aL.min;aG=false}if(aT>aL.max){aT=aL.max;aB=false}if(aJ<aK.min){aJ=aK.min;aH=false}if(aP>aK.max){aP=aK.max;aO=false}aE=aL.p2c(aE);aJ=aK.p2c(aJ);aT=aL.p2c(aT);aP=aK.p2c(aP);if(aD){aU.beginPath();aU.moveTo(aE,aJ);aU.lineTo(aE,aP);aU.lineTo(aT,aP);aU.lineTo(aT,aJ);aU.fillStyle=aD(aJ,aP);aU.fill()}if(aC>0&&(aG||aB||aO||aH)){aU.beginPath();aU.moveTo(aE,aJ+aF);if(aG){aU.lineTo(aE,aP+aF)}else{aU.moveTo(aE,aP+aF)}if(aO){aU.lineTo(aT,aP+aF)}else{aU.moveTo(aT,aP+aF)}if(aB){aU.lineTo(aT,aJ+aF)}else{aU.moveTo(aT,aJ+aF)}if(aH){aU.lineTo(aE,aJ+aF)}else{aU.moveTo(aE,aJ+aF)}aU.stroke()}}function e(aD){function aC(aJ,aI,aL,aG,aK,aN,aM){var aO=aJ.points,aF=aJ.pointsize;for(var aH=0;aH<aO.length;aH+=aF){if(aO[aH]==null){continue}E(aO[aH],aO[aH+1],aO[aH+2],aI,aL,aG,aK,aN,aM,H,aD.bars.horizontal,aD.bars.lineWidth)}}H.save();H.translate(q.left,q.top);H.lineWidth=aD.bars.lineWidth;H.strokeStyle=aD.color;var aB=aD.bars.align=="left"?0:-aD.bars.barWidth/2;var aE=aD.bars.fill?function(aF,aG){return ae(aD.bars,aD.color,aF,aG)}:null;aC(aD.datapoints,aB,aB+aD.bars.barWidth,0,aE,aD.xaxis,aD.yaxis);H.restore()}function ae(aD,aB,aC,aF){var aE=aD.fill;if(!aE){return null}if(aD.fillColor){return am(aD.fillColor,aC,aF,aB)}var aG=c.color.parse(aB);aG.a=typeof aE=="number"?aE:0.4;aG.normalize();return aG.toString()}function o(){av.find(".legend").remove();if(!O.legend.show){return}var aH=[],aF=false,aN=O.legend.labelFormatter,aM,aJ;for(var aE=0;aE<Q.length;++aE){aM=Q[aE];aJ=aM.label;if(!aJ){continue}if(aE%O.legend.noColumns==0){if(aF){aH.push("</tr>")}aH.push("<tr>");aF=true}if(aN){aJ=aN(aJ,aM)}aH.push('<td class="legendColorBox"><div style="border:1px solid '+O.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+aM.color+';overflow:hidden"></div></div></td><td class="legendLabel">'+aJ+"</td>")}if(aF){aH.push("</tr>")}if(aH.length==0){return}var aL='<table style="font-size:smaller;color:'+O.grid.color+'">'+aH.join("")+"</table>";if(O.legend.container!=null){c(O.legend.container).html(aL)}else{var aI="",aC=O.legend.position,aD=O.legend.margin;if(aD[0]==null){aD=[aD,aD]}if(aC.charAt(0)=="n"){aI+="top:"+(aD[1]+q.top)+"px;"}else{if(aC.charAt(0)=="s"){aI+="bottom:"+(aD[1]+q.bottom)+"px;"}}if(aC.charAt(1)=="e"){aI+="right:"+(aD[0]+q.right)+"px;"}else{if(aC.charAt(1)=="w"){aI+="left:"+(aD[0]+q.left)+"px;"}}var aK=c('<div class="legend">'+aL.replace('style="','style="position:absolute;'+aI+";")+"</div>").appendTo(av);if(O.legend.backgroundOpacity!=0){var aG=O.legend.backgroundColor;if(aG==null){aG=O.grid.backgroundColor;if(aG&&typeof aG=="string"){aG=c.color.parse(aG)}else{aG=c.color.extract(aK,"background-color")}aG.a=1;aG=aG.toString()}var aB=aK.children();c('<div style="position:absolute;width:'+aB.width()+"px;height:"+aB.height()+"px;"+aI+"background-color:"+aG+';"> </div>').prependTo(aK).css("opacity",O.legend.backgroundOpacity)}}}var ab=[],M=null;function K(aI,aG,aD){var aO=O.grid.mouseActiveRadius,a0=aO*aO+1,aY=null,aR=false,aW,aU;for(aW=Q.length-1;aW>=0;--aW){if(!aD(Q[aW])){continue}var aP=Q[aW],aH=aP.xaxis,aF=aP.yaxis,aV=aP.datapoints.points,aT=aP.datapoints.pointsize,aQ=aH.c2p(aI),aN=aF.c2p(aG),aC=aO/aH.scale,aB=aO/aF.scale;if(aH.options.inverseTransform){aC=Number.MAX_VALUE}if(aF.options.inverseTransform){aB=Number.MAX_VALUE}if(aP.lines.show||aP.points.show){for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1];if(aK==null){continue}if(aK-aQ>aC||aK-aQ<-aC||aJ-aN>aB||aJ-aN<-aB){continue}var aM=Math.abs(aH.p2c(aK)-aI),aL=Math.abs(aF.p2c(aJ)-aG),aS=aM*aM+aL*aL;if(aS<a0){a0=aS;aY=[aW,aU/aT]}}}if(aP.bars.show&&!aY){var aE=aP.bars.align=="left"?0:-aP.bars.barWidth/2,aX=aE+aP.bars.barWidth;for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1],aZ=aV[aU+2];if(aK==null){continue}if(Q[aW].bars.horizontal?(aQ<=Math.max(aZ,aK)&&aQ>=Math.min(aZ,aK)&&aN>=aJ+aE&&aN<=aJ+aX):(aQ>=aK+aE&&aQ<=aK+aX&&aN>=Math.min(aZ,aJ)&&aN<=Math.max(aZ,aJ))){aY=[aW,aU/aT]}}}}if(aY){aW=aY[0];aU=aY[1];aT=Q[aW].datapoints.pointsize;return{datapoint:Q[aW].datapoints.points.slice(aU*aT,(aU+1)*aT),dataIndex:aU,series:Q[aW],seriesIndex:aW}}return null}function aa(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return aC.hoverable!=false})}}function l(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return false})}}function R(aB){u("plotclick",aB,function(aC){return aC.clickable!=false})}function u(aC,aB,aD){var aE=y.offset(),aH=aB.pageX-aE.left-q.left,aF=aB.pageY-aE.top-q.top,aJ=C({left:aH,top:aF});aJ.pageX=aB.pageX;aJ.pageY=aB.pageY;var aK=K(aH,aF,aD);if(aK){aK.pageX=parseInt(aK.series.xaxis.p2c(aK.datapoint[0])+aE.left+q.left);aK.pageY=parseInt(aK.series.yaxis.p2c(aK.datapoint[1])+aE.top+q.top)}if(O.grid.autoHighlight){for(var aG=0;aG<ab.length;++aG){var aI=ab[aG];if(aI.auto==aC&&!(aK&&aI.series==aK.series&&aI.point[0]==aK.datapoint[0]&&aI.point[1]==aK.datapoint[1])){T(aI.series,aI.point)}}if(aK){x(aK.series,aK.datapoint,aC)}}av.trigger(aC,[aJ,aK])}function f(){if(!M){M=setTimeout(s,30)}}function s(){M=null;A.save();A.clearRect(0,0,G,I);A.translate(q.left,q.top);var aC,aB;for(aC=0;aC<ab.length;++aC){aB=ab[aC];if(aB.series.bars.show){v(aB.series,aB.point)}else{ay(aB.series,aB.point)}}A.restore();an(ak.drawOverlay,[A])}function x(aD,aB,aF){if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){var aE=aD.datapoints.pointsize;aB=aD.datapoints.points.slice(aE*aB,aE*(aB+1))}var aC=al(aD,aB);if(aC==-1){ab.push({series:aD,point:aB,auto:aF});f()}else{if(!aF){ab[aC].auto=false}}}function T(aD,aB){if(aD==null&&aB==null){ab=[];f()}if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){aB=aD.data[aB]}var aC=al(aD,aB);if(aC!=-1){ab.splice(aC,1);f()}}function al(aD,aE){for(var aB=0;aB<ab.length;++aB){var aC=ab[aB];if(aC.series==aD&&aC.point[0]==aE[0]&&aC.point[1]==aE[1]){return aB}}return -1}function ay(aE,aD){var aC=aD[0],aI=aD[1],aH=aE.xaxis,aG=aE.yaxis;if(aC<aH.min||aC>aH.max||aI<aG.min||aI>aG.max){return}var aF=aE.points.radius+aE.points.lineWidth/2;A.lineWidth=aF;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aB=1.5*aF,aC=aH.p2c(aC),aI=aG.p2c(aI);A.beginPath();if(aE.points.symbol=="circle"){A.arc(aC,aI,aB,0,2*Math.PI,false)}else{aE.points.symbol(A,aC,aI,aB,false)}A.closePath();A.stroke()}function v(aE,aB){A.lineWidth=aE.bars.lineWidth;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aD=c.color.parse(aE.color).scale("a",0.5).toString();var aC=aE.bars.align=="left"?0:-aE.bars.barWidth/2;E(aB[0],aB[1],aB[2]||0,aC,aC+aE.bars.barWidth,0,function(){return aD},aE.xaxis,aE.yaxis,A,aE.bars.horizontal,aE.bars.lineWidth)}function am(aJ,aB,aH,aC){if(typeof aJ=="string"){return aJ}else{var aI=H.createLinearGradient(0,aH,0,aB);for(var aE=0,aD=aJ.colors.length;aE<aD;++aE){var aF=aJ.colors[aE];if(typeof aF!="string"){var aG=c.color.parse(aC);if(aF.brightness!=null){aG=aG.scale("rgb",aF.brightness)}if(aF.opacity!=null){aG.a*=aF.opacity}aF=aG.toString()}aI.addColorStop(aE/(aD-1),aF)}return aI}}}c.plot=function(g,e,d){var f=new b(c(g),e,d,c.plot.plugins);return f};c.plot.version="0.7";c.plot.plugins=[];c.plot.formatDate=function(l,f,h){var o=function(d){d=""+d;return d.length==1?"0"+d:d};var e=[];var p=false,j=false;var n=l.getUTCHours();var k=n<12;if(h==null){h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(f.search(/%p|%P/)!=-1){if(n>12){n=n-12}else{if(n==0){n=12}}}for(var g=0;g<f.length;++g){var m=f.charAt(g);if(p){switch(m){case"h":m=""+n;break;case"H":m=o(n);break;case"M":m=o(l.getUTCMinutes());break;case"S":m=o(l.getUTCSeconds());break;case"d":m=""+l.getUTCDate();break;case"m":m=""+(l.getUTCMonth()+1);break;case"y":m=""+l.getUTCFullYear();break;case"b":m=""+h[l.getUTCMonth()];break;case"p":m=(k)?("am"):("pm");break;case"P":m=(k)?("AM"):("PM");break;case"0":m="";j=true;break}if(m&&j){m=o(m);j=false}e.push(m);if(!j){p=false}}else{if(m=="%"){p=true}else{e.push(m)}}}return e.join("")};function a(e,d){return d*Math.floor(e/d)}})(jQuery);
|
@@ -0,0 +1,336 @@
|
|
1
|
+
/*
|
2
|
+
Flot plugin for adding panning and zooming capabilities to a plot.
|
3
|
+
|
4
|
+
The default behaviour is double click and scrollwheel up/down to zoom
|
5
|
+
in, drag to pan. The plugin defines plot.zoom({ center }),
|
6
|
+
plot.zoomOut() and plot.pan(offset) so you easily can add custom
|
7
|
+
controls. It also fires a "plotpan" and "plotzoom" event when
|
8
|
+
something happens, useful for synchronizing plots.
|
9
|
+
|
10
|
+
Options:
|
11
|
+
|
12
|
+
zoom: {
|
13
|
+
interactive: false
|
14
|
+
trigger: "dblclick" // or "click" for single click
|
15
|
+
amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
16
|
+
}
|
17
|
+
|
18
|
+
pan: {
|
19
|
+
interactive: false
|
20
|
+
cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer"
|
21
|
+
frameRate: 20
|
22
|
+
}
|
23
|
+
|
24
|
+
xaxis, yaxis, x2axis, y2axis: {
|
25
|
+
zoomRange: null // or [number, number] (min range, max range) or false
|
26
|
+
panRange: null // or [number, number] (min, max) or false
|
27
|
+
}
|
28
|
+
|
29
|
+
"interactive" enables the built-in drag/click behaviour. If you enable
|
30
|
+
interactive for pan, then you'll have a basic plot that supports
|
31
|
+
moving around; the same for zoom.
|
32
|
+
|
33
|
+
"amount" specifies the default amount to zoom in (so 1.5 = 150%)
|
34
|
+
relative to the current viewport.
|
35
|
+
|
36
|
+
"cursor" is a standard CSS mouse cursor string used for visual
|
37
|
+
feedback to the user when dragging.
|
38
|
+
|
39
|
+
"frameRate" specifies the maximum number of times per second the plot
|
40
|
+
will update itself while the user is panning around on it (set to null
|
41
|
+
to disable intermediate pans, the plot will then not update until the
|
42
|
+
mouse button is released).
|
43
|
+
|
44
|
+
"zoomRange" is the interval in which zooming can happen, e.g. with
|
45
|
+
zoomRange: [1, 100] the zoom will never scale the axis so that the
|
46
|
+
difference between min and max is smaller than 1 or larger than 100.
|
47
|
+
You can set either end to null to ignore, e.g. [1, null]. If you set
|
48
|
+
zoomRange to false, zooming on that axis will be disabled.
|
49
|
+
|
50
|
+
"panRange" confines the panning to stay within a range, e.g. with
|
51
|
+
panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
|
52
|
+
other. Either can be null, e.g. [-10, null]. If you set
|
53
|
+
panRange to false, panning on that axis will be disabled.
|
54
|
+
|
55
|
+
Example API usage:
|
56
|
+
|
57
|
+
plot = $.plot(...);
|
58
|
+
|
59
|
+
// zoom default amount in on the pixel (10, 20)
|
60
|
+
plot.zoom({ center: { left: 10, top: 20 } });
|
61
|
+
|
62
|
+
// zoom out again
|
63
|
+
plot.zoomOut({ center: { left: 10, top: 20 } });
|
64
|
+
|
65
|
+
// zoom 200% in on the pixel (10, 20)
|
66
|
+
plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
|
67
|
+
|
68
|
+
// pan 100 pixels to the left and 20 down
|
69
|
+
plot.pan({ left: -100, top: 20 })
|
70
|
+
|
71
|
+
Here, "center" specifies where the center of the zooming should
|
72
|
+
happen. Note that this is defined in pixel space, not the space of the
|
73
|
+
data points (you can use the p2c helpers on the axes in Flot to help
|
74
|
+
you convert between these).
|
75
|
+
|
76
|
+
"amount" is the amount to zoom the viewport relative to the current
|
77
|
+
range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is
|
78
|
+
70% (zoom out). You can set the default in the options.
|
79
|
+
|
80
|
+
*/
|
81
|
+
|
82
|
+
|
83
|
+
// First two dependencies, jquery.event.drag.js and
|
84
|
+
// jquery.mousewheel.js, we put them inline here to save people the
|
85
|
+
// effort of downloading them.
|
86
|
+
|
87
|
+
/*
|
88
|
+
jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
|
89
|
+
Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
|
90
|
+
*/
|
91
|
+
(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);
|
92
|
+
|
93
|
+
|
94
|
+
/* jquery.mousewheel.min.js
|
95
|
+
* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
|
96
|
+
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
97
|
+
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
98
|
+
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
|
99
|
+
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
|
100
|
+
*
|
101
|
+
* Version: 3.0.2
|
102
|
+
*
|
103
|
+
* Requires: 1.2.2+
|
104
|
+
*/
|
105
|
+
(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
(function ($) {
|
111
|
+
var options = {
|
112
|
+
xaxis: {
|
113
|
+
zoomRange: null, // or [number, number] (min range, max range)
|
114
|
+
panRange: null // or [number, number] (min, max)
|
115
|
+
},
|
116
|
+
zoom: {
|
117
|
+
interactive: false,
|
118
|
+
trigger: "dblclick", // or "click" for single click
|
119
|
+
amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
|
120
|
+
},
|
121
|
+
pan: {
|
122
|
+
interactive: false,
|
123
|
+
cursor: "move",
|
124
|
+
frameRate: 20
|
125
|
+
}
|
126
|
+
};
|
127
|
+
|
128
|
+
function init(plot) {
|
129
|
+
function onZoomClick(e, zoomOut) {
|
130
|
+
var c = plot.offset();
|
131
|
+
c.left = e.pageX - c.left;
|
132
|
+
c.top = e.pageY - c.top;
|
133
|
+
if (zoomOut)
|
134
|
+
plot.zoomOut({ center: c });
|
135
|
+
else
|
136
|
+
plot.zoom({ center: c });
|
137
|
+
}
|
138
|
+
|
139
|
+
function onMouseWheel(e, delta) {
|
140
|
+
onZoomClick(e, delta < 0);
|
141
|
+
return false;
|
142
|
+
}
|
143
|
+
|
144
|
+
var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
|
145
|
+
panTimeout = null;
|
146
|
+
|
147
|
+
function onDragStart(e) {
|
148
|
+
if (e.which != 1) // only accept left-click
|
149
|
+
return false;
|
150
|
+
var c = plot.getPlaceholder().css('cursor');
|
151
|
+
if (c)
|
152
|
+
prevCursor = c;
|
153
|
+
plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
|
154
|
+
prevPageX = e.pageX;
|
155
|
+
prevPageY = e.pageY;
|
156
|
+
}
|
157
|
+
|
158
|
+
function onDrag(e) {
|
159
|
+
var frameRate = plot.getOptions().pan.frameRate;
|
160
|
+
if (panTimeout || !frameRate)
|
161
|
+
return;
|
162
|
+
|
163
|
+
panTimeout = setTimeout(function () {
|
164
|
+
plot.pan({ left: prevPageX - e.pageX,
|
165
|
+
top: prevPageY - e.pageY });
|
166
|
+
prevPageX = e.pageX;
|
167
|
+
prevPageY = e.pageY;
|
168
|
+
|
169
|
+
panTimeout = null;
|
170
|
+
}, 1 / frameRate * 1000);
|
171
|
+
}
|
172
|
+
|
173
|
+
function onDragEnd(e) {
|
174
|
+
if (panTimeout) {
|
175
|
+
clearTimeout(panTimeout);
|
176
|
+
panTimeout = null;
|
177
|
+
}
|
178
|
+
|
179
|
+
plot.getPlaceholder().css('cursor', prevCursor);
|
180
|
+
plot.pan({ left: prevPageX - e.pageX,
|
181
|
+
top: prevPageY - e.pageY });
|
182
|
+
}
|
183
|
+
|
184
|
+
function bindEvents(plot, eventHolder) {
|
185
|
+
var o = plot.getOptions();
|
186
|
+
if (o.zoom.interactive) {
|
187
|
+
eventHolder[o.zoom.trigger](onZoomClick);
|
188
|
+
eventHolder.mousewheel(onMouseWheel);
|
189
|
+
}
|
190
|
+
|
191
|
+
if (o.pan.interactive) {
|
192
|
+
eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
|
193
|
+
eventHolder.bind("drag", onDrag);
|
194
|
+
eventHolder.bind("dragend", onDragEnd);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
plot.zoomOut = function (args) {
|
199
|
+
if (!args)
|
200
|
+
args = {};
|
201
|
+
|
202
|
+
if (!args.amount)
|
203
|
+
args.amount = plot.getOptions().zoom.amount
|
204
|
+
|
205
|
+
args.amount = 1 / args.amount;
|
206
|
+
plot.zoom(args);
|
207
|
+
}
|
208
|
+
|
209
|
+
plot.zoom = function (args) {
|
210
|
+
if (!args)
|
211
|
+
args = {};
|
212
|
+
|
213
|
+
var c = args.center,
|
214
|
+
amount = args.amount || plot.getOptions().zoom.amount,
|
215
|
+
w = plot.width(), h = plot.height();
|
216
|
+
|
217
|
+
if (!c)
|
218
|
+
c = { left: w / 2, top: h / 2 };
|
219
|
+
|
220
|
+
var xf = c.left / w,
|
221
|
+
yf = c.top / h,
|
222
|
+
minmax = {
|
223
|
+
x: {
|
224
|
+
min: c.left - xf * w / amount,
|
225
|
+
max: c.left + (1 - xf) * w / amount
|
226
|
+
},
|
227
|
+
y: {
|
228
|
+
min: c.top - yf * h / amount,
|
229
|
+
max: c.top + (1 - yf) * h / amount
|
230
|
+
}
|
231
|
+
};
|
232
|
+
|
233
|
+
$.each(plot.getAxes(), function(_, axis) {
|
234
|
+
var opts = axis.options,
|
235
|
+
min = minmax[axis.direction].min,
|
236
|
+
max = minmax[axis.direction].max,
|
237
|
+
zr = opts.zoomRange;
|
238
|
+
|
239
|
+
if (zr === false) // no zooming on this axis
|
240
|
+
return;
|
241
|
+
|
242
|
+
min = axis.c2p(min);
|
243
|
+
max = axis.c2p(max);
|
244
|
+
if (min > max) {
|
245
|
+
// make sure min < max
|
246
|
+
var tmp = min;
|
247
|
+
min = max;
|
248
|
+
max = tmp;
|
249
|
+
}
|
250
|
+
|
251
|
+
var range = max - min;
|
252
|
+
if (zr &&
|
253
|
+
((zr[0] != null && range < zr[0]) ||
|
254
|
+
(zr[1] != null && range > zr[1])))
|
255
|
+
return;
|
256
|
+
|
257
|
+
opts.min = min;
|
258
|
+
opts.max = max;
|
259
|
+
});
|
260
|
+
|
261
|
+
plot.setupGrid();
|
262
|
+
plot.draw();
|
263
|
+
|
264
|
+
if (!args.preventEvent)
|
265
|
+
plot.getPlaceholder().trigger("plotzoom", [ plot ]);
|
266
|
+
}
|
267
|
+
|
268
|
+
plot.pan = function (args) {
|
269
|
+
var delta = {
|
270
|
+
x: +args.left,
|
271
|
+
y: +args.top
|
272
|
+
};
|
273
|
+
|
274
|
+
if (isNaN(delta.x))
|
275
|
+
delta.x = 0;
|
276
|
+
if (isNaN(delta.y))
|
277
|
+
delta.y = 0;
|
278
|
+
|
279
|
+
$.each(plot.getAxes(), function (_, axis) {
|
280
|
+
var opts = axis.options,
|
281
|
+
min, max, d = delta[axis.direction];
|
282
|
+
|
283
|
+
min = axis.c2p(axis.p2c(axis.min) + d),
|
284
|
+
max = axis.c2p(axis.p2c(axis.max) + d);
|
285
|
+
|
286
|
+
var pr = opts.panRange;
|
287
|
+
if (pr === false) // no panning on this axis
|
288
|
+
return;
|
289
|
+
|
290
|
+
if (pr) {
|
291
|
+
// check whether we hit the wall
|
292
|
+
if (pr[0] != null && pr[0] > min) {
|
293
|
+
d = pr[0] - min;
|
294
|
+
min += d;
|
295
|
+
max += d;
|
296
|
+
}
|
297
|
+
|
298
|
+
if (pr[1] != null && pr[1] < max) {
|
299
|
+
d = pr[1] - max;
|
300
|
+
min += d;
|
301
|
+
max += d;
|
302
|
+
}
|
303
|
+
}
|
304
|
+
|
305
|
+
opts.min = min;
|
306
|
+
opts.max = max;
|
307
|
+
});
|
308
|
+
|
309
|
+
plot.setupGrid();
|
310
|
+
plot.draw();
|
311
|
+
|
312
|
+
if (!args.preventEvent)
|
313
|
+
plot.getPlaceholder().trigger("plotpan", [ plot ]);
|
314
|
+
}
|
315
|
+
|
316
|
+
function shutdown(plot, eventHolder) {
|
317
|
+
eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
|
318
|
+
eventHolder.unbind("mousewheel", onMouseWheel);
|
319
|
+
eventHolder.unbind("dragstart", onDragStart);
|
320
|
+
eventHolder.unbind("drag", onDrag);
|
321
|
+
eventHolder.unbind("dragend", onDragEnd);
|
322
|
+
if (panTimeout)
|
323
|
+
clearTimeout(panTimeout);
|
324
|
+
}
|
325
|
+
|
326
|
+
plot.hooks.bindEvents.push(bindEvents);
|
327
|
+
plot.hooks.shutdown.push(shutdown);
|
328
|
+
}
|
329
|
+
|
330
|
+
$.plot.plugins.push({
|
331
|
+
init: init,
|
332
|
+
options: options,
|
333
|
+
name: 'navigate',
|
334
|
+
version: '1.3'
|
335
|
+
});
|
336
|
+
})(jQuery);
|
@@ -0,0 +1 @@
|
|
1
|
+
(function(i){i.fn.drag=function(j,k,l){if(k){this.bind("dragstart",j)}if(l){this.bind("dragend",l)}return !j?this.trigger("drag"):this.bind("drag",k?k:j)};var d=i.event,c=d.special,h=c.drag={not:":input",distance:0,which:1,dragging:false,setup:function(j){j=i.extend({distance:h.distance,which:h.which,not:h.not},j||{});j.distance=e(j.distance);d.add(this,"mousedown",f,j);if(this.attachEvent){this.attachEvent("ondragstart",a)}},teardown:function(){d.remove(this,"mousedown",f);if(this===h.dragging){h.dragging=h.proxy=false}g(this,true);if(this.detachEvent){this.detachEvent("ondragstart",a)}}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}};function f(j){var k=this,l,m=j.data||{};if(m.elem){k=j.dragTarget=m.elem;j.dragProxy=h.proxy||k;j.cursorOffsetX=m.pageX-m.left;j.cursorOffsetY=m.pageY-m.top;j.offsetX=j.pageX-j.cursorOffsetX;j.offsetY=j.pageY-j.cursorOffsetY}else{if(h.dragging||(m.which>0&&j.which!=m.which)||i(j.target).is(m.not)){return}}switch(j.type){case"mousedown":i.extend(m,i(k).offset(),{elem:k,target:j.target,pageX:j.pageX,pageY:j.pageY});d.add(document,"mousemove mouseup",f,m);g(k,false);h.dragging=null;return false;case !h.dragging&&"mousemove":if(e(j.pageX-m.pageX)+e(j.pageY-m.pageY)<m.distance){break}j.target=m.target;l=b(j,"dragstart",k);if(l!==false){h.dragging=k;h.proxy=j.dragProxy=i(l||k)[0]}case"mousemove":if(h.dragging){l=b(j,"drag",k);if(c.drop){c.drop.allowed=(l!==false);c.drop.handler(j)}if(l!==false){break}j.type="mouseup"}case"mouseup":d.remove(document,"mousemove mouseup",f);if(h.dragging){if(c.drop){c.drop.handler(j)}b(j,"dragend",k)}g(k,true);h.dragging=h.proxy=m.elem=false;break}return true}function b(m,k,j){m.type=k;var l=i.event.handle.call(j,m);return l===false?false:l||m.result}function e(j){return Math.pow(j,2)}function a(){return(h.dragging===false)}function g(j,k){if(!j){return}j.unselectable=k?"off":"on";j.onselectstart=function(){return k};if(j.style){j.style.MozUserSelect=k?"":"none"}}})(jQuery);(function(f){var e=["DOMMouseScroll","mousewheel"];f.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var a=e.length;a;){this.addEventListener(e[--a],d,false)}}else{this.onmousewheel=d}},teardown:function(){if(this.removeEventListener){for(var a=e.length;a;){this.removeEventListener(e[--a],d,false)}}else{this.onmousewheel=null}}};f.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}});function d(b){var h=[].slice.call(arguments,1),a=0,c=true;b=f.event.fix(b||window.event);b.type="mousewheel";if(b.wheelDelta){a=b.wheelDelta/120}if(b.detail){a=-b.detail/3}h.unshift(b,a);return f.event.handle.apply(this,h)}})(jQuery);(function(b){var a={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function c(o){function m(q,p){var r=o.offset();r.left=q.pageX-r.left;r.top=q.pageY-r.top;if(p){o.zoomOut({center:r})}else{o.zoom({center:r})}}function d(p,q){m(p,q<0);return false}var i="default",g=0,e=0,n=null;function f(p){if(p.which!=1){return false}var q=o.getPlaceholder().css("cursor");if(q){i=q}o.getPlaceholder().css("cursor",o.getOptions().pan.cursor);g=p.pageX;e=p.pageY}function j(q){var p=o.getOptions().pan.frameRate;if(n||!p){return}n=setTimeout(function(){o.pan({left:g-q.pageX,top:e-q.pageY});g=q.pageX;e=q.pageY;n=null},1/p*1000)}function h(p){if(n){clearTimeout(n);n=null}o.getPlaceholder().css("cursor",i);o.pan({left:g-p.pageX,top:e-p.pageY})}function l(q,p){var r=q.getOptions();if(r.zoom.interactive){p[r.zoom.trigger](m);p.mousewheel(d)}if(r.pan.interactive){p.bind("dragstart",{distance:10},f);p.bind("drag",j);p.bind("dragend",h)}}o.zoomOut=function(p){if(!p){p={}}if(!p.amount){p.amount=o.getOptions().zoom.amount}p.amount=1/p.amount;o.zoom(p)};o.zoom=function(q){if(!q){q={}}var x=q.center,r=q.amount||o.getOptions().zoom.amount,p=o.width(),t=o.height();if(!x){x={left:p/2,top:t/2}}var s=x.left/p,v=x.top/t,u={x:{min:x.left-s*p/r,max:x.left+(1-s)*p/r},y:{min:x.top-v*t/r,max:x.top+(1-v)*t/r}};b.each(o.getAxes(),function(z,C){var D=C.options,B=u[C.direction].min,w=u[C.direction].max,E=D.zoomRange;if(E===false){return}B=C.c2p(B);w=C.c2p(w);if(B>w){var A=B;B=w;w=A}var y=w-B;if(E&&((E[0]!=null&&y<E[0])||(E[1]!=null&&y>E[1]))){return}D.min=B;D.max=w});o.setupGrid();o.draw();if(!q.preventEvent){o.getPlaceholder().trigger("plotzoom",[o])}};o.pan=function(p){var q={x:+p.left,y:+p.top};if(isNaN(q.x)){q.x=0}if(isNaN(q.y)){q.y=0}b.each(o.getAxes(),function(s,u){var v=u.options,t,r,w=q[u.direction];t=u.c2p(u.p2c(u.min)+w),r=u.c2p(u.p2c(u.max)+w);var x=v.panRange;if(x===false){return}if(x){if(x[0]!=null&&x[0]>t){w=x[0]-t;t+=w;r+=w}if(x[1]!=null&&x[1]<r){w=x[1]-r;t+=w;r+=w}}v.min=t;v.max=r});o.setupGrid();o.draw();if(!p.preventEvent){o.getPlaceholder().trigger("plotpan",[o])}};function k(q,p){p.unbind(q.getOptions().zoom.trigger,m);p.unbind("mousewheel",d);p.unbind("dragstart",f);p.unbind("drag",j);p.unbind("dragend",h);if(n){clearTimeout(n)}}o.hooks.bindEvents.push(l);o.hooks.shutdown.push(k)}b.plot.plugins.push({init:c,options:a,name:"navigate",version:"1.3"})})(jQuery);
|
@@ -0,0 +1,750 @@
|
|
1
|
+
/*
|
2
|
+
Flot plugin for rendering pie charts. The plugin assumes the data is
|
3
|
+
coming is as a single data value for each series, and each of those
|
4
|
+
values is a positive value or zero (negative numbers don't make
|
5
|
+
any sense and will cause strange effects). The data values do
|
6
|
+
NOT need to be passed in as percentage values because it
|
7
|
+
internally calculates the total and percentages.
|
8
|
+
|
9
|
+
* Created by Brian Medendorp, June 2009
|
10
|
+
* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
|
11
|
+
|
12
|
+
* Changes:
|
13
|
+
2009-10-22: lineJoin set to round
|
14
|
+
2009-10-23: IE full circle fix, donut
|
15
|
+
2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
|
16
|
+
2009-11-17: Added IE hover capability submitted by Anthony Aragues
|
17
|
+
2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
|
18
|
+
|
19
|
+
|
20
|
+
Available options are:
|
21
|
+
series: {
|
22
|
+
pie: {
|
23
|
+
show: true/false
|
24
|
+
radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
|
25
|
+
innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
|
26
|
+
startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
|
27
|
+
tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
|
28
|
+
offset: {
|
29
|
+
top: integer value to move the pie up or down
|
30
|
+
left: integer value to move the pie left or right, or 'auto'
|
31
|
+
},
|
32
|
+
stroke: {
|
33
|
+
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
|
34
|
+
width: integer pixel width of the stroke
|
35
|
+
},
|
36
|
+
label: {
|
37
|
+
show: true/false, or 'auto'
|
38
|
+
formatter: a user-defined function that modifies the text/style of the label text
|
39
|
+
radius: 0-1 for percentage of fullsize, or a specified pixel length
|
40
|
+
background: {
|
41
|
+
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
|
42
|
+
opacity: 0-1
|
43
|
+
},
|
44
|
+
threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
|
45
|
+
},
|
46
|
+
combine: {
|
47
|
+
threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
|
48
|
+
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
|
49
|
+
label: any text value of what the combined slice should be labeled
|
50
|
+
}
|
51
|
+
highlight: {
|
52
|
+
opacity: 0-1
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
More detail and specific examples can be found in the included HTML file.
|
58
|
+
|
59
|
+
*/
|
60
|
+
|
61
|
+
(function ($)
|
62
|
+
{
|
63
|
+
function init(plot) // this is the "body" of the plugin
|
64
|
+
{
|
65
|
+
var canvas = null;
|
66
|
+
var target = null;
|
67
|
+
var maxRadius = null;
|
68
|
+
var centerLeft = null;
|
69
|
+
var centerTop = null;
|
70
|
+
var total = 0;
|
71
|
+
var redraw = true;
|
72
|
+
var redrawAttempts = 10;
|
73
|
+
var shrink = 0.95;
|
74
|
+
var legendWidth = 0;
|
75
|
+
var processed = false;
|
76
|
+
var raw = false;
|
77
|
+
|
78
|
+
// interactive variables
|
79
|
+
var highlights = [];
|
80
|
+
|
81
|
+
// add hook to determine if pie plugin in enabled, and then perform necessary operations
|
82
|
+
plot.hooks.processOptions.push(checkPieEnabled);
|
83
|
+
plot.hooks.bindEvents.push(bindEvents);
|
84
|
+
|
85
|
+
// check to see if the pie plugin is enabled
|
86
|
+
function checkPieEnabled(plot, options)
|
87
|
+
{
|
88
|
+
if (options.series.pie.show)
|
89
|
+
{
|
90
|
+
//disable grid
|
91
|
+
options.grid.show = false;
|
92
|
+
|
93
|
+
// set labels.show
|
94
|
+
if (options.series.pie.label.show=='auto')
|
95
|
+
if (options.legend.show)
|
96
|
+
options.series.pie.label.show = false;
|
97
|
+
else
|
98
|
+
options.series.pie.label.show = true;
|
99
|
+
|
100
|
+
// set radius
|
101
|
+
if (options.series.pie.radius=='auto')
|
102
|
+
if (options.series.pie.label.show)
|
103
|
+
options.series.pie.radius = 3/4;
|
104
|
+
else
|
105
|
+
options.series.pie.radius = 1;
|
106
|
+
|
107
|
+
// ensure sane tilt
|
108
|
+
if (options.series.pie.tilt>1)
|
109
|
+
options.series.pie.tilt=1;
|
110
|
+
if (options.series.pie.tilt<0)
|
111
|
+
options.series.pie.tilt=0;
|
112
|
+
|
113
|
+
// add processData hook to do transformations on the data
|
114
|
+
plot.hooks.processDatapoints.push(processDatapoints);
|
115
|
+
plot.hooks.drawOverlay.push(drawOverlay);
|
116
|
+
|
117
|
+
// add draw hook
|
118
|
+
plot.hooks.draw.push(draw);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
// bind hoverable events
|
123
|
+
function bindEvents(plot, eventHolder)
|
124
|
+
{
|
125
|
+
var options = plot.getOptions();
|
126
|
+
|
127
|
+
if (options.series.pie.show && options.grid.hoverable)
|
128
|
+
eventHolder.unbind('mousemove').mousemove(onMouseMove);
|
129
|
+
|
130
|
+
if (options.series.pie.show && options.grid.clickable)
|
131
|
+
eventHolder.unbind('click').click(onClick);
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
// debugging function that prints out an object
|
136
|
+
function alertObject(obj)
|
137
|
+
{
|
138
|
+
var msg = '';
|
139
|
+
function traverse(obj, depth)
|
140
|
+
{
|
141
|
+
if (!depth)
|
142
|
+
depth = 0;
|
143
|
+
for (var i = 0; i < obj.length; ++i)
|
144
|
+
{
|
145
|
+
for (var j=0; j<depth; j++)
|
146
|
+
msg += '\t';
|
147
|
+
|
148
|
+
if( typeof obj[i] == "object")
|
149
|
+
{ // its an object
|
150
|
+
msg += ''+i+':\n';
|
151
|
+
traverse(obj[i], depth+1);
|
152
|
+
}
|
153
|
+
else
|
154
|
+
{ // its a value
|
155
|
+
msg += ''+i+': '+obj[i]+'\n';
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
traverse(obj);
|
160
|
+
alert(msg);
|
161
|
+
}
|
162
|
+
|
163
|
+
function calcTotal(data)
|
164
|
+
{
|
165
|
+
for (var i = 0; i < data.length; ++i)
|
166
|
+
{
|
167
|
+
var item = parseFloat(data[i].data[0][1]);
|
168
|
+
if (item)
|
169
|
+
total += item;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
function processDatapoints(plot, series, data, datapoints)
|
174
|
+
{
|
175
|
+
if (!processed)
|
176
|
+
{
|
177
|
+
processed = true;
|
178
|
+
|
179
|
+
canvas = plot.getCanvas();
|
180
|
+
target = $(canvas).parent();
|
181
|
+
options = plot.getOptions();
|
182
|
+
|
183
|
+
plot.setData(combine(plot.getData()));
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
function setupPie()
|
188
|
+
{
|
189
|
+
legendWidth = target.children().filter('.legend').children().width();
|
190
|
+
|
191
|
+
// calculate maximum radius and center point
|
192
|
+
maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
|
193
|
+
centerTop = (canvas.height/2)+options.series.pie.offset.top;
|
194
|
+
centerLeft = (canvas.width/2);
|
195
|
+
|
196
|
+
if (options.series.pie.offset.left=='auto')
|
197
|
+
if (options.legend.position.match('w'))
|
198
|
+
centerLeft += legendWidth/2;
|
199
|
+
else
|
200
|
+
centerLeft -= legendWidth/2;
|
201
|
+
else
|
202
|
+
centerLeft += options.series.pie.offset.left;
|
203
|
+
|
204
|
+
if (centerLeft<maxRadius)
|
205
|
+
centerLeft = maxRadius;
|
206
|
+
else if (centerLeft>canvas.width-maxRadius)
|
207
|
+
centerLeft = canvas.width-maxRadius;
|
208
|
+
}
|
209
|
+
|
210
|
+
function fixData(data)
|
211
|
+
{
|
212
|
+
for (var i = 0; i < data.length; ++i)
|
213
|
+
{
|
214
|
+
if (typeof(data[i].data)=='number')
|
215
|
+
data[i].data = [[1,data[i].data]];
|
216
|
+
else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
|
217
|
+
{
|
218
|
+
if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
|
219
|
+
data[i].label = data[i].data.label; // fix weirdness coming from flot
|
220
|
+
data[i].data = [[1,0]];
|
221
|
+
|
222
|
+
}
|
223
|
+
}
|
224
|
+
return data;
|
225
|
+
}
|
226
|
+
|
227
|
+
function combine(data)
|
228
|
+
{
|
229
|
+
data = fixData(data);
|
230
|
+
calcTotal(data);
|
231
|
+
var combined = 0;
|
232
|
+
var numCombined = 0;
|
233
|
+
var color = options.series.pie.combine.color;
|
234
|
+
|
235
|
+
var newdata = [];
|
236
|
+
for (var i = 0; i < data.length; ++i)
|
237
|
+
{
|
238
|
+
// make sure its a number
|
239
|
+
data[i].data[0][1] = parseFloat(data[i].data[0][1]);
|
240
|
+
if (!data[i].data[0][1])
|
241
|
+
data[i].data[0][1] = 0;
|
242
|
+
|
243
|
+
if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
|
244
|
+
{
|
245
|
+
combined += data[i].data[0][1];
|
246
|
+
numCombined++;
|
247
|
+
if (!color)
|
248
|
+
color = data[i].color;
|
249
|
+
}
|
250
|
+
else
|
251
|
+
{
|
252
|
+
newdata.push({
|
253
|
+
data: [[1,data[i].data[0][1]]],
|
254
|
+
color: data[i].color,
|
255
|
+
label: data[i].label,
|
256
|
+
angle: (data[i].data[0][1]*(Math.PI*2))/total,
|
257
|
+
percent: (data[i].data[0][1]/total*100)
|
258
|
+
});
|
259
|
+
}
|
260
|
+
}
|
261
|
+
if (numCombined>0)
|
262
|
+
newdata.push({
|
263
|
+
data: [[1,combined]],
|
264
|
+
color: color,
|
265
|
+
label: options.series.pie.combine.label,
|
266
|
+
angle: (combined*(Math.PI*2))/total,
|
267
|
+
percent: (combined/total*100)
|
268
|
+
});
|
269
|
+
return newdata;
|
270
|
+
}
|
271
|
+
|
272
|
+
function draw(plot, newCtx)
|
273
|
+
{
|
274
|
+
if (!target) return; // if no series were passed
|
275
|
+
ctx = newCtx;
|
276
|
+
|
277
|
+
setupPie();
|
278
|
+
var slices = plot.getData();
|
279
|
+
|
280
|
+
var attempts = 0;
|
281
|
+
while (redraw && attempts<redrawAttempts)
|
282
|
+
{
|
283
|
+
redraw = false;
|
284
|
+
if (attempts>0)
|
285
|
+
maxRadius *= shrink;
|
286
|
+
attempts += 1;
|
287
|
+
clear();
|
288
|
+
if (options.series.pie.tilt<=0.8)
|
289
|
+
drawShadow();
|
290
|
+
drawPie();
|
291
|
+
}
|
292
|
+
if (attempts >= redrawAttempts) {
|
293
|
+
clear();
|
294
|
+
target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
|
295
|
+
}
|
296
|
+
|
297
|
+
if ( plot.setSeries && plot.insertLegend )
|
298
|
+
{
|
299
|
+
plot.setSeries(slices);
|
300
|
+
plot.insertLegend();
|
301
|
+
}
|
302
|
+
|
303
|
+
// we're actually done at this point, just defining internal functions at this point
|
304
|
+
|
305
|
+
function clear()
|
306
|
+
{
|
307
|
+
ctx.clearRect(0,0,canvas.width,canvas.height);
|
308
|
+
target.children().filter('.pieLabel, .pieLabelBackground').remove();
|
309
|
+
}
|
310
|
+
|
311
|
+
function drawShadow()
|
312
|
+
{
|
313
|
+
var shadowLeft = 5;
|
314
|
+
var shadowTop = 15;
|
315
|
+
var edge = 10;
|
316
|
+
var alpha = 0.02;
|
317
|
+
|
318
|
+
// set radius
|
319
|
+
if (options.series.pie.radius>1)
|
320
|
+
var radius = options.series.pie.radius;
|
321
|
+
else
|
322
|
+
var radius = maxRadius * options.series.pie.radius;
|
323
|
+
|
324
|
+
if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
|
325
|
+
return; // shadow would be outside canvas, so don't draw it
|
326
|
+
|
327
|
+
ctx.save();
|
328
|
+
ctx.translate(shadowLeft,shadowTop);
|
329
|
+
ctx.globalAlpha = alpha;
|
330
|
+
ctx.fillStyle = '#000';
|
331
|
+
|
332
|
+
// center and rotate to starting position
|
333
|
+
ctx.translate(centerLeft,centerTop);
|
334
|
+
ctx.scale(1, options.series.pie.tilt);
|
335
|
+
|
336
|
+
//radius -= edge;
|
337
|
+
for (var i=1; i<=edge; i++)
|
338
|
+
{
|
339
|
+
ctx.beginPath();
|
340
|
+
ctx.arc(0,0,radius,0,Math.PI*2,false);
|
341
|
+
ctx.fill();
|
342
|
+
radius -= i;
|
343
|
+
}
|
344
|
+
|
345
|
+
ctx.restore();
|
346
|
+
}
|
347
|
+
|
348
|
+
function drawPie()
|
349
|
+
{
|
350
|
+
startAngle = Math.PI*options.series.pie.startAngle;
|
351
|
+
|
352
|
+
// set radius
|
353
|
+
if (options.series.pie.radius>1)
|
354
|
+
var radius = options.series.pie.radius;
|
355
|
+
else
|
356
|
+
var radius = maxRadius * options.series.pie.radius;
|
357
|
+
|
358
|
+
// center and rotate to starting position
|
359
|
+
ctx.save();
|
360
|
+
ctx.translate(centerLeft,centerTop);
|
361
|
+
ctx.scale(1, options.series.pie.tilt);
|
362
|
+
//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
|
363
|
+
|
364
|
+
// draw slices
|
365
|
+
ctx.save();
|
366
|
+
var currentAngle = startAngle;
|
367
|
+
for (var i = 0; i < slices.length; ++i)
|
368
|
+
{
|
369
|
+
slices[i].startAngle = currentAngle;
|
370
|
+
drawSlice(slices[i].angle, slices[i].color, true);
|
371
|
+
}
|
372
|
+
ctx.restore();
|
373
|
+
|
374
|
+
// draw slice outlines
|
375
|
+
ctx.save();
|
376
|
+
ctx.lineWidth = options.series.pie.stroke.width;
|
377
|
+
currentAngle = startAngle;
|
378
|
+
for (var i = 0; i < slices.length; ++i)
|
379
|
+
drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
|
380
|
+
ctx.restore();
|
381
|
+
|
382
|
+
// draw donut hole
|
383
|
+
drawDonutHole(ctx);
|
384
|
+
|
385
|
+
// draw labels
|
386
|
+
if (options.series.pie.label.show)
|
387
|
+
drawLabels();
|
388
|
+
|
389
|
+
// restore to original state
|
390
|
+
ctx.restore();
|
391
|
+
|
392
|
+
function drawSlice(angle, color, fill)
|
393
|
+
{
|
394
|
+
if (angle<=0)
|
395
|
+
return;
|
396
|
+
|
397
|
+
if (fill)
|
398
|
+
ctx.fillStyle = color;
|
399
|
+
else
|
400
|
+
{
|
401
|
+
ctx.strokeStyle = color;
|
402
|
+
ctx.lineJoin = 'round';
|
403
|
+
}
|
404
|
+
|
405
|
+
ctx.beginPath();
|
406
|
+
if (Math.abs(angle - Math.PI*2) > 0.000000001)
|
407
|
+
ctx.moveTo(0,0); // Center of the pie
|
408
|
+
else if ($.browser.msie)
|
409
|
+
angle -= 0.0001;
|
410
|
+
//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
|
411
|
+
ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
|
412
|
+
ctx.closePath();
|
413
|
+
//ctx.rotate(angle); // This doesn't work properly in Opera
|
414
|
+
currentAngle += angle;
|
415
|
+
|
416
|
+
if (fill)
|
417
|
+
ctx.fill();
|
418
|
+
else
|
419
|
+
ctx.stroke();
|
420
|
+
}
|
421
|
+
|
422
|
+
function drawLabels()
|
423
|
+
{
|
424
|
+
var currentAngle = startAngle;
|
425
|
+
|
426
|
+
// set radius
|
427
|
+
if (options.series.pie.label.radius>1)
|
428
|
+
var radius = options.series.pie.label.radius;
|
429
|
+
else
|
430
|
+
var radius = maxRadius * options.series.pie.label.radius;
|
431
|
+
|
432
|
+
for (var i = 0; i < slices.length; ++i)
|
433
|
+
{
|
434
|
+
if (slices[i].percent >= options.series.pie.label.threshold*100)
|
435
|
+
drawLabel(slices[i], currentAngle, i);
|
436
|
+
currentAngle += slices[i].angle;
|
437
|
+
}
|
438
|
+
|
439
|
+
function drawLabel(slice, startAngle, index)
|
440
|
+
{
|
441
|
+
if (slice.data[0][1]==0)
|
442
|
+
return;
|
443
|
+
|
444
|
+
// format label text
|
445
|
+
var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
|
446
|
+
if (lf)
|
447
|
+
text = lf(slice.label, slice);
|
448
|
+
else
|
449
|
+
text = slice.label;
|
450
|
+
if (plf)
|
451
|
+
text = plf(text, slice);
|
452
|
+
|
453
|
+
var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
|
454
|
+
var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
|
455
|
+
var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
|
456
|
+
|
457
|
+
var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
|
458
|
+
target.append(html);
|
459
|
+
var label = target.children('#pieLabel'+index);
|
460
|
+
var labelTop = (y - label.height()/2);
|
461
|
+
var labelLeft = (x - label.width()/2);
|
462
|
+
label.css('top', labelTop);
|
463
|
+
label.css('left', labelLeft);
|
464
|
+
|
465
|
+
// check to make sure that the label is not outside the canvas
|
466
|
+
if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
|
467
|
+
redraw = true;
|
468
|
+
|
469
|
+
if (options.series.pie.label.background.opacity != 0) {
|
470
|
+
// put in the transparent background separately to avoid blended labels and label boxes
|
471
|
+
var c = options.series.pie.label.background.color;
|
472
|
+
if (c == null) {
|
473
|
+
c = slice.color;
|
474
|
+
}
|
475
|
+
var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
|
476
|
+
$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
|
477
|
+
}
|
478
|
+
} // end individual label function
|
479
|
+
} // end drawLabels function
|
480
|
+
} // end drawPie function
|
481
|
+
} // end draw function
|
482
|
+
|
483
|
+
// Placed here because it needs to be accessed from multiple locations
|
484
|
+
function drawDonutHole(layer)
|
485
|
+
{
|
486
|
+
// draw donut hole
|
487
|
+
if(options.series.pie.innerRadius > 0)
|
488
|
+
{
|
489
|
+
// subtract the center
|
490
|
+
layer.save();
|
491
|
+
innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
|
492
|
+
layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
|
493
|
+
layer.beginPath();
|
494
|
+
layer.fillStyle = options.series.pie.stroke.color;
|
495
|
+
layer.arc(0,0,innerRadius,0,Math.PI*2,false);
|
496
|
+
layer.fill();
|
497
|
+
layer.closePath();
|
498
|
+
layer.restore();
|
499
|
+
|
500
|
+
// add inner stroke
|
501
|
+
layer.save();
|
502
|
+
layer.beginPath();
|
503
|
+
layer.strokeStyle = options.series.pie.stroke.color;
|
504
|
+
layer.arc(0,0,innerRadius,0,Math.PI*2,false);
|
505
|
+
layer.stroke();
|
506
|
+
layer.closePath();
|
507
|
+
layer.restore();
|
508
|
+
// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
512
|
+
//-- Additional Interactive related functions --
|
513
|
+
|
514
|
+
function isPointInPoly(poly, pt)
|
515
|
+
{
|
516
|
+
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
|
517
|
+
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
|
518
|
+
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
|
519
|
+
&& (c = !c);
|
520
|
+
return c;
|
521
|
+
}
|
522
|
+
|
523
|
+
function findNearbySlice(mouseX, mouseY)
|
524
|
+
{
|
525
|
+
var slices = plot.getData(),
|
526
|
+
options = plot.getOptions(),
|
527
|
+
radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
|
528
|
+
|
529
|
+
for (var i = 0; i < slices.length; ++i)
|
530
|
+
{
|
531
|
+
var s = slices[i];
|
532
|
+
|
533
|
+
if(s.pie.show)
|
534
|
+
{
|
535
|
+
ctx.save();
|
536
|
+
ctx.beginPath();
|
537
|
+
ctx.moveTo(0,0); // Center of the pie
|
538
|
+
//ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
|
539
|
+
ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
|
540
|
+
ctx.closePath();
|
541
|
+
x = mouseX-centerLeft;
|
542
|
+
y = mouseY-centerTop;
|
543
|
+
if(ctx.isPointInPath)
|
544
|
+
{
|
545
|
+
if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
|
546
|
+
{
|
547
|
+
//alert('found slice!');
|
548
|
+
ctx.restore();
|
549
|
+
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
|
550
|
+
}
|
551
|
+
}
|
552
|
+
else
|
553
|
+
{
|
554
|
+
// excanvas for IE doesn;t support isPointInPath, this is a workaround.
|
555
|
+
p1X = (radius * Math.cos(s.startAngle));
|
556
|
+
p1Y = (radius * Math.sin(s.startAngle));
|
557
|
+
p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
|
558
|
+
p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
|
559
|
+
p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
|
560
|
+
p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
|
561
|
+
p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
|
562
|
+
p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
|
563
|
+
p5X = (radius * Math.cos(s.startAngle+s.angle));
|
564
|
+
p5Y = (radius * Math.sin(s.startAngle+s.angle));
|
565
|
+
arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
|
566
|
+
arrPoint = [x,y];
|
567
|
+
// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
|
568
|
+
if(isPointInPoly(arrPoly, arrPoint))
|
569
|
+
{
|
570
|
+
ctx.restore();
|
571
|
+
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
|
572
|
+
}
|
573
|
+
}
|
574
|
+
ctx.restore();
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
return null;
|
579
|
+
}
|
580
|
+
|
581
|
+
function onMouseMove(e)
|
582
|
+
{
|
583
|
+
triggerClickHoverEvent('plothover', e);
|
584
|
+
}
|
585
|
+
|
586
|
+
function onClick(e)
|
587
|
+
{
|
588
|
+
triggerClickHoverEvent('plotclick', e);
|
589
|
+
}
|
590
|
+
|
591
|
+
// trigger click or hover event (they send the same parameters so we share their code)
|
592
|
+
function triggerClickHoverEvent(eventname, e)
|
593
|
+
{
|
594
|
+
var offset = plot.offset(),
|
595
|
+
canvasX = parseInt(e.pageX - offset.left),
|
596
|
+
canvasY = parseInt(e.pageY - offset.top),
|
597
|
+
item = findNearbySlice(canvasX, canvasY);
|
598
|
+
|
599
|
+
if (options.grid.autoHighlight)
|
600
|
+
{
|
601
|
+
// clear auto-highlights
|
602
|
+
for (var i = 0; i < highlights.length; ++i)
|
603
|
+
{
|
604
|
+
var h = highlights[i];
|
605
|
+
if (h.auto == eventname && !(item && h.series == item.series))
|
606
|
+
unhighlight(h.series);
|
607
|
+
}
|
608
|
+
}
|
609
|
+
|
610
|
+
// highlight the slice
|
611
|
+
if (item)
|
612
|
+
highlight(item.series, eventname);
|
613
|
+
|
614
|
+
// trigger any hover bind events
|
615
|
+
var pos = { pageX: e.pageX, pageY: e.pageY };
|
616
|
+
target.trigger(eventname, [ pos, item ]);
|
617
|
+
}
|
618
|
+
|
619
|
+
function highlight(s, auto)
|
620
|
+
{
|
621
|
+
if (typeof s == "number")
|
622
|
+
s = series[s];
|
623
|
+
|
624
|
+
var i = indexOfHighlight(s);
|
625
|
+
if (i == -1)
|
626
|
+
{
|
627
|
+
highlights.push({ series: s, auto: auto });
|
628
|
+
plot.triggerRedrawOverlay();
|
629
|
+
}
|
630
|
+
else if (!auto)
|
631
|
+
highlights[i].auto = false;
|
632
|
+
}
|
633
|
+
|
634
|
+
function unhighlight(s)
|
635
|
+
{
|
636
|
+
if (s == null)
|
637
|
+
{
|
638
|
+
highlights = [];
|
639
|
+
plot.triggerRedrawOverlay();
|
640
|
+
}
|
641
|
+
|
642
|
+
if (typeof s == "number")
|
643
|
+
s = series[s];
|
644
|
+
|
645
|
+
var i = indexOfHighlight(s);
|
646
|
+
if (i != -1)
|
647
|
+
{
|
648
|
+
highlights.splice(i, 1);
|
649
|
+
plot.triggerRedrawOverlay();
|
650
|
+
}
|
651
|
+
}
|
652
|
+
|
653
|
+
function indexOfHighlight(s)
|
654
|
+
{
|
655
|
+
for (var i = 0; i < highlights.length; ++i)
|
656
|
+
{
|
657
|
+
var h = highlights[i];
|
658
|
+
if (h.series == s)
|
659
|
+
return i;
|
660
|
+
}
|
661
|
+
return -1;
|
662
|
+
}
|
663
|
+
|
664
|
+
function drawOverlay(plot, octx)
|
665
|
+
{
|
666
|
+
//alert(options.series.pie.radius);
|
667
|
+
var options = plot.getOptions();
|
668
|
+
//alert(options.series.pie.radius);
|
669
|
+
|
670
|
+
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
|
671
|
+
|
672
|
+
octx.save();
|
673
|
+
octx.translate(centerLeft, centerTop);
|
674
|
+
octx.scale(1, options.series.pie.tilt);
|
675
|
+
|
676
|
+
for (i = 0; i < highlights.length; ++i)
|
677
|
+
drawHighlight(highlights[i].series);
|
678
|
+
|
679
|
+
drawDonutHole(octx);
|
680
|
+
|
681
|
+
octx.restore();
|
682
|
+
|
683
|
+
function drawHighlight(series)
|
684
|
+
{
|
685
|
+
if (series.angle < 0) return;
|
686
|
+
|
687
|
+
//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
|
688
|
+
octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
|
689
|
+
|
690
|
+
octx.beginPath();
|
691
|
+
if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
|
692
|
+
octx.moveTo(0,0); // Center of the pie
|
693
|
+
octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
|
694
|
+
octx.closePath();
|
695
|
+
octx.fill();
|
696
|
+
}
|
697
|
+
|
698
|
+
}
|
699
|
+
|
700
|
+
} // end init (plugin body)
|
701
|
+
|
702
|
+
// define pie specific options and their default values
|
703
|
+
var options = {
|
704
|
+
series: {
|
705
|
+
pie: {
|
706
|
+
show: false,
|
707
|
+
radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
|
708
|
+
innerRadius:0, /* for donut */
|
709
|
+
startAngle: 3/2,
|
710
|
+
tilt: 1,
|
711
|
+
offset: {
|
712
|
+
top: 0,
|
713
|
+
left: 'auto'
|
714
|
+
},
|
715
|
+
stroke: {
|
716
|
+
color: '#FFF',
|
717
|
+
width: 1
|
718
|
+
},
|
719
|
+
label: {
|
720
|
+
show: 'auto',
|
721
|
+
formatter: function(label, slice){
|
722
|
+
return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
|
723
|
+
}, // formatter function
|
724
|
+
radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
|
725
|
+
background: {
|
726
|
+
color: null,
|
727
|
+
opacity: 0
|
728
|
+
},
|
729
|
+
threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
|
730
|
+
},
|
731
|
+
combine: {
|
732
|
+
threshold: -1, // percentage at which to combine little slices into one larger slice
|
733
|
+
color: null, // color to give the new slice (auto-generated if null)
|
734
|
+
label: 'Other' // label to give the new slice
|
735
|
+
},
|
736
|
+
highlight: {
|
737
|
+
//color: '#FFF', // will add this functionality once parseColor is available
|
738
|
+
opacity: 0.5
|
739
|
+
}
|
740
|
+
}
|
741
|
+
}
|
742
|
+
};
|
743
|
+
|
744
|
+
$.plot.plugins.push({
|
745
|
+
init: init,
|
746
|
+
options: options,
|
747
|
+
name: "pie",
|
748
|
+
version: "1.0"
|
749
|
+
});
|
750
|
+
})(jQuery);
|