blacklight_range_limit 2.3.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -2
- data/.travis.yml +7 -13
- data/Gemfile +8 -34
- data/LICENSE +15 -0
- data/README.rdoc +25 -7
- data/Rakefile +3 -4
- data/VERSION +1 -1
- data/app/assets/javascripts/blacklight_range_limit.js +5 -2
- data/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js +144 -68
- data/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js +68 -36
- data/app/assets/stylesheets/blacklight_range_limit.css.scss +1 -46
- data/app/assets/stylesheets/blacklight_range_limit/blacklight_range_limit.css +12 -2
- data/app/helpers/range_limit_helper.rb +7 -1
- data/app/views/blacklight_range_limit/_range_limit_panel.html.erb +27 -11
- data/app/views/blacklight_range_limit/_range_segments.html.erb +13 -8
- data/blacklight_range_limit.gemspec +9 -12
- data/config/jetty.yml +7 -2
- data/lib/blacklight_range_limit/controller_override.rb +4 -13
- data/lib/blacklight_range_limit/route_sets.rb +21 -4
- data/lib/blacklight_range_limit/view_helper_override.rb +27 -11
- data/lib/generators/blacklight_range_limit/assets_generator.rb +9 -2
- data/spec/features/blacklight_range_limit_spec.rb +5 -5
- data/spec/spec_helper.rb +7 -1
- data/spec/test_app_templates/Gemfile.extra +14 -1
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +4 -15
- data/spec/test_app_templates/lib/tasks/blacklight_test_app.rake +0 -6
- data/vendor/assets/javascripts/bootstrap-slider.js +388 -0
- data/vendor/assets/javascripts/flot/excanvas.min.js +1 -1
- data/vendor/assets/javascripts/flot/jquery.flot.js +1328 -790
- data/vendor/assets/javascripts/flot/jquery.flot.selection.js +76 -60
- data/vendor/assets/stylesheets/slider.css +138 -0
- metadata +74 -110
- checksums.yaml +0 -7
- data/.rspec +0 -1
- data/MIT-LICENSE +0 -20
- data/solr/sample_solr_documents.yml +0 -641
- data/vendor/assets/javascripts/jquery-ui-1.9.2.custom.js +0 -1654
@@ -1 +1 @@
|
|
1
|
-
if(!document.createElement("canvas").getContext){(function(){var z=Math;var K=z.round;var J=z.sin;var U=z.cos;var b=z.abs;var k=z.sqrt;var D=10;var F=D/2;function T(){return this.context_||(this.context_=new W(this))}var O=Array.prototype.slice;function G(i,j,m){var Z=O.call(arguments,2);return function(){return i.apply(j,Z.concat(O.call(arguments)))}}function AD(Z){return String(Z).replace(/&/g,"&").replace(/"/g,""")}function r(i){if(!i.namespaces.g_vml_){i.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML")}if(!i.namespaces.g_o_){i.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML")}if(!i.styleSheets.ex_canvas_){var Z=i.createStyleSheet();Z.owningElement.id="ex_canvas_";Z.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}r(document);var E={init:function(Z){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var i=Z||document;i.createElement("canvas");i.attachEvent("onreadystatechange",G(this.init_,this,i))}},init_:function(m){var j=m.getElementsByTagName("canvas");for(var Z=0;Z<j.length;Z++){this.initElement(j[Z])}},initElement:function(i){if(!i.getContext){i.getContext=T;r(i.ownerDocument);i.innerHTML="";i.attachEvent("onpropertychange",S);i.attachEvent("onresize",w);var Z=i.attributes;if(Z.width&&Z.width.specified){i.style.width=Z.width.nodeValue+"px"}else{i.width=i.clientWidth}if(Z.height&&Z.height.specified){i.style.height=Z.height.nodeValue+"px"}else{i.height=i.clientHeight}}return i}};function S(i){var Z=i.srcElement;switch(i.propertyName){case"width":Z.getContext().clearRect();Z.style.width=Z.attributes.width.nodeValue+"px";Z.firstChild.style.width=Z.clientWidth+"px";break;case"height":Z.getContext().clearRect();Z.style.height=Z.attributes.height.nodeValue+"px";Z.firstChild.style.height=Z.clientHeight+"px";break}}function w(i){var Z=i.srcElement;if(Z.firstChild){Z.firstChild.style.width=Z.clientWidth+"px";Z.firstChild.style.height=Z.clientHeight+"px"}}E.init();var I=[];for(var AC=0;AC<16;AC++){for(var AB=0;AB<16;AB++){I[AC*16+AB]=AC.toString(16)+AB.toString(16)}}function V(){return[[1,0,0],[0,1,0],[0,0,1]]}function d(m,j){var i=V();for(var Z=0;Z<3;Z++){for(var AF=0;AF<3;AF++){var p=0;for(var AE=0;AE<3;AE++){p+=m[Z][AE]*j[AE][AF]}i[Z][AF]=p}}return i}function Q(i,Z){Z.fillStyle=i.fillStyle;Z.lineCap=i.lineCap;Z.lineJoin=i.lineJoin;Z.lineWidth=i.lineWidth;Z.miterLimit=i.miterLimit;Z.shadowBlur=i.shadowBlur;Z.shadowColor=i.shadowColor;Z.shadowOffsetX=i.shadowOffsetX;Z.shadowOffsetY=i.shadowOffsetY;Z.strokeStyle=i.strokeStyle;Z.globalAlpha=i.globalAlpha;Z.font=i.font;Z.textAlign=i.textAlign;Z.textBaseline=i.textBaseline;Z.arcScaleX_=i.arcScaleX_;Z.arcScaleY_=i.arcScaleY_;Z.lineScale_=i.lineScale_}var B={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"};function g(i){var m=i.indexOf("(",3);var Z=i.indexOf(")",m+1);var j=i.substring(m+1,Z).split(",");if(j.length==4&&i.substr(3,1)=="a"){alpha=Number(j[3])}else{j[3]=1}return j}function C(Z){return parseFloat(Z)/100}function N(i,j,Z){return Math.min(Z,Math.max(j,i))}function c(AF){var j,i,Z;h=parseFloat(AF[0])/360%360;if(h<0){h++}s=N(C(AF[1]),0,1);l=N(C(AF[2]),0,1);if(s==0){j=i=Z=l}else{var m=l<0.5?l*(1+s):l+s-l*s;var AE=2*l-m;j=A(AE,m,h+1/3);i=A(AE,m,h);Z=A(AE,m,h-1/3)}return"#"+I[Math.floor(j*255)]+I[Math.floor(i*255)]+I[Math.floor(Z*255)]}function A(i,Z,j){if(j<0){j++}if(j>1){j--}if(6*j<1){return i+(Z-i)*6*j}else{if(2*j<1){return Z}else{if(3*j<2){return i+(Z-i)*(2/3-j)*6}else{return i}}}}function Y(Z){var AE,p=1;Z=String(Z);if(Z.charAt(0)=="#"){AE=Z}else{if(/^rgb/.test(Z)){var m=g(Z);var AE="#",AF;for(var j=0;j<3;j++){if(m[j].indexOf("%")!=-1){AF=Math.floor(C(m[j])*255)}else{AF=Number(m[j])}AE+=I[N(AF,0,255)]}p=m[3]}else{if(/^hsl/.test(Z)){var m=g(Z);AE=c(m);p=m[3]}else{AE=B[Z]||Z}}}return{color:AE,alpha:p}}var L={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var f={};function X(Z){if(f[Z]){return f[Z]}var m=document.createElement("div");var j=m.style;try{j.font=Z}catch(i){}return f[Z]={style:j.fontStyle||L.style,variant:j.fontVariant||L.variant,weight:j.fontWeight||L.weight,size:j.fontSize||L.size,family:j.fontFamily||L.family}}function P(j,i){var Z={};for(var AF in j){Z[AF]=j[AF]}var AE=parseFloat(i.currentStyle.fontSize),m=parseFloat(j.size);if(typeof j.size=="number"){Z.size=j.size}else{if(j.size.indexOf("px")!=-1){Z.size=m}else{if(j.size.indexOf("em")!=-1){Z.size=AE*m}else{if(j.size.indexOf("%")!=-1){Z.size=(AE/100)*m}else{if(j.size.indexOf("pt")!=-1){Z.size=m/0.75}else{Z.size=AE}}}}}Z.size*=0.981;return Z}function AA(Z){return Z.style+" "+Z.variant+" "+Z.weight+" "+Z.size+"px "+Z.family}function t(Z){switch(Z){case"butt":return"flat";case"round":return"round";case"square":default:return"square"}}function W(i){this.m_=V();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=D*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var Z=i.ownerDocument.createElement("div");Z.style.width=i.clientWidth+"px";Z.style.height=i.clientHeight+"px";Z.style.overflow="hidden";Z.style.position="absolute";i.appendChild(Z);this.element_=Z;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var M=W.prototype;M.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};M.beginPath=function(){this.currentPath_=[]};M.moveTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"moveTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.lineTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"lineTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.bezierCurveTo=function(j,i,AI,AH,AG,AE){var Z=this.getCoords_(AG,AE);var AF=this.getCoords_(j,i);var m=this.getCoords_(AI,AH);e(this,AF,m,Z)};function e(Z,m,j,i){Z.currentPath_.push({type:"bezierCurveTo",cp1x:m.x,cp1y:m.y,cp2x:j.x,cp2y:j.y,x:i.x,y:i.y});Z.currentX_=i.x;Z.currentY_=i.y}M.quadraticCurveTo=function(AG,j,i,Z){var AF=this.getCoords_(AG,j);var AE=this.getCoords_(i,Z);var AH={x:this.currentX_+2/3*(AF.x-this.currentX_),y:this.currentY_+2/3*(AF.y-this.currentY_)};var m={x:AH.x+(AE.x-this.currentX_)/3,y:AH.y+(AE.y-this.currentY_)/3};e(this,AH,m,AE)};M.arc=function(AJ,AH,AI,AE,i,j){AI*=D;var AN=j?"at":"wa";var AK=AJ+U(AE)*AI-F;var AM=AH+J(AE)*AI-F;var Z=AJ+U(i)*AI-F;var AL=AH+J(i)*AI-F;if(AK==Z&&!j){AK+=0.125}var m=this.getCoords_(AJ,AH);var AG=this.getCoords_(AK,AM);var AF=this.getCoords_(Z,AL);this.currentPath_.push({type:AN,x:m.x,y:m.y,radius:AI,xStart:AG.x,yStart:AG.y,xEnd:AF.x,yEnd:AF.y})};M.rect=function(j,i,Z,m){this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath()};M.strokeRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.stroke();this.currentPath_=p};M.fillRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.fill();this.currentPath_=p};M.createLinearGradient=function(i,m,Z,j){var p=new v("gradient");p.x0_=i;p.y0_=m;p.x1_=Z;p.y1_=j;return p};M.createRadialGradient=function(m,AE,j,i,p,Z){var AF=new v("gradientradial");AF.x0_=m;AF.y0_=AE;AF.r0_=j;AF.x1_=i;AF.y1_=p;AF.r1_=Z;return AF};M.drawImage=function(AO,j){var AH,AF,AJ,AV,AM,AK,AQ,AX;var AI=AO.runtimeStyle.width;var AN=AO.runtimeStyle.height;AO.runtimeStyle.width="auto";AO.runtimeStyle.height="auto";var AG=AO.width;var AT=AO.height;AO.runtimeStyle.width=AI;AO.runtimeStyle.height=AN;if(arguments.length==3){AH=arguments[1];AF=arguments[2];AM=AK=0;AQ=AJ=AG;AX=AV=AT}else{if(arguments.length==5){AH=arguments[1];AF=arguments[2];AJ=arguments[3];AV=arguments[4];AM=AK=0;AQ=AG;AX=AT}else{if(arguments.length==9){AM=arguments[1];AK=arguments[2];AQ=arguments[3];AX=arguments[4];AH=arguments[5];AF=arguments[6];AJ=arguments[7];AV=arguments[8]}else{throw Error("Invalid number of arguments")}}}var AW=this.getCoords_(AH,AF);var m=AQ/2;var i=AX/2;var AU=[];var Z=10;var AE=10;AU.push(" <g_vml_:group",' coordsize="',D*Z,",",D*AE,'"',' coordorigin="0,0"',' style="width:',Z,"px;height:",AE,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var p=[];p.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",K(AW.x/D),",","Dy=",K(AW.y/D),"");var AS=AW;var AR=this.getCoords_(AH+AJ,AF);var AP=this.getCoords_(AH,AF+AV);var AL=this.getCoords_(AH+AJ,AF+AV);AS.x=z.max(AS.x,AR.x,AP.x,AL.x);AS.y=z.max(AS.y,AR.y,AP.y,AL.y);AU.push("padding:0 ",K(AS.x/D),"px ",K(AS.y/D),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",p.join(""),", sizingmethod='clip');")}else{AU.push("top:",K(AW.y/D),"px;left:",K(AW.x/D),"px;")}AU.push(' ">','<g_vml_:image src="',AO.src,'"',' style="width:',D*AJ,"px;"," height:",D*AV,'px"',' cropleft="',AM/AG,'"',' croptop="',AK/AT,'"',' cropright="',(AG-AM-AQ)/AG,'"',' cropbottom="',(AT-AK-AX)/AT,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",AU.join(""))};M.stroke=function(AM){var m=10;var AN=10;var AE=5000;var AG={x:null,y:null};var AL={x:null,y:null};for(var AH=0;AH<this.currentPath_.length;AH+=AE){var AK=[];var AF=false;AK.push("<g_vml_:shape",' filled="',!!AM,'"',' style="position:absolute;width:',m,"px;height:",AN,'px;"',' coordorigin="0,0"',' coordsize="',D*m,",",D*AN,'"',' stroked="',!AM,'"',' path="');var AO=false;for(var AI=AH;AI<Math.min(AH+AE,this.currentPath_.length);AI++){if(AI%AE==0&&AI>0){AK.push(" m ",K(this.currentPath_[AI-1].x),",",K(this.currentPath_[AI-1].y))}var Z=this.currentPath_[AI];var AJ;switch(Z.type){case"moveTo":AJ=Z;AK.push(" m ",K(Z.x),",",K(Z.y));break;case"lineTo":AK.push(" l ",K(Z.x),",",K(Z.y));break;case"close":AK.push(" x ");Z=null;break;case"bezierCurveTo":AK.push(" c ",K(Z.cp1x),",",K(Z.cp1y),",",K(Z.cp2x),",",K(Z.cp2y),",",K(Z.x),",",K(Z.y));break;case"at":case"wa":AK.push(" ",Z.type," ",K(Z.x-this.arcScaleX_*Z.radius),",",K(Z.y-this.arcScaleY_*Z.radius)," ",K(Z.x+this.arcScaleX_*Z.radius),",",K(Z.y+this.arcScaleY_*Z.radius)," ",K(Z.xStart),",",K(Z.yStart)," ",K(Z.xEnd),",",K(Z.yEnd));break}if(Z){if(AG.x==null||Z.x<AG.x){AG.x=Z.x}if(AL.x==null||Z.x>AL.x){AL.x=Z.x}if(AG.y==null||Z.y<AG.y){AG.y=Z.y}if(AL.y==null||Z.y>AL.y){AL.y=Z.y}}}AK.push(' ">');if(!AM){R(this,AK)}else{a(this,AK,AG,AL)}AK.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",AK.join(""))}};function R(j,AE){var i=Y(j.strokeStyle);var m=i.color;var p=i.alpha*j.globalAlpha;var Z=j.lineScale_*j.lineWidth;if(Z<1){p*=Z}AE.push("<g_vml_:stroke",' opacity="',p,'"',' joinstyle="',j.lineJoin,'"',' miterlimit="',j.miterLimit,'"',' endcap="',t(j.lineCap),'"',' weight="',Z,'px"',' color="',m,'" />')}function a(AO,AG,Ah,AP){var AH=AO.fillStyle;var AY=AO.arcScaleX_;var AX=AO.arcScaleY_;var Z=AP.x-Ah.x;var m=AP.y-Ah.y;if(AH instanceof v){var AL=0;var Ac={x:0,y:0};var AU=0;var AK=1;if(AH.type_=="gradient"){var AJ=AH.x0_/AY;var j=AH.y0_/AX;var AI=AH.x1_/AY;var Aj=AH.y1_/AX;var Ag=AO.getCoords_(AJ,j);var Af=AO.getCoords_(AI,Aj);var AE=Af.x-Ag.x;var p=Af.y-Ag.y;AL=Math.atan2(AE,p)*180/Math.PI;if(AL<0){AL+=360}if(AL<0.000001){AL=0}}else{var Ag=AO.getCoords_(AH.x0_,AH.y0_);Ac={x:(Ag.x-Ah.x)/Z,y:(Ag.y-Ah.y)/m};Z/=AY*D;m/=AX*D;var Aa=z.max(Z,m);AU=2*AH.r0_/Aa;AK=2*AH.r1_/Aa-AU}var AS=AH.colors_;AS.sort(function(Ak,i){return Ak.offset-i.offset});var AN=AS.length;var AR=AS[0].color;var AQ=AS[AN-1].color;var AW=AS[0].alpha*AO.globalAlpha;var AV=AS[AN-1].alpha*AO.globalAlpha;var Ab=[];for(var Ae=0;Ae<AN;Ae++){var AM=AS[Ae];Ab.push(AM.offset*AK+AU+" "+AM.color)}AG.push('<g_vml_:fill type="',AH.type_,'"',' method="none" focus="100%"',' color="',AR,'"',' color2="',AQ,'"',' colors="',Ab.join(","),'"',' opacity="',AV,'"',' g_o_:opacity2="',AW,'"',' angle="',AL,'"',' focusposition="',Ac.x,",",Ac.y,'" />')}else{if(AH instanceof u){if(Z&&m){var AF=-Ah.x;var AZ=-Ah.y;AG.push("<g_vml_:fill",' position="',AF/Z*AY*AY,",",AZ/m*AX*AX,'"',' type="tile"',' src="',AH.src_,'" />')}}else{var Ai=Y(AO.fillStyle);var AT=Ai.color;var Ad=Ai.alpha*AO.globalAlpha;AG.push('<g_vml_:fill color="',AT,'" opacity="',Ad,'" />')}}}M.fill=function(){this.stroke(true)};M.closePath=function(){this.currentPath_.push({type:"close"})};M.getCoords_=function(j,i){var Z=this.m_;return{x:D*(j*Z[0][0]+i*Z[1][0]+Z[2][0])-F,y:D*(j*Z[0][1]+i*Z[1][1]+Z[2][1])-F}};M.save=function(){var Z={};Q(this,Z);this.aStack_.push(Z);this.mStack_.push(this.m_);this.m_=d(V(),this.m_)};M.restore=function(){if(this.aStack_.length){Q(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function H(Z){return isFinite(Z[0][0])&&isFinite(Z[0][1])&&isFinite(Z[1][0])&&isFinite(Z[1][1])&&isFinite(Z[2][0])&&isFinite(Z[2][1])}function y(i,Z,j){if(!H(Z)){return }i.m_=Z;if(j){var p=Z[0][0]*Z[1][1]-Z[0][1]*Z[1][0];i.lineScale_=k(b(p))}}M.translate=function(j,i){var Z=[[1,0,0],[0,1,0],[j,i,1]];y(this,d(Z,this.m_),false)};M.rotate=function(i){var m=U(i);var j=J(i);var Z=[[m,j,0],[-j,m,0],[0,0,1]];y(this,d(Z,this.m_),false)};M.scale=function(j,i){this.arcScaleX_*=j;this.arcScaleY_*=i;var Z=[[j,0,0],[0,i,0],[0,0,1]];y(this,d(Z,this.m_),true)};M.transform=function(p,m,AF,AE,i,Z){var j=[[p,m,0],[AF,AE,0],[i,Z,1]];y(this,d(j,this.m_),true)};M.setTransform=function(AE,p,AG,AF,j,i){var Z=[[AE,p,0],[AG,AF,0],[j,i,1]];y(this,Z,true)};M.drawText_=function(AK,AI,AH,AN,AG){var AM=this.m_,AQ=1000,i=0,AP=AQ,AF={x:0,y:0},AE=[];var Z=P(X(this.font),this.element_);var j=AA(Z);var AR=this.element_.currentStyle;var p=this.textAlign.toLowerCase();switch(p){case"left":case"center":case"right":break;case"end":p=AR.direction=="ltr"?"right":"left";break;case"start":p=AR.direction=="rtl"?"right":"left";break;default:p="left"}switch(this.textBaseline){case"hanging":case"top":AF.y=Z.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":AF.y=-Z.size/2.25;break}switch(p){case"right":i=AQ;AP=0.05;break;case"center":i=AP=AQ/2;break}var AO=this.getCoords_(AI+AF.x,AH+AF.y);AE.push('<g_vml_:line from="',-i,' 0" to="',AP,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!AG,'" stroked="',!!AG,'" style="position:absolute;width:1px;height:1px;">');if(AG){R(this,AE)}else{a(this,AE,{x:-i,y:0},{x:AP,y:Z.size})}var AL=AM[0][0].toFixed(3)+","+AM[1][0].toFixed(3)+","+AM[0][1].toFixed(3)+","+AM[1][1].toFixed(3)+",0,0";var AJ=K(AO.x/D)+","+K(AO.y/D);AE.push('<g_vml_:skew on="t" matrix="',AL,'" ',' offset="',AJ,'" origin="',i,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',AD(AK),'" style="v-text-align:',p,";font:",AD(j),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",AE.join(""))};M.fillText=function(j,Z,m,i){this.drawText_(j,Z,m,i,false)};M.strokeText=function(j,Z,m,i){this.drawText_(j,Z,m,i,true)};M.measureText=function(j){if(!this.textMeasureEl_){var Z='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",Z);this.textMeasureEl_=this.element_.lastChild}var i=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(i.createTextNode(j));return{width:this.textMeasureEl_.offsetWidth}};M.clip=function(){};M.arcTo=function(){};M.createPattern=function(i,Z){return new u(i,Z)};function v(Z){this.type_=Z;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}v.prototype.addColorStop=function(i,Z){Z=Y(Z);this.colors_.push({offset:i,color:Z.color,alpha:Z.alpha})};function u(i,Z){q(i);switch(Z){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=Z;break;default:n("SYNTAX_ERR")}this.src_=i.src;this.width_=i.width;this.height_=i.height}function n(Z){throw new o(Z)}function q(Z){if(!Z||Z.nodeType!=1||Z.tagName!="IMG"){n("TYPE_MISMATCH_ERR")}if(Z.readyState!="complete"){n("INVALID_STATE_ERR")}}function o(Z){this.code=this[Z];this.message=Z+": DOM Exception "+this.code}var x=o.prototype=new Error;x.INDEX_SIZE_ERR=1;x.DOMSTRING_SIZE_ERR=2;x.HIERARCHY_REQUEST_ERR=3;x.WRONG_DOCUMENT_ERR=4;x.INVALID_CHARACTER_ERR=5;x.NO_DATA_ALLOWED_ERR=6;x.NO_MODIFICATION_ALLOWED_ERR=7;x.NOT_FOUND_ERR=8;x.NOT_SUPPORTED_ERR=9;x.INUSE_ATTRIBUTE_ERR=10;x.INVALID_STATE_ERR=11;x.SYNTAX_ERR=12;x.INVALID_MODIFICATION_ERR=13;x.NAMESPACE_ERR=14;x.INVALID_ACCESS_ERR=15;x.VALIDATION_ERR=16;x.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=E;CanvasRenderingContext2D=W;CanvasGradient=v;CanvasPattern=u;DOMException=o})()};
|
1
|
+
if(!document.createElement("canvas").getContext){(function(){var ab=Math;var n=ab.round;var l=ab.sin;var A=ab.cos;var H=ab.abs;var N=ab.sqrt;var d=10;var f=d/2;var z=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];function y(){return this.context_||(this.context_=new D(this))}var t=Array.prototype.slice;function g(j,m,p){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}function af(i){return String(i).replace(/&/g,"&").replace(/"/g,""")}function Y(m,j,i){if(!m.namespaces[j]){m.namespaces.add(j,i,"#default#VML")}}function R(j){Y(j,"g_vml_","urn:schemas-microsoft-com:vml");Y(j,"g_o_","urn:schemas-microsoft-com:office:office");if(!j.styleSheets.ex_canvas_){var i=j.createStyleSheet();i.owningElement.id="ex_canvas_";i.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}R(document);var e={init:function(i){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",g(this.init_,this,j))},init_:function(p){var m=p.getElementsByTagName("canvas");for(var j=0;j<m.length;j++){this.initElement(m[j])}},initElement:function(j){if(!j.getContext){j.getContext=y;R(j.ownerDocument);j.innerHTML="";j.attachEvent("onpropertychange",x);j.attachEvent("onresize",W);var i=j.attributes;if(i.width&&i.width.specified){j.style.width=i.width.nodeValue+"px"}else{j.width=j.clientWidth}if(i.height&&i.height.specified){j.style.height=i.height.nodeValue+"px"}else{j.height=j.clientHeight}}return j}};function x(j){var i=j.srcElement;switch(j.propertyName){case"width":i.getContext().clearRect();i.style.width=i.attributes.width.nodeValue+"px";i.firstChild.style.width=i.clientWidth+"px";break;case"height":i.getContext().clearRect();i.style.height=i.attributes.height.nodeValue+"px";i.firstChild.style.height=i.clientHeight+"px";break}}function W(j){var i=j.srcElement;if(i.firstChild){i.firstChild.style.width=i.clientWidth+"px";i.firstChild.style.height=i.clientHeight+"px"}}e.init();var k=[];for(var ae=0;ae<16;ae++){for(var ad=0;ad<16;ad++){k[ae*16+ad]=ae.toString(16)+ad.toString(16)}}function B(){return[[1,0,0],[0,1,0],[0,0,1]]}function J(p,m){var j=B();for(var i=0;i<3;i++){for(var ah=0;ah<3;ah++){var Z=0;for(var ag=0;ag<3;ag++){Z+=p[i][ag]*m[ag][ah]}j[i][ah]=Z}}return j}function v(j,i){i.fillStyle=j.fillStyle;i.lineCap=j.lineCap;i.lineJoin=j.lineJoin;i.lineWidth=j.lineWidth;i.miterLimit=j.miterLimit;i.shadowBlur=j.shadowBlur;i.shadowColor=j.shadowColor;i.shadowOffsetX=j.shadowOffsetX;i.shadowOffsetY=j.shadowOffsetY;i.strokeStyle=j.strokeStyle;i.globalAlpha=j.globalAlpha;i.font=j.font;i.textAlign=j.textAlign;i.textBaseline=j.textBaseline;i.arcScaleX_=j.arcScaleX_;i.arcScaleY_=j.arcScaleY_;i.lineScale_=j.lineScale_}var b={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"};function M(j){var p=j.indexOf("(",3);var i=j.indexOf(")",p+1);var m=j.substring(p+1,i).split(",");if(m.length!=4||j.charAt(3)!="a"){m[3]=1}return m}function c(i){return parseFloat(i)/100}function r(j,m,i){return Math.min(i,Math.max(m,j))}function I(ag){var i,ai,aj,ah,ak,Z;ah=parseFloat(ag[0])/360%360;if(ah<0){ah++}ak=r(c(ag[1]),0,1);Z=r(c(ag[2]),0,1);if(ak==0){i=ai=aj=Z}else{var j=Z<0.5?Z*(1+ak):Z+ak-Z*ak;var m=2*Z-j;i=a(m,j,ah+1/3);ai=a(m,j,ah);aj=a(m,j,ah-1/3)}return"#"+k[Math.floor(i*255)]+k[Math.floor(ai*255)]+k[Math.floor(aj*255)]}function a(j,i,m){if(m<0){m++}if(m>1){m--}if(6*m<1){return j+(i-j)*6*m}else{if(2*m<1){return i}else{if(3*m<2){return j+(i-j)*(2/3-m)*6}else{return j}}}}var C={};function F(j){if(j in C){return C[j]}var ag,Z=1;j=String(j);if(j.charAt(0)=="#"){ag=j}else{if(/^rgb/.test(j)){var p=M(j);var ag="#",ah;for(var m=0;m<3;m++){if(p[m].indexOf("%")!=-1){ah=Math.floor(c(p[m])*255)}else{ah=+p[m]}ag+=k[r(ah,0,255)]}Z=+p[3]}else{if(/^hsl/.test(j)){var p=M(j);ag=I(p);Z=p[3]}else{ag=b[j]||j}}}return C[j]={color:ag,alpha:Z}}var o={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var L={};function E(i){if(L[i]){return L[i]}var p=document.createElement("div");var m=p.style;try{m.font=i}catch(j){}return L[i]={style:m.fontStyle||o.style,variant:m.fontVariant||o.variant,weight:m.fontWeight||o.weight,size:m.fontSize||o.size,family:m.fontFamily||o.family}}function u(m,j){var i={};for(var ah in m){i[ah]=m[ah]}var ag=parseFloat(j.currentStyle.fontSize),Z=parseFloat(m.size);if(typeof m.size=="number"){i.size=m.size}else{if(m.size.indexOf("px")!=-1){i.size=Z}else{if(m.size.indexOf("em")!=-1){i.size=ag*Z}else{if(m.size.indexOf("%")!=-1){i.size=(ag/100)*Z}else{if(m.size.indexOf("pt")!=-1){i.size=Z/0.75}else{i.size=ag}}}}}i.size*=0.981;return i}function ac(i){return i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family}var s={butt:"flat",round:"round"};function S(i){return s[i]||"square"}function D(i){this.m_=B();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=d*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var m="width:"+i.clientWidth+"px;height:"+i.clientHeight+"px;overflow:hidden;position:absolute";var j=i.ownerDocument.createElement("div");j.style.cssText=m;i.appendChild(j);var p=j.cloneNode(false);p.style.backgroundColor="red";p.style.filter="alpha(opacity=0)";i.appendChild(p);this.element_=j;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var q=D.prototype;q.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};q.beginPath=function(){this.currentPath_=[]};q.moveTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"moveTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.lineTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"lineTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.bezierCurveTo=function(m,j,ak,aj,ai,ag){var i=V(this,ai,ag);var ah=V(this,m,j);var Z=V(this,ak,aj);K(this,ah,Z,i)};function K(i,Z,m,j){i.currentPath_.push({type:"bezierCurveTo",cp1x:Z.x,cp1y:Z.y,cp2x:m.x,cp2y:m.y,x:j.x,y:j.y});i.currentX_=j.x;i.currentY_=j.y}q.quadraticCurveTo=function(ai,m,j,i){var ah=V(this,ai,m);var ag=V(this,j,i);var aj={x:this.currentX_+2/3*(ah.x-this.currentX_),y:this.currentY_+2/3*(ah.y-this.currentY_)};var Z={x:aj.x+(ag.x-this.currentX_)/3,y:aj.y+(ag.y-this.currentY_)/3};K(this,aj,Z,ag)};q.arc=function(al,aj,ak,ag,j,m){ak*=d;var ap=m?"at":"wa";var am=al+A(ag)*ak-f;var ao=aj+l(ag)*ak-f;var i=al+A(j)*ak-f;var an=aj+l(j)*ak-f;if(am==i&&!m){am+=0.125}var Z=V(this,al,aj);var ai=V(this,am,ao);var ah=V(this,i,an);this.currentPath_.push({type:ap,x:Z.x,y:Z.y,radius:ak,xStart:ai.x,yStart:ai.y,xEnd:ah.x,yEnd:ah.y})};q.rect=function(m,j,i,p){this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath()};q.strokeRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.stroke();this.currentPath_=Z};q.fillRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.fill();this.currentPath_=Z};q.createLinearGradient=function(j,p,i,m){var Z=new U("gradient");Z.x0_=j;Z.y0_=p;Z.x1_=i;Z.y1_=m;return Z};q.createRadialGradient=function(p,ag,m,j,Z,i){var ah=new U("gradientradial");ah.x0_=p;ah.y0_=ag;ah.r0_=m;ah.x1_=j;ah.y1_=Z;ah.r1_=i;return ah};q.drawImage=function(aq,m){var aj,ah,al,ay,ao,am,at,aA;var ak=aq.runtimeStyle.width;var ap=aq.runtimeStyle.height;aq.runtimeStyle.width="auto";aq.runtimeStyle.height="auto";var ai=aq.width;var aw=aq.height;aq.runtimeStyle.width=ak;aq.runtimeStyle.height=ap;if(arguments.length==3){aj=arguments[1];ah=arguments[2];ao=am=0;at=al=ai;aA=ay=aw}else{if(arguments.length==5){aj=arguments[1];ah=arguments[2];al=arguments[3];ay=arguments[4];ao=am=0;at=ai;aA=aw}else{if(arguments.length==9){ao=arguments[1];am=arguments[2];at=arguments[3];aA=arguments[4];aj=arguments[5];ah=arguments[6];al=arguments[7];ay=arguments[8]}else{throw Error("Invalid number of arguments")}}}var az=V(this,aj,ah);var p=at/2;var j=aA/2;var ax=[];var i=10;var ag=10;ax.push(" <g_vml_:group",' coordsize="',d*i,",",d*ag,'"',' coordorigin="0,0"',' style="width:',i,"px;height:",ag,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var Z=[];Z.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",n(az.x/d),",","Dy=",n(az.y/d),"");var av=az;var au=V(this,aj+al,ah);var ar=V(this,aj,ah+ay);var an=V(this,aj+al,ah+ay);av.x=ab.max(av.x,au.x,ar.x,an.x);av.y=ab.max(av.y,au.y,ar.y,an.y);ax.push("padding:0 ",n(av.x/d),"px ",n(av.y/d),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",Z.join(""),", sizingmethod='clip');")}else{ax.push("top:",n(az.y/d),"px;left:",n(az.x/d),"px;")}ax.push(' ">','<g_vml_:image src="',aq.src,'"',' style="width:',d*al,"px;"," height:",d*ay,'px"',' cropleft="',ao/ai,'"',' croptop="',am/aw,'"',' cropright="',(ai-ao-at)/ai,'"',' cropbottom="',(aw-am-aA)/aw,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",ax.join(""))};q.stroke=function(ao){var Z=10;var ap=10;var ag=5000;var ai={x:null,y:null};var an={x:null,y:null};for(var aj=0;aj<this.currentPath_.length;aj+=ag){var am=[];var ah=false;am.push("<g_vml_:shape",' filled="',!!ao,'"',' style="position:absolute;width:',Z,"px;height:",ap,'px;"',' coordorigin="0,0"',' coordsize="',d*Z,",",d*ap,'"',' stroked="',!ao,'"',' path="');var aq=false;for(var ak=aj;ak<Math.min(aj+ag,this.currentPath_.length);ak++){if(ak%ag==0&&ak>0){am.push(" m ",n(this.currentPath_[ak-1].x),",",n(this.currentPath_[ak-1].y))}var m=this.currentPath_[ak];var al;switch(m.type){case"moveTo":al=m;am.push(" m ",n(m.x),",",n(m.y));break;case"lineTo":am.push(" l ",n(m.x),",",n(m.y));break;case"close":am.push(" x ");m=null;break;case"bezierCurveTo":am.push(" c ",n(m.cp1x),",",n(m.cp1y),",",n(m.cp2x),",",n(m.cp2y),",",n(m.x),",",n(m.y));break;case"at":case"wa":am.push(" ",m.type," ",n(m.x-this.arcScaleX_*m.radius),",",n(m.y-this.arcScaleY_*m.radius)," ",n(m.x+this.arcScaleX_*m.radius),",",n(m.y+this.arcScaleY_*m.radius)," ",n(m.xStart),",",n(m.yStart)," ",n(m.xEnd),",",n(m.yEnd));break}if(m){if(ai.x==null||m.x<ai.x){ai.x=m.x}if(an.x==null||m.x>an.x){an.x=m.x}if(ai.y==null||m.y<ai.y){ai.y=m.y}if(an.y==null||m.y>an.y){an.y=m.y}}}am.push(' ">');if(!ao){w(this,am)}else{G(this,am,ai,an)}am.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",am.join(""))}};function w(m,ag){var j=F(m.strokeStyle);var p=j.color;var Z=j.alpha*m.globalAlpha;var i=m.lineScale_*m.lineWidth;if(i<1){Z*=i}ag.push("<g_vml_:stroke",' opacity="',Z,'"',' joinstyle="',m.lineJoin,'"',' miterlimit="',m.miterLimit,'"',' endcap="',S(m.lineCap),'"',' weight="',i,'px"',' color="',p,'" />')}function G(aq,ai,aK,ar){var aj=aq.fillStyle;var aB=aq.arcScaleX_;var aA=aq.arcScaleY_;var j=ar.x-aK.x;var p=ar.y-aK.y;if(aj instanceof U){var an=0;var aF={x:0,y:0};var ax=0;var am=1;if(aj.type_=="gradient"){var al=aj.x0_/aB;var m=aj.y0_/aA;var ak=aj.x1_/aB;var aM=aj.y1_/aA;var aJ=V(aq,al,m);var aI=V(aq,ak,aM);var ag=aI.x-aJ.x;var Z=aI.y-aJ.y;an=Math.atan2(ag,Z)*180/Math.PI;if(an<0){an+=360}if(an<0.000001){an=0}}else{var aJ=V(aq,aj.x0_,aj.y0_);aF={x:(aJ.x-aK.x)/j,y:(aJ.y-aK.y)/p};j/=aB*d;p/=aA*d;var aD=ab.max(j,p);ax=2*aj.r0_/aD;am=2*aj.r1_/aD-ax}var av=aj.colors_;av.sort(function(aN,i){return aN.offset-i.offset});var ap=av.length;var au=av[0].color;var at=av[ap-1].color;var az=av[0].alpha*aq.globalAlpha;var ay=av[ap-1].alpha*aq.globalAlpha;var aE=[];for(var aH=0;aH<ap;aH++){var ao=av[aH];aE.push(ao.offset*am+ax+" "+ao.color)}ai.push('<g_vml_:fill type="',aj.type_,'"',' method="none" focus="100%"',' color="',au,'"',' color2="',at,'"',' colors="',aE.join(","),'"',' opacity="',ay,'"',' g_o_:opacity2="',az,'"',' angle="',an,'"',' focusposition="',aF.x,",",aF.y,'" />')}else{if(aj instanceof T){if(j&&p){var ah=-aK.x;var aC=-aK.y;ai.push("<g_vml_:fill",' position="',ah/j*aB*aB,",",aC/p*aA*aA,'"',' type="tile"',' src="',aj.src_,'" />')}}else{var aL=F(aq.fillStyle);var aw=aL.color;var aG=aL.alpha*aq.globalAlpha;ai.push('<g_vml_:fill color="',aw,'" opacity="',aG,'" />')}}}q.fill=function(){this.stroke(true)};q.closePath=function(){this.currentPath_.push({type:"close"})};function V(j,Z,p){var i=j.m_;return{x:d*(Z*i[0][0]+p*i[1][0]+i[2][0])-f,y:d*(Z*i[0][1]+p*i[1][1]+i[2][1])-f}}q.save=function(){var i={};v(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=J(B(),this.m_)};q.restore=function(){if(this.aStack_.length){v(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function h(i){return isFinite(i[0][0])&&isFinite(i[0][1])&&isFinite(i[1][0])&&isFinite(i[1][1])&&isFinite(i[2][0])&&isFinite(i[2][1])}function aa(j,i,p){if(!h(i)){return}j.m_=i;if(p){var Z=i[0][0]*i[1][1]-i[0][1]*i[1][0];j.lineScale_=N(H(Z))}}q.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];aa(this,J(i,this.m_),false)};q.rotate=function(j){var p=A(j);var m=l(j);var i=[[p,m,0],[-m,p,0],[0,0,1]];aa(this,J(i,this.m_),false)};q.scale=function(m,j){this.arcScaleX_*=m;this.arcScaleY_*=j;var i=[[m,0,0],[0,j,0],[0,0,1]];aa(this,J(i,this.m_),true)};q.transform=function(Z,p,ah,ag,j,i){var m=[[Z,p,0],[ah,ag,0],[j,i,1]];aa(this,J(m,this.m_),true)};q.setTransform=function(ag,Z,ai,ah,p,j){var i=[[ag,Z,0],[ai,ah,0],[p,j,1]];aa(this,i,true)};q.drawText_=function(am,ak,aj,ap,ai){var ao=this.m_,at=1000,j=0,ar=at,ah={x:0,y:0},ag=[];var i=u(E(this.font),this.element_);var p=ac(i);var au=this.element_.currentStyle;var Z=this.textAlign.toLowerCase();switch(Z){case"left":case"center":case"right":break;case"end":Z=au.direction=="ltr"?"right":"left";break;case"start":Z=au.direction=="rtl"?"right":"left";break;default:Z="left"}switch(this.textBaseline){case"hanging":case"top":ah.y=i.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":ah.y=-i.size/2.25;break}switch(Z){case"right":j=at;ar=0.05;break;case"center":j=ar=at/2;break}var aq=V(this,ak+ah.x,aj+ah.y);ag.push('<g_vml_:line from="',-j,' 0" to="',ar,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!ai,'" stroked="',!!ai,'" style="position:absolute;width:1px;height:1px;">');if(ai){w(this,ag)}else{G(this,ag,{x:-j,y:0},{x:ar,y:i.size})}var an=ao[0][0].toFixed(3)+","+ao[1][0].toFixed(3)+","+ao[0][1].toFixed(3)+","+ao[1][1].toFixed(3)+",0,0";var al=n(aq.x/d)+","+n(aq.y/d);ag.push('<g_vml_:skew on="t" matrix="',an,'" ',' offset="',al,'" origin="',j,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',af(am),'" style="v-text-align:',Z,";font:",af(p),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",ag.join(""))};q.fillText=function(m,i,p,j){this.drawText_(m,i,p,j,false)};q.strokeText=function(m,i,p,j){this.drawText_(m,i,p,j,true)};q.measureText=function(m){if(!this.textMeasureEl_){var i='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",i);this.textMeasureEl_=this.element_.lastChild}var j=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(j.createTextNode(m));return{width:this.textMeasureEl_.offsetWidth}};q.clip=function(){};q.arcTo=function(){};q.createPattern=function(j,i){return new T(j,i)};function U(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}U.prototype.addColorStop=function(j,i){i=F(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function T(j,i){Q(j);switch(i){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=i;break;default:O("SYNTAX_ERR")}this.src_=j.src;this.width_=j.width;this.height_=j.height}function O(i){throw new P(i)}function Q(i){if(!i||i.nodeType!=1||i.tagName!="IMG"){O("TYPE_MISMATCH_ERR")}if(i.readyState!="complete"){O("INVALID_STATE_ERR")}}function P(i){this.code=this[i];this.message=i+": DOM Exception "+this.code}var X=P.prototype=new Error;X.INDEX_SIZE_ERR=1;X.DOMSTRING_SIZE_ERR=2;X.HIERARCHY_REQUEST_ERR=3;X.WRONG_DOCUMENT_ERR=4;X.INVALID_CHARACTER_ERR=5;X.NO_DATA_ALLOWED_ERR=6;X.NO_MODIFICATION_ALLOWED_ERR=7;X.NOT_FOUND_ERR=8;X.NOT_SUPPORTED_ERR=9;X.INUSE_ATTRIBUTE_ERR=10;X.INVALID_STATE_ERR=11;X.SYNTAX_ERR=12;X.INVALID_MODIFICATION_ERR=13;X.NAMESPACE_ERR=14;X.INVALID_ACCESS_ERR=15;X.VALIDATION_ERR=16;X.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=e;CanvasRenderingContext2D=D;CanvasGradient=U;CanvasPattern=T;DOMException=P})()};
|
@@ -1,16 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
/* Javascript plotting library for jQuery, version 0.8.2.
|
2
|
+
|
3
|
+
Copyright (c) 2007-2013 IOLA and Ole Laursen.
|
4
|
+
Licensed under the MIT license.
|
5
|
+
|
6
|
+
*/
|
6
7
|
|
7
8
|
// first an inline dependency, jquery.colorhelpers.js, we inline it here
|
8
9
|
// for convenience
|
9
10
|
|
10
11
|
/* Plugin for jQuery for working with colors.
|
11
|
-
*
|
12
|
+
*
|
12
13
|
* Version 1.1.
|
13
|
-
*
|
14
|
+
*
|
14
15
|
* Inspiration from jQuery color animation plugin by John Resig.
|
15
16
|
*
|
16
17
|
* Released under the MIT license by Ole Laursen, October 2009.
|
@@ -27,17 +28,473 @@
|
|
27
28
|
*
|
28
29
|
* V. 1.1: Fix error handling so e.g. parsing an empty string does
|
29
30
|
* produce a color rather than just crashing.
|
30
|
-
*/
|
31
|
-
(function(
|
31
|
+
*/
|
32
|
+
(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/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(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/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(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={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);
|
32
33
|
|
33
34
|
// the actual Flot code
|
34
35
|
(function($) {
|
36
|
+
|
37
|
+
// Cache the prototype hasOwnProperty for faster access
|
38
|
+
|
39
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
40
|
+
|
41
|
+
///////////////////////////////////////////////////////////////////////////
|
42
|
+
// The Canvas object is a wrapper around an HTML5 <canvas> tag.
|
43
|
+
//
|
44
|
+
// @constructor
|
45
|
+
// @param {string} cls List of classes to apply to the canvas.
|
46
|
+
// @param {element} container Element onto which to append the canvas.
|
47
|
+
//
|
48
|
+
// Requiring a container is a little iffy, but unfortunately canvas
|
49
|
+
// operations don't work unless the canvas is attached to the DOM.
|
50
|
+
|
51
|
+
function Canvas(cls, container) {
|
52
|
+
|
53
|
+
var element = container.children("." + cls)[0];
|
54
|
+
|
55
|
+
if (element == null) {
|
56
|
+
|
57
|
+
element = document.createElement("canvas");
|
58
|
+
element.className = cls;
|
59
|
+
|
60
|
+
$(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 })
|
61
|
+
.appendTo(container);
|
62
|
+
|
63
|
+
// If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas
|
64
|
+
|
65
|
+
if (!element.getContext) {
|
66
|
+
if (window.G_vmlCanvasManager) {
|
67
|
+
element = window.G_vmlCanvasManager.initElement(element);
|
68
|
+
} else {
|
69
|
+
throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
this.element = element;
|
75
|
+
|
76
|
+
var context = this.context = element.getContext("2d");
|
77
|
+
|
78
|
+
// Determine the screen's ratio of physical to device-independent
|
79
|
+
// pixels. This is the ratio between the canvas width that the browser
|
80
|
+
// advertises and the number of pixels actually present in that space.
|
81
|
+
|
82
|
+
// The iPhone 4, for example, has a device-independent width of 320px,
|
83
|
+
// but its screen is actually 640px wide. It therefore has a pixel
|
84
|
+
// ratio of 2, while most normal devices have a ratio of 1.
|
85
|
+
|
86
|
+
var devicePixelRatio = window.devicePixelRatio || 1,
|
87
|
+
backingStoreRatio =
|
88
|
+
context.webkitBackingStorePixelRatio ||
|
89
|
+
context.mozBackingStorePixelRatio ||
|
90
|
+
context.msBackingStorePixelRatio ||
|
91
|
+
context.oBackingStorePixelRatio ||
|
92
|
+
context.backingStorePixelRatio || 1;
|
93
|
+
|
94
|
+
this.pixelRatio = devicePixelRatio / backingStoreRatio;
|
95
|
+
|
96
|
+
// Size the canvas to match the internal dimensions of its container
|
97
|
+
|
98
|
+
this.resize(container.width(), container.height());
|
99
|
+
|
100
|
+
// Collection of HTML div layers for text overlaid onto the canvas
|
101
|
+
|
102
|
+
this.textContainer = null;
|
103
|
+
this.text = {};
|
104
|
+
|
105
|
+
// Cache of text fragments and metrics, so we can avoid expensively
|
106
|
+
// re-calculating them when the plot is re-rendered in a loop.
|
107
|
+
|
108
|
+
this._textCache = {};
|
109
|
+
}
|
110
|
+
|
111
|
+
// Resizes the canvas to the given dimensions.
|
112
|
+
//
|
113
|
+
// @param {number} width New width of the canvas, in pixels.
|
114
|
+
// @param {number} width New height of the canvas, in pixels.
|
115
|
+
|
116
|
+
Canvas.prototype.resize = function(width, height) {
|
117
|
+
|
118
|
+
if (width <= 0 || height <= 0) {
|
119
|
+
throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height);
|
120
|
+
}
|
121
|
+
|
122
|
+
var element = this.element,
|
123
|
+
context = this.context,
|
124
|
+
pixelRatio = this.pixelRatio;
|
125
|
+
|
126
|
+
// Resize the canvas, increasing its density based on the display's
|
127
|
+
// pixel ratio; basically giving it more pixels without increasing the
|
128
|
+
// size of its element, to take advantage of the fact that retina
|
129
|
+
// displays have that many more pixels in the same advertised space.
|
130
|
+
|
131
|
+
// Resizing should reset the state (excanvas seems to be buggy though)
|
132
|
+
|
133
|
+
if (this.width != width) {
|
134
|
+
element.width = width * pixelRatio;
|
135
|
+
element.style.width = width + "px";
|
136
|
+
this.width = width;
|
137
|
+
}
|
138
|
+
|
139
|
+
if (this.height != height) {
|
140
|
+
element.height = height * pixelRatio;
|
141
|
+
element.style.height = height + "px";
|
142
|
+
this.height = height;
|
143
|
+
}
|
144
|
+
|
145
|
+
// Save the context, so we can reset in case we get replotted. The
|
146
|
+
// restore ensure that we're really back at the initial state, and
|
147
|
+
// should be safe even if we haven't saved the initial state yet.
|
148
|
+
|
149
|
+
context.restore();
|
150
|
+
context.save();
|
151
|
+
|
152
|
+
// Scale the coordinate space to match the display density; so even though we
|
153
|
+
// may have twice as many pixels, we still want lines and other drawing to
|
154
|
+
// appear at the same size; the extra pixels will just make them crisper.
|
155
|
+
|
156
|
+
context.scale(pixelRatio, pixelRatio);
|
157
|
+
};
|
158
|
+
|
159
|
+
// Clears the entire canvas area, not including any overlaid HTML text
|
160
|
+
|
161
|
+
Canvas.prototype.clear = function() {
|
162
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
163
|
+
};
|
164
|
+
|
165
|
+
// Finishes rendering the canvas, including managing the text overlay.
|
166
|
+
|
167
|
+
Canvas.prototype.render = function() {
|
168
|
+
|
169
|
+
var cache = this._textCache;
|
170
|
+
|
171
|
+
// For each text layer, add elements marked as active that haven't
|
172
|
+
// already been rendered, and remove those that are no longer active.
|
173
|
+
|
174
|
+
for (var layerKey in cache) {
|
175
|
+
if (hasOwnProperty.call(cache, layerKey)) {
|
176
|
+
|
177
|
+
var layer = this.getTextLayer(layerKey),
|
178
|
+
layerCache = cache[layerKey];
|
179
|
+
|
180
|
+
layer.hide();
|
181
|
+
|
182
|
+
for (var styleKey in layerCache) {
|
183
|
+
if (hasOwnProperty.call(layerCache, styleKey)) {
|
184
|
+
var styleCache = layerCache[styleKey];
|
185
|
+
for (var key in styleCache) {
|
186
|
+
if (hasOwnProperty.call(styleCache, key)) {
|
187
|
+
|
188
|
+
var positions = styleCache[key].positions;
|
189
|
+
|
190
|
+
for (var i = 0, position; position = positions[i]; i++) {
|
191
|
+
if (position.active) {
|
192
|
+
if (!position.rendered) {
|
193
|
+
layer.append(position.element);
|
194
|
+
position.rendered = true;
|
195
|
+
}
|
196
|
+
} else {
|
197
|
+
positions.splice(i--, 1);
|
198
|
+
if (position.rendered) {
|
199
|
+
position.element.detach();
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
if (positions.length == 0) {
|
205
|
+
delete styleCache[key];
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
layer.show();
|
213
|
+
}
|
214
|
+
}
|
215
|
+
};
|
216
|
+
|
217
|
+
// Creates (if necessary) and returns the text overlay container.
|
218
|
+
//
|
219
|
+
// @param {string} classes String of space-separated CSS classes used to
|
220
|
+
// uniquely identify the text layer.
|
221
|
+
// @return {object} The jQuery-wrapped text-layer div.
|
222
|
+
|
223
|
+
Canvas.prototype.getTextLayer = function(classes) {
|
224
|
+
|
225
|
+
var layer = this.text[classes];
|
226
|
+
|
227
|
+
// Create the text layer if it doesn't exist
|
228
|
+
|
229
|
+
if (layer == null) {
|
230
|
+
|
231
|
+
// Create the text layer container, if it doesn't exist
|
232
|
+
|
233
|
+
if (this.textContainer == null) {
|
234
|
+
this.textContainer = $("<div class='flot-text'></div>")
|
235
|
+
.css({
|
236
|
+
position: "absolute",
|
237
|
+
top: 0,
|
238
|
+
left: 0,
|
239
|
+
bottom: 0,
|
240
|
+
right: 0,
|
241
|
+
'font-size': "smaller",
|
242
|
+
color: "#545454"
|
243
|
+
})
|
244
|
+
.insertAfter(this.element);
|
245
|
+
}
|
246
|
+
|
247
|
+
layer = this.text[classes] = $("<div></div>")
|
248
|
+
.addClass(classes)
|
249
|
+
.css({
|
250
|
+
position: "absolute",
|
251
|
+
top: 0,
|
252
|
+
left: 0,
|
253
|
+
bottom: 0,
|
254
|
+
right: 0
|
255
|
+
})
|
256
|
+
.appendTo(this.textContainer);
|
257
|
+
}
|
258
|
+
|
259
|
+
return layer;
|
260
|
+
};
|
261
|
+
|
262
|
+
// Creates (if necessary) and returns a text info object.
|
263
|
+
//
|
264
|
+
// The object looks like this:
|
265
|
+
//
|
266
|
+
// {
|
267
|
+
// width: Width of the text's wrapper div.
|
268
|
+
// height: Height of the text's wrapper div.
|
269
|
+
// element: The jQuery-wrapped HTML div containing the text.
|
270
|
+
// positions: Array of positions at which this text is drawn.
|
271
|
+
// }
|
272
|
+
//
|
273
|
+
// The positions array contains objects that look like this:
|
274
|
+
//
|
275
|
+
// {
|
276
|
+
// active: Flag indicating whether the text should be visible.
|
277
|
+
// rendered: Flag indicating whether the text is currently visible.
|
278
|
+
// element: The jQuery-wrapped HTML div containing the text.
|
279
|
+
// x: X coordinate at which to draw the text.
|
280
|
+
// y: Y coordinate at which to draw the text.
|
281
|
+
// }
|
282
|
+
//
|
283
|
+
// Each position after the first receives a clone of the original element.
|
284
|
+
//
|
285
|
+
// The idea is that that the width, height, and general 'identity' of the
|
286
|
+
// text is constant no matter where it is placed; the placements are a
|
287
|
+
// secondary property.
|
288
|
+
//
|
289
|
+
// Canvas maintains a cache of recently-used text info objects; getTextInfo
|
290
|
+
// either returns the cached element or creates a new entry.
|
291
|
+
//
|
292
|
+
// @param {string} layer A string of space-separated CSS classes uniquely
|
293
|
+
// identifying the layer containing this text.
|
294
|
+
// @param {string} text Text string to retrieve info for.
|
295
|
+
// @param {(string|object)=} font Either a string of space-separated CSS
|
296
|
+
// classes or a font-spec object, defining the text's font and style.
|
297
|
+
// @param {number=} angle Angle at which to rotate the text, in degrees.
|
298
|
+
// Angle is currently unused, it will be implemented in the future.
|
299
|
+
// @param {number=} width Maximum width of the text before it wraps.
|
300
|
+
// @return {object} a text info object.
|
301
|
+
|
302
|
+
Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
|
303
|
+
|
304
|
+
var textStyle, layerCache, styleCache, info;
|
305
|
+
|
306
|
+
// Cast the value to a string, in case we were given a number or such
|
307
|
+
|
308
|
+
text = "" + text;
|
309
|
+
|
310
|
+
// If the font is a font-spec object, generate a CSS font definition
|
311
|
+
|
312
|
+
if (typeof font === "object") {
|
313
|
+
textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family;
|
314
|
+
} else {
|
315
|
+
textStyle = font;
|
316
|
+
}
|
317
|
+
|
318
|
+
// Retrieve (or create) the cache for the text's layer and styles
|
319
|
+
|
320
|
+
layerCache = this._textCache[layer];
|
321
|
+
|
322
|
+
if (layerCache == null) {
|
323
|
+
layerCache = this._textCache[layer] = {};
|
324
|
+
}
|
325
|
+
|
326
|
+
styleCache = layerCache[textStyle];
|
327
|
+
|
328
|
+
if (styleCache == null) {
|
329
|
+
styleCache = layerCache[textStyle] = {};
|
330
|
+
}
|
331
|
+
|
332
|
+
info = styleCache[text];
|
333
|
+
|
334
|
+
// If we can't find a matching element in our cache, create a new one
|
335
|
+
|
336
|
+
if (info == null) {
|
337
|
+
|
338
|
+
var element = $("<div></div>").html(text)
|
339
|
+
.css({
|
340
|
+
position: "absolute",
|
341
|
+
'max-width': width,
|
342
|
+
top: -9999
|
343
|
+
})
|
344
|
+
.appendTo(this.getTextLayer(layer));
|
345
|
+
|
346
|
+
if (typeof font === "object") {
|
347
|
+
element.css({
|
348
|
+
font: textStyle,
|
349
|
+
color: font.color
|
350
|
+
});
|
351
|
+
} else if (typeof font === "string") {
|
352
|
+
element.addClass(font);
|
353
|
+
}
|
354
|
+
|
355
|
+
info = styleCache[text] = {
|
356
|
+
width: element.outerWidth(true),
|
357
|
+
height: element.outerHeight(true),
|
358
|
+
element: element,
|
359
|
+
positions: []
|
360
|
+
};
|
361
|
+
|
362
|
+
element.detach();
|
363
|
+
}
|
364
|
+
|
365
|
+
return info;
|
366
|
+
};
|
367
|
+
|
368
|
+
// Adds a text string to the canvas text overlay.
|
369
|
+
//
|
370
|
+
// The text isn't drawn immediately; it is marked as rendering, which will
|
371
|
+
// result in its addition to the canvas on the next render pass.
|
372
|
+
//
|
373
|
+
// @param {string} layer A string of space-separated CSS classes uniquely
|
374
|
+
// identifying the layer containing this text.
|
375
|
+
// @param {number} x X coordinate at which to draw the text.
|
376
|
+
// @param {number} y Y coordinate at which to draw the text.
|
377
|
+
// @param {string} text Text string to draw.
|
378
|
+
// @param {(string|object)=} font Either a string of space-separated CSS
|
379
|
+
// classes or a font-spec object, defining the text's font and style.
|
380
|
+
// @param {number=} angle Angle at which to rotate the text, in degrees.
|
381
|
+
// Angle is currently unused, it will be implemented in the future.
|
382
|
+
// @param {number=} width Maximum width of the text before it wraps.
|
383
|
+
// @param {string=} halign Horizontal alignment of the text; either "left",
|
384
|
+
// "center" or "right".
|
385
|
+
// @param {string=} valign Vertical alignment of the text; either "top",
|
386
|
+
// "middle" or "bottom".
|
387
|
+
|
388
|
+
Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {
|
389
|
+
|
390
|
+
var info = this.getTextInfo(layer, text, font, angle, width),
|
391
|
+
positions = info.positions;
|
392
|
+
|
393
|
+
// Tweak the div's position to match the text's alignment
|
394
|
+
|
395
|
+
if (halign == "center") {
|
396
|
+
x -= info.width / 2;
|
397
|
+
} else if (halign == "right") {
|
398
|
+
x -= info.width;
|
399
|
+
}
|
400
|
+
|
401
|
+
if (valign == "middle") {
|
402
|
+
y -= info.height / 2;
|
403
|
+
} else if (valign == "bottom") {
|
404
|
+
y -= info.height;
|
405
|
+
}
|
406
|
+
|
407
|
+
// Determine whether this text already exists at this position.
|
408
|
+
// If so, mark it for inclusion in the next render pass.
|
409
|
+
|
410
|
+
for (var i = 0, position; position = positions[i]; i++) {
|
411
|
+
if (position.x == x && position.y == y) {
|
412
|
+
position.active = true;
|
413
|
+
return;
|
414
|
+
}
|
415
|
+
}
|
416
|
+
|
417
|
+
// If the text doesn't exist at this position, create a new entry
|
418
|
+
|
419
|
+
// For the very first position we'll re-use the original element,
|
420
|
+
// while for subsequent ones we'll clone it.
|
421
|
+
|
422
|
+
position = {
|
423
|
+
active: true,
|
424
|
+
rendered: false,
|
425
|
+
element: positions.length ? info.element.clone() : info.element,
|
426
|
+
x: x,
|
427
|
+
y: y
|
428
|
+
};
|
429
|
+
|
430
|
+
positions.push(position);
|
431
|
+
|
432
|
+
// Move the element to its final position within the container
|
433
|
+
|
434
|
+
position.element.css({
|
435
|
+
top: Math.round(y),
|
436
|
+
left: Math.round(x),
|
437
|
+
'text-align': halign // In case the text wraps
|
438
|
+
});
|
439
|
+
};
|
440
|
+
|
441
|
+
// Removes one or more text strings from the canvas text overlay.
|
442
|
+
//
|
443
|
+
// If no parameters are given, all text within the layer is removed.
|
444
|
+
//
|
445
|
+
// Note that the text is not immediately removed; it is simply marked as
|
446
|
+
// inactive, which will result in its removal on the next render pass.
|
447
|
+
// This avoids the performance penalty for 'clear and redraw' behavior,
|
448
|
+
// where we potentially get rid of all text on a layer, but will likely
|
449
|
+
// add back most or all of it later, as when redrawing axes, for example.
|
450
|
+
//
|
451
|
+
// @param {string} layer A string of space-separated CSS classes uniquely
|
452
|
+
// identifying the layer containing this text.
|
453
|
+
// @param {number=} x X coordinate of the text.
|
454
|
+
// @param {number=} y Y coordinate of the text.
|
455
|
+
// @param {string=} text Text string to remove.
|
456
|
+
// @param {(string|object)=} font Either a string of space-separated CSS
|
457
|
+
// classes or a font-spec object, defining the text's font and style.
|
458
|
+
// @param {number=} angle Angle at which the text is rotated, in degrees.
|
459
|
+
// Angle is currently unused, it will be implemented in the future.
|
460
|
+
|
461
|
+
Canvas.prototype.removeText = function(layer, x, y, text, font, angle) {
|
462
|
+
if (text == null) {
|
463
|
+
var layerCache = this._textCache[layer];
|
464
|
+
if (layerCache != null) {
|
465
|
+
for (var styleKey in layerCache) {
|
466
|
+
if (hasOwnProperty.call(layerCache, styleKey)) {
|
467
|
+
var styleCache = layerCache[styleKey];
|
468
|
+
for (var key in styleCache) {
|
469
|
+
if (hasOwnProperty.call(styleCache, key)) {
|
470
|
+
var positions = styleCache[key].positions;
|
471
|
+
for (var i = 0, position; position = positions[i]; i++) {
|
472
|
+
position.active = false;
|
473
|
+
}
|
474
|
+
}
|
475
|
+
}
|
476
|
+
}
|
477
|
+
}
|
478
|
+
}
|
479
|
+
} else {
|
480
|
+
var positions = this.getTextInfo(layer, text, font, angle).positions;
|
481
|
+
for (var i = 0, position; position = positions[i]; i++) {
|
482
|
+
if (position.x == x && position.y == y) {
|
483
|
+
position.active = false;
|
484
|
+
}
|
485
|
+
}
|
486
|
+
}
|
487
|
+
};
|
488
|
+
|
489
|
+
///////////////////////////////////////////////////////////////////////////
|
490
|
+
// The top-level container for the entire plot.
|
491
|
+
|
35
492
|
function Plot(placeholder, data_, options_, plugins) {
|
36
493
|
// data is on the form:
|
37
494
|
// [ series1, series2 ... ]
|
38
495
|
// where series is either just the data as [ [x1, y1], [x2, y2], ... ]
|
39
496
|
// or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
|
40
|
-
|
497
|
+
|
41
498
|
var series = [],
|
42
499
|
options = {
|
43
500
|
// the color theme used for graphs
|
@@ -51,12 +508,14 @@
|
|
51
508
|
position: "ne", // position of default legend container within plot
|
52
509
|
margin: 5, // distance from grid edge to default legend container within plot
|
53
510
|
backgroundColor: null, // null means auto-detect
|
54
|
-
backgroundOpacity: 0.85 // set to 0 to avoid background
|
511
|
+
backgroundOpacity: 0.85, // set to 0 to avoid background
|
512
|
+
sorted: null // default to no legend sorting
|
55
513
|
},
|
56
514
|
xaxis: {
|
57
515
|
show: null, // null = auto-detect, true = always, false = never
|
58
516
|
position: "bottom", // or "top"
|
59
517
|
mode: null, // null or "time"
|
518
|
+
font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" }
|
60
519
|
color: null, // base color, labels, ticks
|
61
520
|
tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
|
62
521
|
transform: null, // null or f: number -> number to transform axis
|
@@ -71,14 +530,9 @@
|
|
71
530
|
reserveSpace: null, // whether to reserve space even if axis isn't shown
|
72
531
|
tickLength: null, // size in pixels of ticks, or "full" for whole line
|
73
532
|
alignTicksWithAxis: null, // axis number or null for no sync
|
74
|
-
|
75
|
-
// mode specific options
|
76
533
|
tickDecimals: null, // no. of decimals, null means auto
|
77
534
|
tickSize: null, // number or [number, "unit"]
|
78
|
-
minTickSize: null
|
79
|
-
monthNames: null, // list of names of months
|
80
|
-
timeformat: null, // format string to use
|
81
|
-
twelveHourClock: false // 12 or 24 time in time mode
|
535
|
+
minTickSize: null // number or [number, "unit"]
|
82
536
|
},
|
83
537
|
yaxis: {
|
84
538
|
autoscaleMargin: 0.02,
|
@@ -97,11 +551,13 @@
|
|
97
551
|
},
|
98
552
|
lines: {
|
99
553
|
// we don't put in show: false so we can see
|
100
|
-
// whether lines were actively disabled
|
554
|
+
// whether lines were actively disabled
|
101
555
|
lineWidth: 2, // in pixels
|
102
556
|
fill: false,
|
103
557
|
fillColor: null,
|
104
558
|
steps: false
|
559
|
+
// Omit 'zero', so we can later default its value to
|
560
|
+
// match that of the 'fill' option.
|
105
561
|
},
|
106
562
|
bars: {
|
107
563
|
show: false,
|
@@ -109,10 +565,12 @@
|
|
109
565
|
barWidth: 1, // in units of the x axis
|
110
566
|
fill: true,
|
111
567
|
fillColor: null,
|
112
|
-
align: "left", // or "center"
|
113
|
-
horizontal: false
|
568
|
+
align: "left", // "left", "right", or "center"
|
569
|
+
horizontal: false,
|
570
|
+
zero: true
|
114
571
|
},
|
115
|
-
shadowSize: 3
|
572
|
+
shadowSize: 3,
|
573
|
+
highlightColor: null
|
116
574
|
},
|
117
575
|
grid: {
|
118
576
|
show: true,
|
@@ -121,6 +579,7 @@
|
|
121
579
|
backgroundColor: null, // null for transparent, else color
|
122
580
|
borderColor: null, // set if different from the grid color
|
123
581
|
tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
|
582
|
+
margin: 0, // distance from the canvas edge to the grid
|
124
583
|
labelMargin: 5, // in pixels
|
125
584
|
axisMargin: 8, // in pixels
|
126
585
|
borderWidth: 2, // in pixels
|
@@ -134,20 +593,24 @@
|
|
134
593
|
autoHighlight: true, // highlight in case mouse is near
|
135
594
|
mouseActiveRadius: 10 // how far the mouse can be away to activate an item
|
136
595
|
},
|
596
|
+
interaction: {
|
597
|
+
redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow
|
598
|
+
},
|
137
599
|
hooks: {}
|
138
600
|
},
|
139
|
-
|
601
|
+
surface = null, // the canvas for the plot itself
|
140
602
|
overlay = null, // canvas for interactive stuff on top of plot
|
141
603
|
eventHolder = null, // jQuery object that events should be bound to
|
142
604
|
ctx = null, octx = null,
|
143
605
|
xaxes = [], yaxes = [],
|
144
606
|
plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
|
145
|
-
canvasWidth = 0, canvasHeight = 0,
|
146
607
|
plotWidth = 0, plotHeight = 0,
|
147
608
|
hooks = {
|
148
609
|
processOptions: [],
|
149
610
|
processRawData: [],
|
150
611
|
processDatapoints: [],
|
612
|
+
processOffset: [],
|
613
|
+
drawBackground: [],
|
151
614
|
drawSeries: [],
|
152
615
|
draw: [],
|
153
616
|
bindEvents: [],
|
@@ -161,7 +624,7 @@
|
|
161
624
|
plot.setupGrid = setupGrid;
|
162
625
|
plot.draw = draw;
|
163
626
|
plot.getPlaceholder = function() { return placeholder; };
|
164
|
-
plot.getCanvas = function() { return
|
627
|
+
plot.getCanvas = function() { return surface.element; };
|
165
628
|
plot.getPlotOffset = function() { return plotOffset; };
|
166
629
|
plot.width = function () { return plotWidth; };
|
167
630
|
plot.height = function () { return plotHeight; };
|
@@ -190,20 +653,38 @@
|
|
190
653
|
plot.triggerRedrawOverlay = triggerRedrawOverlay;
|
191
654
|
plot.pointOffset = function(point) {
|
192
655
|
return {
|
193
|
-
left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left),
|
194
|
-
top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top)
|
656
|
+
left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10),
|
657
|
+
top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10)
|
195
658
|
};
|
196
659
|
};
|
197
660
|
plot.shutdown = shutdown;
|
661
|
+
plot.destroy = function () {
|
662
|
+
shutdown();
|
663
|
+
placeholder.removeData("plot").empty();
|
664
|
+
|
665
|
+
series = [];
|
666
|
+
options = null;
|
667
|
+
surface = null;
|
668
|
+
overlay = null;
|
669
|
+
eventHolder = null;
|
670
|
+
ctx = null;
|
671
|
+
octx = null;
|
672
|
+
xaxes = [];
|
673
|
+
yaxes = [];
|
674
|
+
hooks = null;
|
675
|
+
highlights = [];
|
676
|
+
plot = null;
|
677
|
+
};
|
198
678
|
plot.resize = function () {
|
199
|
-
|
200
|
-
|
201
|
-
|
679
|
+
var width = placeholder.width(),
|
680
|
+
height = placeholder.height();
|
681
|
+
surface.resize(width, height);
|
682
|
+
overlay.resize(width, height);
|
202
683
|
};
|
203
684
|
|
204
685
|
// public attributes
|
205
686
|
plot.hooks = hooks;
|
206
|
-
|
687
|
+
|
207
688
|
// initialize
|
208
689
|
initPlugins(plot);
|
209
690
|
parseOptions(options_);
|
@@ -221,40 +702,109 @@
|
|
221
702
|
}
|
222
703
|
|
223
704
|
function initPlugins() {
|
705
|
+
|
706
|
+
// References to key classes, allowing plugins to modify them
|
707
|
+
|
708
|
+
var classes = {
|
709
|
+
Canvas: Canvas
|
710
|
+
};
|
711
|
+
|
224
712
|
for (var i = 0; i < plugins.length; ++i) {
|
225
713
|
var p = plugins[i];
|
226
|
-
p.init(plot);
|
714
|
+
p.init(plot, classes);
|
227
715
|
if (p.options)
|
228
716
|
$.extend(true, options, p.options);
|
229
717
|
}
|
230
718
|
}
|
231
|
-
|
719
|
+
|
232
720
|
function parseOptions(opts) {
|
233
|
-
|
234
|
-
|
721
|
+
|
235
722
|
$.extend(true, options, opts);
|
236
|
-
|
723
|
+
|
724
|
+
// $.extend merges arrays, rather than replacing them. When less
|
725
|
+
// colors are provided than the size of the default palette, we
|
726
|
+
// end up with those colors plus the remaining defaults, which is
|
727
|
+
// not expected behavior; avoid it by replacing them here.
|
728
|
+
|
729
|
+
if (opts && opts.colors) {
|
730
|
+
options.colors = opts.colors;
|
731
|
+
}
|
732
|
+
|
237
733
|
if (options.xaxis.color == null)
|
238
|
-
options.xaxis.color = options.grid.color;
|
734
|
+
options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
|
239
735
|
if (options.yaxis.color == null)
|
240
|
-
options.yaxis.color = options.grid.color;
|
241
|
-
|
242
|
-
if (options.xaxis.tickColor == null) //
|
243
|
-
options.xaxis.tickColor = options.grid.tickColor;
|
244
|
-
if (options.yaxis.tickColor == null) //
|
245
|
-
options.yaxis.tickColor = options.grid.tickColor;
|
736
|
+
options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
|
737
|
+
|
738
|
+
if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility
|
739
|
+
options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color;
|
740
|
+
if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility
|
741
|
+
options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color;
|
246
742
|
|
247
743
|
if (options.grid.borderColor == null)
|
248
744
|
options.grid.borderColor = options.grid.color;
|
249
745
|
if (options.grid.tickColor == null)
|
250
746
|
options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
|
251
|
-
|
252
|
-
//
|
253
|
-
//
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
747
|
+
|
748
|
+
// Fill in defaults for axis options, including any unspecified
|
749
|
+
// font-spec fields, if a font-spec was provided.
|
750
|
+
|
751
|
+
// If no x/y axis options were provided, create one of each anyway,
|
752
|
+
// since the rest of the code assumes that they exist.
|
753
|
+
|
754
|
+
var i, axisOptions, axisCount,
|
755
|
+
fontSize = placeholder.css("font-size"),
|
756
|
+
fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13,
|
757
|
+
fontDefaults = {
|
758
|
+
style: placeholder.css("font-style"),
|
759
|
+
size: Math.round(0.8 * fontSizeDefault),
|
760
|
+
variant: placeholder.css("font-variant"),
|
761
|
+
weight: placeholder.css("font-weight"),
|
762
|
+
family: placeholder.css("font-family")
|
763
|
+
};
|
764
|
+
|
765
|
+
axisCount = options.xaxes.length || 1;
|
766
|
+
for (i = 0; i < axisCount; ++i) {
|
767
|
+
|
768
|
+
axisOptions = options.xaxes[i];
|
769
|
+
if (axisOptions && !axisOptions.tickColor) {
|
770
|
+
axisOptions.tickColor = axisOptions.color;
|
771
|
+
}
|
772
|
+
|
773
|
+
axisOptions = $.extend(true, {}, options.xaxis, axisOptions);
|
774
|
+
options.xaxes[i] = axisOptions;
|
775
|
+
|
776
|
+
if (axisOptions.font) {
|
777
|
+
axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
|
778
|
+
if (!axisOptions.font.color) {
|
779
|
+
axisOptions.font.color = axisOptions.color;
|
780
|
+
}
|
781
|
+
if (!axisOptions.font.lineHeight) {
|
782
|
+
axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
|
783
|
+
}
|
784
|
+
}
|
785
|
+
}
|
786
|
+
|
787
|
+
axisCount = options.yaxes.length || 1;
|
788
|
+
for (i = 0; i < axisCount; ++i) {
|
789
|
+
|
790
|
+
axisOptions = options.yaxes[i];
|
791
|
+
if (axisOptions && !axisOptions.tickColor) {
|
792
|
+
axisOptions.tickColor = axisOptions.color;
|
793
|
+
}
|
794
|
+
|
795
|
+
axisOptions = $.extend(true, {}, options.yaxis, axisOptions);
|
796
|
+
options.yaxes[i] = axisOptions;
|
797
|
+
|
798
|
+
if (axisOptions.font) {
|
799
|
+
axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
|
800
|
+
if (!axisOptions.font.color) {
|
801
|
+
axisOptions.font.color = axisOptions.color;
|
802
|
+
}
|
803
|
+
if (!axisOptions.font.lineHeight) {
|
804
|
+
axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
|
805
|
+
}
|
806
|
+
}
|
807
|
+
}
|
258
808
|
|
259
809
|
// backwards compatibility, to be removed in future
|
260
810
|
if (options.xaxis.noTicks && options.xaxis.ticks == null)
|
@@ -281,6 +831,8 @@
|
|
281
831
|
$.extend(true, options.series.bars, options.bars);
|
282
832
|
if (options.shadowSize != null)
|
283
833
|
options.series.shadowSize = options.shadowSize;
|
834
|
+
if (options.highlightColor != null)
|
835
|
+
options.series.highlightColor = options.highlightColor;
|
284
836
|
|
285
837
|
// save options on axes for future reference
|
286
838
|
for (i = 0; i < options.xaxes.length; ++i)
|
@@ -301,7 +853,7 @@
|
|
301
853
|
fillInSeriesOptions();
|
302
854
|
processData();
|
303
855
|
}
|
304
|
-
|
856
|
+
|
305
857
|
function parseData(d) {
|
306
858
|
var res = [];
|
307
859
|
for (var i = 0; i < d.length; ++i) {
|
@@ -322,7 +874,7 @@
|
|
322
874
|
|
323
875
|
return res;
|
324
876
|
}
|
325
|
-
|
877
|
+
|
326
878
|
function axisNumber(obj, coord) {
|
327
879
|
var a = obj[coord + "axis"];
|
328
880
|
if (typeof a == "object") // if we got a real axis, extract number
|
@@ -336,9 +888,9 @@
|
|
336
888
|
// return flat array without annoying null entries
|
337
889
|
return $.grep(xaxes.concat(yaxes), function (a) { return a; });
|
338
890
|
}
|
339
|
-
|
891
|
+
|
340
892
|
function canvasToAxisCoords(pos) {
|
341
|
-
// return an object with x/y corresponding to all used axes
|
893
|
+
// return an object with x/y corresponding to all used axes
|
342
894
|
var res = {}, i, axis;
|
343
895
|
for (i = 0; i < xaxes.length; ++i) {
|
344
896
|
axis = xaxes[i];
|
@@ -351,7 +903,7 @@
|
|
351
903
|
if (axis && axis.used)
|
352
904
|
res["y" + axis.n] = axis.c2p(pos.top);
|
353
905
|
}
|
354
|
-
|
906
|
+
|
355
907
|
if (res.x1 !== undefined)
|
356
908
|
res.x = res.x1;
|
357
909
|
if (res.y1 !== undefined)
|
@@ -359,7 +911,7 @@
|
|
359
911
|
|
360
912
|
return res;
|
361
913
|
}
|
362
|
-
|
914
|
+
|
363
915
|
function axisToCanvasCoords(pos) {
|
364
916
|
// get canvas coords from the first pair of x/y found in pos
|
365
917
|
var res = {}, i, axis, key;
|
@@ -377,7 +929,7 @@
|
|
377
929
|
}
|
378
930
|
}
|
379
931
|
}
|
380
|
-
|
932
|
+
|
381
933
|
for (i = 0; i < yaxes.length; ++i) {
|
382
934
|
axis = yaxes[i];
|
383
935
|
if (axis && axis.used) {
|
@@ -391,10 +943,10 @@
|
|
391
943
|
}
|
392
944
|
}
|
393
945
|
}
|
394
|
-
|
946
|
+
|
395
947
|
return res;
|
396
948
|
}
|
397
|
-
|
949
|
+
|
398
950
|
function getOrCreateAxis(axes, number) {
|
399
951
|
if (!axes[number - 1])
|
400
952
|
axes[number - 1] = {
|
@@ -402,64 +954,69 @@
|
|
402
954
|
direction: axes == xaxes ? "x" : "y",
|
403
955
|
options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
|
404
956
|
};
|
405
|
-
|
957
|
+
|
406
958
|
return axes[number - 1];
|
407
959
|
}
|
408
960
|
|
409
961
|
function fillInSeriesOptions() {
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
962
|
+
|
963
|
+
var neededColors = series.length, maxIndex = -1, i;
|
964
|
+
|
965
|
+
// Subtract the number of series that already have fixed colors or
|
966
|
+
// color indexes from the number that we still need to generate.
|
967
|
+
|
416
968
|
for (i = 0; i < series.length; ++i) {
|
417
969
|
var sc = series[i].color;
|
418
970
|
if (sc != null) {
|
419
|
-
|
420
|
-
if (typeof sc == "number")
|
421
|
-
|
422
|
-
|
423
|
-
usedColors.push($.color.parse(series[i].color));
|
971
|
+
neededColors--;
|
972
|
+
if (typeof sc == "number" && sc > maxIndex) {
|
973
|
+
maxIndex = sc;
|
974
|
+
}
|
424
975
|
}
|
425
976
|
}
|
426
|
-
|
427
|
-
//
|
428
|
-
//
|
429
|
-
|
430
|
-
|
977
|
+
|
978
|
+
// If any of the series have fixed color indexes, then we need to
|
979
|
+
// generate at least as many colors as the highest index.
|
980
|
+
|
981
|
+
if (neededColors <= maxIndex) {
|
982
|
+
neededColors = maxIndex + 1;
|
431
983
|
}
|
432
984
|
|
433
|
-
//
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
//
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
//
|
449
|
-
colors.
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
985
|
+
// Generate all the colors, using first the option colors and then
|
986
|
+
// variations on those colors once they're exhausted.
|
987
|
+
|
988
|
+
var c, colors = [], colorPool = options.colors,
|
989
|
+
colorPoolSize = colorPool.length, variation = 0;
|
990
|
+
|
991
|
+
for (i = 0; i < neededColors; i++) {
|
992
|
+
|
993
|
+
c = $.color.parse(colorPool[i % colorPoolSize] || "#666");
|
994
|
+
|
995
|
+
// Each time we exhaust the colors in the pool we adjust
|
996
|
+
// a scaling factor used to produce more variations on
|
997
|
+
// those colors. The factor alternates negative/positive
|
998
|
+
// to produce lighter/darker colors.
|
999
|
+
|
1000
|
+
// Reset the variation after every few cycles, or else
|
1001
|
+
// it will end up producing only white or black colors.
|
1002
|
+
|
1003
|
+
if (i % colorPoolSize == 0 && i) {
|
1004
|
+
if (variation >= 0) {
|
1005
|
+
if (variation < 0.5) {
|
1006
|
+
variation = -variation - 0.2;
|
1007
|
+
} else variation = 0;
|
1008
|
+
} else variation = -variation;
|
455
1009
|
}
|
1010
|
+
|
1011
|
+
colors[i] = c.scale('rgb', 1 + variation);
|
456
1012
|
}
|
457
1013
|
|
458
|
-
//
|
1014
|
+
// Finalize the series options, filling in their colors
|
1015
|
+
|
459
1016
|
var colori = 0, s;
|
460
1017
|
for (i = 0; i < series.length; ++i) {
|
461
1018
|
s = series[i];
|
462
|
-
|
1019
|
+
|
463
1020
|
// assign colors
|
464
1021
|
if (s.color == null) {
|
465
1022
|
s.color = colors[colori].toString();
|
@@ -480,18 +1037,26 @@
|
|
480
1037
|
s.lines.show = true;
|
481
1038
|
}
|
482
1039
|
|
1040
|
+
// If nothing was provided for lines.zero, default it to match
|
1041
|
+
// lines.fill, since areas by default should extend to zero.
|
1042
|
+
|
1043
|
+
if (s.lines.zero == null) {
|
1044
|
+
s.lines.zero = !!s.lines.fill;
|
1045
|
+
}
|
1046
|
+
|
483
1047
|
// setup axes
|
484
1048
|
s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
|
485
1049
|
s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
|
486
1050
|
}
|
487
1051
|
}
|
488
|
-
|
1052
|
+
|
489
1053
|
function processData() {
|
490
1054
|
var topSentry = Number.POSITIVE_INFINITY,
|
491
1055
|
bottomSentry = Number.NEGATIVE_INFINITY,
|
492
1056
|
fakeInfinity = Number.MAX_VALUE,
|
493
1057
|
i, j, k, m, length,
|
494
|
-
s, points, ps, x, y, axis, val, f, p
|
1058
|
+
s, points, ps, x, y, axis, val, f, p,
|
1059
|
+
data, format;
|
495
1060
|
|
496
1061
|
function updateAxis(axis, min, max) {
|
497
1062
|
if (min < axis.datamin && min != -fakeInfinity)
|
@@ -506,19 +1071,20 @@
|
|
506
1071
|
axis.datamax = bottomSentry;
|
507
1072
|
axis.used = false;
|
508
1073
|
});
|
509
|
-
|
1074
|
+
|
510
1075
|
for (i = 0; i < series.length; ++i) {
|
511
1076
|
s = series[i];
|
512
1077
|
s.datapoints = { points: [] };
|
513
|
-
|
1078
|
+
|
514
1079
|
executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
|
515
1080
|
}
|
516
|
-
|
1081
|
+
|
517
1082
|
// first pass: clean and copy data
|
518
1083
|
for (i = 0; i < series.length; ++i) {
|
519
1084
|
s = series[i];
|
520
1085
|
|
521
|
-
|
1086
|
+
data = s.data;
|
1087
|
+
format = s.datapoints.format;
|
522
1088
|
|
523
1089
|
if (!format) {
|
524
1090
|
format = [];
|
@@ -527,13 +1093,14 @@
|
|
527
1093
|
format.push({ y: true, number: true, required: true });
|
528
1094
|
|
529
1095
|
if (s.bars.show || (s.lines.show && s.lines.fill)) {
|
530
|
-
|
1096
|
+
var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
|
1097
|
+
format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
|
531
1098
|
if (s.bars.horizontal) {
|
532
1099
|
delete format[format.length - 1].y;
|
533
1100
|
format[format.length - 1].x = true;
|
534
1101
|
}
|
535
1102
|
}
|
536
|
-
|
1103
|
+
|
537
1104
|
s.datapoints.format = format;
|
538
1105
|
}
|
539
1106
|
|
@@ -541,13 +1108,13 @@
|
|
541
1108
|
continue; // already filled in
|
542
1109
|
|
543
1110
|
s.datapoints.pointsize = format.length;
|
544
|
-
|
1111
|
+
|
545
1112
|
ps = s.datapoints.pointsize;
|
546
1113
|
points = s.datapoints.points;
|
547
1114
|
|
548
|
-
insertSteps = s.lines.show && s.lines.steps;
|
1115
|
+
var insertSteps = s.lines.show && s.lines.steps;
|
549
1116
|
s.xaxis.used = s.yaxis.used = true;
|
550
|
-
|
1117
|
+
|
551
1118
|
for (j = k = 0; j < data.length; ++j, k += ps) {
|
552
1119
|
p = data[j];
|
553
1120
|
|
@@ -571,26 +1138,30 @@
|
|
571
1138
|
if (val == null) {
|
572
1139
|
if (f.required)
|
573
1140
|
nullify = true;
|
574
|
-
|
1141
|
+
|
575
1142
|
if (f.defaultValue != null)
|
576
1143
|
val = f.defaultValue;
|
577
1144
|
}
|
578
1145
|
}
|
579
|
-
|
1146
|
+
|
580
1147
|
points[k + m] = val;
|
581
1148
|
}
|
582
1149
|
}
|
583
|
-
|
1150
|
+
|
584
1151
|
if (nullify) {
|
585
1152
|
for (m = 0; m < ps; ++m) {
|
586
1153
|
val = points[k + m];
|
587
1154
|
if (val != null) {
|
588
1155
|
f = format[m];
|
589
1156
|
// extract min/max info
|
590
|
-
if (f.
|
591
|
-
|
592
|
-
|
593
|
-
|
1157
|
+
if (f.autoscale !== false) {
|
1158
|
+
if (f.x) {
|
1159
|
+
updateAxis(s.xaxis, val, val);
|
1160
|
+
}
|
1161
|
+
if (f.y) {
|
1162
|
+
updateAxis(s.yaxis, val, val);
|
1163
|
+
}
|
1164
|
+
}
|
594
1165
|
}
|
595
1166
|
points[k + m] = null;
|
596
1167
|
}
|
@@ -620,19 +1191,20 @@
|
|
620
1191
|
// give the hooks a chance to run
|
621
1192
|
for (i = 0; i < series.length; ++i) {
|
622
1193
|
s = series[i];
|
623
|
-
|
1194
|
+
|
624
1195
|
executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
|
625
1196
|
}
|
626
1197
|
|
627
1198
|
// second pass: find datamax/datamin for auto-scaling
|
628
1199
|
for (i = 0; i < series.length; ++i) {
|
629
1200
|
s = series[i];
|
630
|
-
points = s.datapoints.points
|
1201
|
+
points = s.datapoints.points;
|
631
1202
|
ps = s.datapoints.pointsize;
|
1203
|
+
format = s.datapoints.format;
|
632
1204
|
|
633
1205
|
var xmin = topSentry, ymin = topSentry,
|
634
1206
|
xmax = bottomSentry, ymax = bottomSentry;
|
635
|
-
|
1207
|
+
|
636
1208
|
for (j = 0; j < points.length; j += ps) {
|
637
1209
|
if (points[j] == null)
|
638
1210
|
continue;
|
@@ -640,9 +1212,9 @@
|
|
640
1212
|
for (m = 0; m < ps; ++m) {
|
641
1213
|
val = points[j + m];
|
642
1214
|
f = format[m];
|
643
|
-
if (!f || val == fakeInfinity || val == -fakeInfinity)
|
1215
|
+
if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity)
|
644
1216
|
continue;
|
645
|
-
|
1217
|
+
|
646
1218
|
if (f.x) {
|
647
1219
|
if (val < xmin)
|
648
1220
|
xmin = val;
|
@@ -657,10 +1229,22 @@
|
|
657
1229
|
}
|
658
1230
|
}
|
659
1231
|
}
|
660
|
-
|
1232
|
+
|
661
1233
|
if (s.bars.show) {
|
662
1234
|
// make sure we got room for the bar on the dancing floor
|
663
|
-
var delta
|
1235
|
+
var delta;
|
1236
|
+
|
1237
|
+
switch (s.bars.align) {
|
1238
|
+
case "left":
|
1239
|
+
delta = 0;
|
1240
|
+
break;
|
1241
|
+
case "right":
|
1242
|
+
delta = -s.bars.barWidth;
|
1243
|
+
break;
|
1244
|
+
default:
|
1245
|
+
delta = -s.bars.barWidth / 2;
|
1246
|
+
}
|
1247
|
+
|
664
1248
|
if (s.bars.horizontal) {
|
665
1249
|
ymin += delta;
|
666
1250
|
ymax += delta + s.bars.barWidth;
|
@@ -670,7 +1254,7 @@
|
|
670
1254
|
xmax += delta + s.bars.barWidth;
|
671
1255
|
}
|
672
1256
|
}
|
673
|
-
|
1257
|
+
|
674
1258
|
updateAxis(s.xaxis, xmin, xmax);
|
675
1259
|
updateAxis(s.yaxis, ymin, ymax);
|
676
1260
|
}
|
@@ -683,103 +1267,35 @@
|
|
683
1267
|
});
|
684
1268
|
}
|
685
1269
|
|
686
|
-
function
|
687
|
-
var c = document.createElement('canvas');
|
688
|
-
c.className = cls;
|
689
|
-
c.width = canvasWidth;
|
690
|
-
c.height = canvasHeight;
|
691
|
-
|
692
|
-
if (!skipPositioning)
|
693
|
-
$(c).css({ position: 'absolute', left: 0, top: 0 });
|
694
|
-
|
695
|
-
$(c).appendTo(placeholder);
|
696
|
-
|
697
|
-
if (!c.getContext) // excanvas hack
|
698
|
-
c = window.G_vmlCanvasManager.initElement(c);
|
699
|
-
|
700
|
-
// used for resetting in case we get replotted
|
701
|
-
c.getContext("2d").save();
|
702
|
-
|
703
|
-
return c;
|
704
|
-
}
|
705
|
-
|
706
|
-
function getCanvasDimensions() {
|
707
|
-
canvasWidth = placeholder.width();
|
708
|
-
canvasHeight = placeholder.height();
|
709
|
-
|
710
|
-
if (canvasWidth <= 0 || canvasHeight <= 0)
|
711
|
-
throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
|
712
|
-
}
|
1270
|
+
function setupCanvases() {
|
713
1271
|
|
714
|
-
|
715
|
-
//
|
716
|
-
// buggy though)
|
717
|
-
if (c.width != canvasWidth)
|
718
|
-
c.width = canvasWidth;
|
1272
|
+
// Make sure the placeholder is clear of everything except canvases
|
1273
|
+
// from a previous plot in this container that we'll try to re-use.
|
719
1274
|
|
720
|
-
|
721
|
-
|
1275
|
+
placeholder.css("padding", 0) // padding messes up the positioning
|
1276
|
+
.children().filter(function(){
|
1277
|
+
return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base');
|
1278
|
+
}).remove();
|
722
1279
|
|
723
|
-
|
724
|
-
|
725
|
-
var cctx = c.getContext("2d");
|
726
|
-
cctx.restore();
|
1280
|
+
if (placeholder.css("position") == 'static')
|
1281
|
+
placeholder.css("position", "relative"); // for positioning labels and overlay
|
727
1282
|
|
728
|
-
|
729
|
-
|
730
|
-
}
|
731
|
-
|
732
|
-
function setupCanvases() {
|
733
|
-
var reused,
|
734
|
-
existingCanvas = placeholder.children("canvas.base"),
|
735
|
-
existingOverlay = placeholder.children("canvas.overlay");
|
736
|
-
|
737
|
-
if (existingCanvas.length == 0 || existingOverlay == 0) {
|
738
|
-
// init everything
|
739
|
-
|
740
|
-
placeholder.html(""); // make sure placeholder is clear
|
741
|
-
|
742
|
-
placeholder.css({ padding: 0 }); // padding messes up the positioning
|
743
|
-
|
744
|
-
if (placeholder.css("position") == 'static')
|
745
|
-
placeholder.css("position", "relative"); // for positioning labels and overlay
|
746
|
-
|
747
|
-
getCanvasDimensions();
|
748
|
-
|
749
|
-
canvas = makeCanvas(true, "base");
|
750
|
-
overlay = makeCanvas(false, "overlay"); // overlay canvas for interactive features
|
751
|
-
|
752
|
-
reused = false;
|
753
|
-
}
|
754
|
-
else {
|
755
|
-
// reuse existing elements
|
1283
|
+
surface = new Canvas("flot-base", placeholder);
|
1284
|
+
overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features
|
756
1285
|
|
757
|
-
|
758
|
-
|
1286
|
+
ctx = surface.context;
|
1287
|
+
octx = overlay.context;
|
759
1288
|
|
760
|
-
|
761
|
-
|
1289
|
+
// define which element we're listening for events on
|
1290
|
+
eventHolder = $(overlay.element).unbind();
|
762
1291
|
|
763
|
-
|
764
|
-
octx = overlay.getContext("2d");
|
1292
|
+
// If we're re-using a plot object, shut down the old one
|
765
1293
|
|
766
|
-
|
767
|
-
// sometimes has trouble with the stacking order
|
768
|
-
eventHolder = $([overlay, canvas]);
|
1294
|
+
var existing = placeholder.data("plot");
|
769
1295
|
|
770
|
-
if (
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
// reset reused canvases
|
775
|
-
plot.resize();
|
776
|
-
|
777
|
-
// make sure overlay pixels are cleared (canvas is cleared when we redraw)
|
778
|
-
octx.clearRect(0, 0, canvasWidth, canvasHeight);
|
779
|
-
|
780
|
-
// then whack any remaining obvious garbage left
|
781
|
-
eventHolder.unbind();
|
782
|
-
placeholder.children().not([canvas, overlay]).remove();
|
1296
|
+
if (existing) {
|
1297
|
+
existing.shutdown();
|
1298
|
+
overlay.clear();
|
783
1299
|
}
|
784
1300
|
|
785
1301
|
// save in case we get replotted
|
@@ -790,7 +1306,14 @@
|
|
790
1306
|
// bind events
|
791
1307
|
if (options.grid.hoverable) {
|
792
1308
|
eventHolder.mousemove(onMouseMove);
|
793
|
-
|
1309
|
+
|
1310
|
+
// Use bind, rather than .mouseleave, because we officially
|
1311
|
+
// still support jQuery 1.2.6, which doesn't define a shortcut
|
1312
|
+
// for mouseenter or mouseleave. This was a bug/oversight that
|
1313
|
+
// was fixed somewhere around 1.3.x. We can return to using
|
1314
|
+
// .mouseleave when we drop support for 1.2.6.
|
1315
|
+
|
1316
|
+
eventHolder.bind("mouseleave", onMouseLeave);
|
794
1317
|
}
|
795
1318
|
|
796
1319
|
if (options.grid.clickable)
|
@@ -802,23 +1325,23 @@
|
|
802
1325
|
function shutdown() {
|
803
1326
|
if (redrawTimeout)
|
804
1327
|
clearTimeout(redrawTimeout);
|
805
|
-
|
1328
|
+
|
806
1329
|
eventHolder.unbind("mousemove", onMouseMove);
|
807
1330
|
eventHolder.unbind("mouseleave", onMouseLeave);
|
808
1331
|
eventHolder.unbind("click", onClick);
|
809
|
-
|
1332
|
+
|
810
1333
|
executeHooks(hooks.shutdown, [eventHolder]);
|
811
1334
|
}
|
812
1335
|
|
813
1336
|
function setTransformationHelpers(axis) {
|
814
1337
|
// set helper functions on the axis, assumes plot area
|
815
1338
|
// has been computed already
|
816
|
-
|
1339
|
+
|
817
1340
|
function identity(x) { return x; }
|
818
|
-
|
1341
|
+
|
819
1342
|
var s, m, t = axis.options.transform || identity,
|
820
1343
|
it = axis.options.inverseTransform;
|
821
|
-
|
1344
|
+
|
822
1345
|
// precompute how much the axis is scaling a point
|
823
1346
|
// in canvas space
|
824
1347
|
if (axis.direction == "x") {
|
@@ -844,129 +1367,108 @@
|
|
844
1367
|
}
|
845
1368
|
|
846
1369
|
function measureTickLabels(axis) {
|
847
|
-
var opts = axis.options, i, ticks = axis.ticks || [], labels = [],
|
848
|
-
l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;
|
849
1370
|
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
// them, we don't need the exact figures and the
|
861
|
-
// fixed-size box content is easy to center
|
862
|
-
if (w == null)
|
863
|
-
w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));
|
864
|
-
|
865
|
-
// measure x label heights
|
866
|
-
if (h == null) {
|
867
|
-
labels = [];
|
868
|
-
for (i = 0; i < ticks.length; ++i) {
|
869
|
-
l = ticks[i].label;
|
870
|
-
if (l)
|
871
|
-
labels.push('<div class="tickLabel" style="float:left;width:' + w + 'px">' + l + '</div>');
|
872
|
-
}
|
873
|
-
|
874
|
-
if (labels.length > 0) {
|
875
|
-
// stick them all in the same div and measure
|
876
|
-
// collective height
|
877
|
-
labels.push('<div style="clear:left"></div>');
|
878
|
-
dummyDiv = makeDummyDiv(labels, "width:10000px;");
|
879
|
-
h = dummyDiv.height();
|
880
|
-
dummyDiv.remove();
|
881
|
-
}
|
882
|
-
}
|
883
|
-
}
|
884
|
-
else if (w == null || h == null) {
|
885
|
-
// calculate y label dimensions
|
886
|
-
for (i = 0; i < ticks.length; ++i) {
|
887
|
-
l = ticks[i].label;
|
888
|
-
if (l)
|
889
|
-
labels.push('<div class="tickLabel">' + l + '</div>');
|
890
|
-
}
|
891
|
-
|
892
|
-
if (labels.length > 0) {
|
893
|
-
dummyDiv = makeDummyDiv(labels, "");
|
894
|
-
if (w == null)
|
895
|
-
w = dummyDiv.children().width();
|
896
|
-
if (h == null)
|
897
|
-
h = dummyDiv.find("div.tickLabel").height();
|
898
|
-
dummyDiv.remove();
|
899
|
-
}
|
900
|
-
}
|
1371
|
+
var opts = axis.options,
|
1372
|
+
ticks = axis.ticks || [],
|
1373
|
+
labelWidth = opts.labelWidth || 0,
|
1374
|
+
labelHeight = opts.labelHeight || 0,
|
1375
|
+
maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null),
|
1376
|
+
legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
|
1377
|
+
layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
|
1378
|
+
font = opts.font || "flot-tick-label tickLabel";
|
1379
|
+
|
1380
|
+
for (var i = 0; i < ticks.length; ++i) {
|
901
1381
|
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
1382
|
+
var t = ticks[i];
|
1383
|
+
|
1384
|
+
if (!t.label)
|
1385
|
+
continue;
|
906
1386
|
|
907
|
-
|
908
|
-
|
1387
|
+
var info = surface.getTextInfo(layer, t.label, font, null, maxWidth);
|
1388
|
+
|
1389
|
+
labelWidth = Math.max(labelWidth, info.width);
|
1390
|
+
labelHeight = Math.max(labelHeight, info.height);
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
axis.labelWidth = opts.labelWidth || labelWidth;
|
1394
|
+
axis.labelHeight = opts.labelHeight || labelHeight;
|
909
1395
|
}
|
910
1396
|
|
911
1397
|
function allocateAxisBoxFirstPhase(axis) {
|
912
1398
|
// find the bounding box of the axis by looking at label
|
913
1399
|
// widths/heights and ticks, make room by diminishing the
|
914
|
-
// plotOffset
|
1400
|
+
// plotOffset; this first phase only looks at one
|
1401
|
+
// dimension per axis, the other dimension depends on the
|
1402
|
+
// other axes so will have to wait
|
915
1403
|
|
916
1404
|
var lw = axis.labelWidth,
|
917
1405
|
lh = axis.labelHeight,
|
918
1406
|
pos = axis.options.position,
|
1407
|
+
isXAxis = axis.direction === "x",
|
919
1408
|
tickLength = axis.options.tickLength,
|
920
|
-
|
1409
|
+
axisMargin = options.grid.axisMargin,
|
921
1410
|
padding = options.grid.labelMargin,
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
1411
|
+
innermost = true,
|
1412
|
+
outermost = true,
|
1413
|
+
first = true,
|
1414
|
+
found = false;
|
1415
|
+
|
1416
|
+
// Determine the axis's position in its direction and on its side
|
1417
|
+
|
1418
|
+
$.each(isXAxis ? xaxes : yaxes, function(i, a) {
|
1419
|
+
if (a && a.reserveSpace) {
|
1420
|
+
if (a === axis) {
|
1421
|
+
found = true;
|
1422
|
+
} else if (a.options.position === pos) {
|
1423
|
+
if (found) {
|
1424
|
+
outermost = false;
|
1425
|
+
} else {
|
1426
|
+
innermost = false;
|
1427
|
+
}
|
1428
|
+
}
|
1429
|
+
if (!found) {
|
1430
|
+
first = false;
|
1431
|
+
}
|
1432
|
+
}
|
928
1433
|
});
|
929
|
-
if ($.inArray(axis, samePosition) == samePosition.length - 1)
|
930
|
-
axismargin = 0; // outermost
|
931
1434
|
|
932
|
-
//
|
933
|
-
if (tickLength == null)
|
934
|
-
tickLength = "full";
|
1435
|
+
// The outermost axis on each side has no margin
|
935
1436
|
|
936
|
-
|
937
|
-
|
938
|
-
}
|
1437
|
+
if (outermost) {
|
1438
|
+
axisMargin = 0;
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
// The ticks for the first axis in each direction stretch across
|
1442
|
+
|
1443
|
+
if (tickLength == null) {
|
1444
|
+
tickLength = first ? "full" : 5;
|
1445
|
+
}
|
939
1446
|
|
940
|
-
var innermost = $.inArray(axis, sameDirection) == 0;
|
941
|
-
if (!innermost && tickLength == "full")
|
942
|
-
tickLength = 5;
|
943
|
-
|
944
1447
|
if (!isNaN(+tickLength))
|
945
1448
|
padding += +tickLength;
|
946
1449
|
|
947
|
-
|
948
|
-
if (axis.direction == "x") {
|
1450
|
+
if (isXAxis) {
|
949
1451
|
lh += padding;
|
950
|
-
|
1452
|
+
|
951
1453
|
if (pos == "bottom") {
|
952
|
-
plotOffset.bottom += lh +
|
953
|
-
axis.box = { top:
|
1454
|
+
plotOffset.bottom += lh + axisMargin;
|
1455
|
+
axis.box = { top: surface.height - plotOffset.bottom, height: lh };
|
954
1456
|
}
|
955
1457
|
else {
|
956
|
-
axis.box = { top: plotOffset.top +
|
957
|
-
plotOffset.top += lh +
|
1458
|
+
axis.box = { top: plotOffset.top + axisMargin, height: lh };
|
1459
|
+
plotOffset.top += lh + axisMargin;
|
958
1460
|
}
|
959
1461
|
}
|
960
1462
|
else {
|
961
1463
|
lw += padding;
|
962
|
-
|
1464
|
+
|
963
1465
|
if (pos == "left") {
|
964
|
-
axis.box = { left: plotOffset.left +
|
965
|
-
plotOffset.left += lw +
|
1466
|
+
axis.box = { left: plotOffset.left + axisMargin, width: lw };
|
1467
|
+
plotOffset.left += lw + axisMargin;
|
966
1468
|
}
|
967
1469
|
else {
|
968
|
-
plotOffset.right += lw +
|
969
|
-
axis.box = { left:
|
1470
|
+
plotOffset.right += lw + axisMargin;
|
1471
|
+
axis.box = { left: surface.width - plotOffset.right, width: lw };
|
970
1472
|
}
|
971
1473
|
}
|
972
1474
|
|
@@ -978,85 +1480,144 @@
|
|
978
1480
|
}
|
979
1481
|
|
980
1482
|
function allocateAxisBoxSecondPhase(axis) {
|
981
|
-
//
|
1483
|
+
// now that all axis boxes have been placed in one
|
1484
|
+
// dimension, we can set the remaining dimension coordinates
|
982
1485
|
if (axis.direction == "x") {
|
983
|
-
axis.box.left = plotOffset.left;
|
984
|
-
axis.box.width =
|
1486
|
+
axis.box.left = plotOffset.left - axis.labelWidth / 2;
|
1487
|
+
axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth;
|
985
1488
|
}
|
986
1489
|
else {
|
987
|
-
axis.box.top = plotOffset.top;
|
988
|
-
axis.box.height =
|
1490
|
+
axis.box.top = plotOffset.top - axis.labelHeight / 2;
|
1491
|
+
axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight;
|
1492
|
+
}
|
1493
|
+
}
|
1494
|
+
|
1495
|
+
function adjustLayoutForThingsStickingOut() {
|
1496
|
+
// possibly adjust plot offset to ensure everything stays
|
1497
|
+
// inside the canvas and isn't clipped off
|
1498
|
+
|
1499
|
+
var minMargin = options.grid.minBorderMargin,
|
1500
|
+
axis, i;
|
1501
|
+
|
1502
|
+
// check stuff from the plot (FIXME: this should just read
|
1503
|
+
// a value from the series, otherwise it's impossible to
|
1504
|
+
// customize)
|
1505
|
+
if (minMargin == null) {
|
1506
|
+
minMargin = 0;
|
1507
|
+
for (i = 0; i < series.length; ++i)
|
1508
|
+
minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
|
989
1509
|
}
|
1510
|
+
|
1511
|
+
var margins = {
|
1512
|
+
left: minMargin,
|
1513
|
+
right: minMargin,
|
1514
|
+
top: minMargin,
|
1515
|
+
bottom: minMargin
|
1516
|
+
};
|
1517
|
+
|
1518
|
+
// check axis labels, note we don't check the actual
|
1519
|
+
// labels but instead use the overall width/height to not
|
1520
|
+
// jump as much around with replots
|
1521
|
+
$.each(allAxes(), function (_, axis) {
|
1522
|
+
if (axis.reserveSpace && axis.ticks && axis.ticks.length) {
|
1523
|
+
var lastTick = axis.ticks[axis.ticks.length - 1];
|
1524
|
+
if (axis.direction === "x") {
|
1525
|
+
margins.left = Math.max(margins.left, axis.labelWidth / 2);
|
1526
|
+
if (lastTick.v <= axis.max) {
|
1527
|
+
margins.right = Math.max(margins.right, axis.labelWidth / 2);
|
1528
|
+
}
|
1529
|
+
} else {
|
1530
|
+
margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);
|
1531
|
+
if (lastTick.v <= axis.max) {
|
1532
|
+
margins.top = Math.max(margins.top, axis.labelHeight / 2);
|
1533
|
+
}
|
1534
|
+
}
|
1535
|
+
}
|
1536
|
+
});
|
1537
|
+
|
1538
|
+
plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));
|
1539
|
+
plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));
|
1540
|
+
plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));
|
1541
|
+
plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));
|
990
1542
|
}
|
991
|
-
|
1543
|
+
|
992
1544
|
function setupGrid() {
|
993
|
-
var i, axes = allAxes();
|
1545
|
+
var i, axes = allAxes(), showGrid = options.grid.show;
|
1546
|
+
|
1547
|
+
// Initialize the plot's offset from the edge of the canvas
|
994
1548
|
|
995
|
-
|
1549
|
+
for (var a in plotOffset) {
|
1550
|
+
var margin = options.grid.margin || 0;
|
1551
|
+
plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0;
|
1552
|
+
}
|
996
1553
|
|
1554
|
+
executeHooks(hooks.processOffset, [plotOffset]);
|
1555
|
+
|
1556
|
+
// If the grid is visible, add its border width to the offset
|
1557
|
+
|
1558
|
+
for (var a in plotOffset) {
|
1559
|
+
if(typeof(options.grid.borderWidth) == "object") {
|
1560
|
+
plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0;
|
1561
|
+
}
|
1562
|
+
else {
|
1563
|
+
plotOffset[a] += showGrid ? options.grid.borderWidth : 0;
|
1564
|
+
}
|
1565
|
+
}
|
1566
|
+
|
1567
|
+
// init axes
|
997
1568
|
$.each(axes, function (_, axis) {
|
998
1569
|
axis.show = axis.options.show;
|
999
1570
|
if (axis.show == null)
|
1000
1571
|
axis.show = axis.used; // by default an axis is visible if it's got data
|
1001
|
-
|
1572
|
+
|
1002
1573
|
axis.reserveSpace = axis.show || axis.options.reserveSpace;
|
1003
1574
|
|
1004
1575
|
setRange(axis);
|
1005
1576
|
});
|
1006
1577
|
|
1007
|
-
|
1578
|
+
if (showGrid) {
|
1579
|
+
|
1580
|
+
var allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
|
1008
1581
|
|
1009
|
-
plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;
|
1010
|
-
if (options.grid.show) {
|
1011
1582
|
$.each(allocatedAxes, function (_, axis) {
|
1012
1583
|
// make the ticks
|
1013
1584
|
setupTickGeneration(axis);
|
1014
1585
|
setTicks(axis);
|
1015
1586
|
snapRangeToTicks(axis, axis.ticks);
|
1016
|
-
|
1017
1587
|
// find labelWidth/Height for axis
|
1018
1588
|
measureTickLabels(axis);
|
1019
1589
|
});
|
1020
1590
|
|
1021
|
-
// with all dimensions
|
1022
|
-
// axis boxes, start from the outside
|
1591
|
+
// with all dimensions calculated, we can compute the
|
1592
|
+
// axis bounding boxes, start from the outside
|
1593
|
+
// (reverse order)
|
1023
1594
|
for (i = allocatedAxes.length - 1; i >= 0; --i)
|
1024
1595
|
allocateAxisBoxFirstPhase(allocatedAxes[i]);
|
1025
1596
|
|
1026
1597
|
// make sure we've got enough space for things that
|
1027
1598
|
// might stick out
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
}
|
1034
|
-
|
1035
|
-
for (var a in plotOffset) {
|
1036
|
-
plotOffset[a] += options.grid.borderWidth;
|
1037
|
-
plotOffset[a] = Math.max(minMargin, plotOffset[a]);
|
1038
|
-
}
|
1599
|
+
adjustLayoutForThingsStickingOut();
|
1600
|
+
|
1601
|
+
$.each(allocatedAxes, function (_, axis) {
|
1602
|
+
allocateAxisBoxSecondPhase(axis);
|
1603
|
+
});
|
1039
1604
|
}
|
1040
|
-
|
1041
|
-
plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
|
1042
|
-
plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
|
1043
1605
|
|
1044
|
-
|
1606
|
+
plotWidth = surface.width - plotOffset.left - plotOffset.right;
|
1607
|
+
plotHeight = surface.height - plotOffset.bottom - plotOffset.top;
|
1608
|
+
|
1609
|
+
// now we got the proper plot dimensions, we can compute the scaling
|
1045
1610
|
$.each(axes, function (_, axis) {
|
1046
1611
|
setTransformationHelpers(axis);
|
1047
1612
|
});
|
1048
1613
|
|
1049
|
-
if (
|
1050
|
-
|
1051
|
-
allocateAxisBoxSecondPhase(axis);
|
1052
|
-
});
|
1053
|
-
|
1054
|
-
insertAxisLabels();
|
1614
|
+
if (showGrid) {
|
1615
|
+
drawAxisLabels();
|
1055
1616
|
}
|
1056
|
-
|
1617
|
+
|
1057
1618
|
insertLegend();
|
1058
1619
|
}
|
1059
|
-
|
1620
|
+
|
1060
1621
|
function setRange(axis) {
|
1061
1622
|
var opts = axis.options,
|
1062
1623
|
min = +(opts.min != null ? opts.min : axis.datamin),
|
@@ -1098,7 +1659,7 @@
|
|
1098
1659
|
|
1099
1660
|
function setupTickGeneration(axis) {
|
1100
1661
|
var opts = axis.options;
|
1101
|
-
|
1662
|
+
|
1102
1663
|
// estimate number of ticks
|
1103
1664
|
var noTicks;
|
1104
1665
|
if (typeof opts.ticks == "number" && opts.ticks > 0)
|
@@ -1106,209 +1667,65 @@
|
|
1106
1667
|
else
|
1107
1668
|
// heuristic based on the model a*sqrt(x) fitted to
|
1108
1669
|
// some data points that seemed reasonable
|
1109
|
-
noTicks = 0.3 * Math.sqrt(axis.direction == "x" ?
|
1670
|
+
noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height);
|
1110
1671
|
|
1111
1672
|
var delta = (axis.max - axis.min) / noTicks,
|
1112
|
-
|
1113
|
-
|
1114
|
-
if (opts.mode == "time") {
|
1115
|
-
// pretty handling of time
|
1116
|
-
|
1117
|
-
// map of app. size of time units in milliseconds
|
1118
|
-
var timeUnitSize = {
|
1119
|
-
"second": 1000,
|
1120
|
-
"minute": 60 * 1000,
|
1121
|
-
"hour": 60 * 60 * 1000,
|
1122
|
-
"day": 24 * 60 * 60 * 1000,
|
1123
|
-
"month": 30 * 24 * 60 * 60 * 1000,
|
1124
|
-
"year": 365.2425 * 24 * 60 * 60 * 1000
|
1125
|
-
};
|
1673
|
+
dec = -Math.floor(Math.log(delta) / Math.LN10),
|
1674
|
+
maxDec = opts.tickDecimals;
|
1126
1675
|
|
1676
|
+
if (maxDec != null && dec > maxDec) {
|
1677
|
+
dec = maxDec;
|
1678
|
+
}
|
1127
1679
|
|
1128
|
-
|
1129
|
-
//
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
[1, "year"]
|
1141
|
-
];
|
1142
|
-
|
1143
|
-
var minSize = 0;
|
1144
|
-
if (opts.minTickSize != null) {
|
1145
|
-
if (typeof opts.tickSize == "number")
|
1146
|
-
minSize = opts.tickSize;
|
1147
|
-
else
|
1148
|
-
minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
|
1680
|
+
var magn = Math.pow(10, -dec),
|
1681
|
+
norm = delta / magn, // norm is between 1.0 and 10.0
|
1682
|
+
size;
|
1683
|
+
|
1684
|
+
if (norm < 1.5) {
|
1685
|
+
size = 1;
|
1686
|
+
} else if (norm < 3) {
|
1687
|
+
size = 2;
|
1688
|
+
// special case for 2.5, requires an extra decimal
|
1689
|
+
if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
|
1690
|
+
size = 2.5;
|
1691
|
+
++dec;
|
1149
1692
|
}
|
1693
|
+
} else if (norm < 7.5) {
|
1694
|
+
size = 5;
|
1695
|
+
} else {
|
1696
|
+
size = 10;
|
1697
|
+
}
|
1150
1698
|
|
1151
|
-
|
1152
|
-
if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]
|
1153
|
-
+ spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
|
1154
|
-
&& spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)
|
1155
|
-
break;
|
1156
|
-
size = spec[i][0];
|
1157
|
-
unit = spec[i][1];
|
1158
|
-
|
1159
|
-
// special-case the possibility of several years
|
1160
|
-
if (unit == "year") {
|
1161
|
-
magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));
|
1162
|
-
norm = (delta / timeUnitSize.year) / magn;
|
1163
|
-
if (norm < 1.5)
|
1164
|
-
size = 1;
|
1165
|
-
else if (norm < 3)
|
1166
|
-
size = 2;
|
1167
|
-
else if (norm < 7.5)
|
1168
|
-
size = 5;
|
1169
|
-
else
|
1170
|
-
size = 10;
|
1699
|
+
size *= magn;
|
1171
1700
|
|
1172
|
-
|
1173
|
-
|
1701
|
+
if (opts.minTickSize != null && size < opts.minTickSize) {
|
1702
|
+
size = opts.minTickSize;
|
1703
|
+
}
|
1174
1704
|
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
var ticks = [],
|
1179
|
-
tickSize = axis.tickSize[0], unit = axis.tickSize[1],
|
1180
|
-
d = new Date(axis.min);
|
1181
|
-
|
1182
|
-
var step = tickSize * timeUnitSize[unit];
|
1183
|
-
|
1184
|
-
if (unit == "second")
|
1185
|
-
d.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));
|
1186
|
-
if (unit == "minute")
|
1187
|
-
d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));
|
1188
|
-
if (unit == "hour")
|
1189
|
-
d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));
|
1190
|
-
if (unit == "month")
|
1191
|
-
d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));
|
1192
|
-
if (unit == "year")
|
1193
|
-
d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));
|
1194
|
-
|
1195
|
-
// reset smaller components
|
1196
|
-
d.setUTCMilliseconds(0);
|
1197
|
-
if (step >= timeUnitSize.minute)
|
1198
|
-
d.setUTCSeconds(0);
|
1199
|
-
if (step >= timeUnitSize.hour)
|
1200
|
-
d.setUTCMinutes(0);
|
1201
|
-
if (step >= timeUnitSize.day)
|
1202
|
-
d.setUTCHours(0);
|
1203
|
-
if (step >= timeUnitSize.day * 4)
|
1204
|
-
d.setUTCDate(1);
|
1205
|
-
if (step >= timeUnitSize.year)
|
1206
|
-
d.setUTCMonth(0);
|
1207
|
-
|
1208
|
-
|
1209
|
-
var carry = 0, v = Number.NaN, prev;
|
1210
|
-
do {
|
1211
|
-
prev = v;
|
1212
|
-
v = d.getTime();
|
1213
|
-
ticks.push(v);
|
1214
|
-
if (unit == "month") {
|
1215
|
-
if (tickSize < 1) {
|
1216
|
-
// a bit complicated - we'll divide the month
|
1217
|
-
// up but we need to take care of fractions
|
1218
|
-
// so we don't end up in the middle of a day
|
1219
|
-
d.setUTCDate(1);
|
1220
|
-
var start = d.getTime();
|
1221
|
-
d.setUTCMonth(d.getUTCMonth() + 1);
|
1222
|
-
var end = d.getTime();
|
1223
|
-
d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
|
1224
|
-
carry = d.getUTCHours();
|
1225
|
-
d.setUTCHours(0);
|
1226
|
-
}
|
1227
|
-
else
|
1228
|
-
d.setUTCMonth(d.getUTCMonth() + tickSize);
|
1229
|
-
}
|
1230
|
-
else if (unit == "year") {
|
1231
|
-
d.setUTCFullYear(d.getUTCFullYear() + tickSize);
|
1232
|
-
}
|
1233
|
-
else
|
1234
|
-
d.setTime(v + step);
|
1235
|
-
} while (v < axis.max && v != prev);
|
1705
|
+
axis.delta = delta;
|
1706
|
+
axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
|
1707
|
+
axis.tickSize = opts.tickSize || size;
|
1236
1708
|
|
1237
|
-
|
1238
|
-
|
1709
|
+
// Time mode was moved to a plug-in in 0.8, but since so many people use this
|
1710
|
+
// we'll add an especially friendly make sure they remembered to include it.
|
1239
1711
|
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
// first check global format
|
1244
|
-
if (opts.timeformat != null)
|
1245
|
-
return $.plot.formatDate(d, opts.timeformat, opts.monthNames);
|
1246
|
-
|
1247
|
-
var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
|
1248
|
-
var span = axis.max - axis.min;
|
1249
|
-
var suffix = (opts.twelveHourClock) ? " %p" : "";
|
1250
|
-
|
1251
|
-
if (t < timeUnitSize.minute)
|
1252
|
-
fmt = "%h:%M:%S" + suffix;
|
1253
|
-
else if (t < timeUnitSize.day) {
|
1254
|
-
if (span < 2 * timeUnitSize.day)
|
1255
|
-
fmt = "%h:%M" + suffix;
|
1256
|
-
else
|
1257
|
-
fmt = "%b %d %h:%M" + suffix;
|
1258
|
-
}
|
1259
|
-
else if (t < timeUnitSize.month)
|
1260
|
-
fmt = "%b %d";
|
1261
|
-
else if (t < timeUnitSize.year) {
|
1262
|
-
if (span < timeUnitSize.year)
|
1263
|
-
fmt = "%b";
|
1264
|
-
else
|
1265
|
-
fmt = "%b %y";
|
1266
|
-
}
|
1267
|
-
else
|
1268
|
-
fmt = "%y";
|
1269
|
-
|
1270
|
-
return $.plot.formatDate(d, fmt, opts.monthNames);
|
1271
|
-
};
|
1712
|
+
if (opts.mode == "time" && !axis.tickGenerator) {
|
1713
|
+
throw new Error("Time mode requires the flot.time plugin.");
|
1272
1714
|
}
|
1273
|
-
else {
|
1274
|
-
// pretty rounding of base-10 numbers
|
1275
|
-
var maxDec = opts.tickDecimals;
|
1276
|
-
var dec = -Math.floor(Math.log(delta) / Math.LN10);
|
1277
|
-
if (maxDec != null && dec > maxDec)
|
1278
|
-
dec = maxDec;
|
1279
|
-
|
1280
|
-
magn = Math.pow(10, -dec);
|
1281
|
-
norm = delta / magn; // norm is between 1.0 and 10.0
|
1282
|
-
|
1283
|
-
if (norm < 1.5)
|
1284
|
-
size = 1;
|
1285
|
-
else if (norm < 3) {
|
1286
|
-
size = 2;
|
1287
|
-
// special case for 2.5, requires an extra decimal
|
1288
|
-
if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
|
1289
|
-
size = 2.5;
|
1290
|
-
++dec;
|
1291
|
-
}
|
1292
|
-
}
|
1293
|
-
else if (norm < 7.5)
|
1294
|
-
size = 5;
|
1295
|
-
else
|
1296
|
-
size = 10;
|
1297
1715
|
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1716
|
+
// Flot supports base-10 axes; any other mode else is handled by a plug-in,
|
1717
|
+
// like flot.time.js.
|
1718
|
+
|
1719
|
+
if (!axis.tickGenerator) {
|
1302
1720
|
|
1303
|
-
axis.
|
1304
|
-
axis.tickSize = opts.tickSize || size;
|
1721
|
+
axis.tickGenerator = function (axis) {
|
1305
1722
|
|
1306
|
-
|
1307
|
-
|
1723
|
+
var ticks = [],
|
1724
|
+
start = floorInBase(axis.min, axis.tickSize),
|
1725
|
+
i = 0,
|
1726
|
+
v = Number.NaN,
|
1727
|
+
prev;
|
1308
1728
|
|
1309
|
-
// spew out all possible ticks
|
1310
|
-
var start = floorInBase(axis.min, axis.tickSize),
|
1311
|
-
i = 0, v = Number.NaN, prev;
|
1312
1729
|
do {
|
1313
1730
|
prev = v;
|
1314
1731
|
v = start + i * axis.tickSize;
|
@@ -1318,24 +1735,42 @@
|
|
1318
1735
|
return ticks;
|
1319
1736
|
};
|
1320
1737
|
|
1321
|
-
|
1322
|
-
|
1738
|
+
axis.tickFormatter = function (value, axis) {
|
1739
|
+
|
1740
|
+
var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
|
1741
|
+
var formatted = "" + Math.round(value * factor) / factor;
|
1742
|
+
|
1743
|
+
// If tickDecimals was specified, ensure that we have exactly that
|
1744
|
+
// much precision; otherwise default to the value's own precision.
|
1745
|
+
|
1746
|
+
if (axis.tickDecimals != null) {
|
1747
|
+
var decimal = formatted.indexOf(".");
|
1748
|
+
var precision = decimal == -1 ? 0 : formatted.length - decimal - 1;
|
1749
|
+
if (precision < axis.tickDecimals) {
|
1750
|
+
return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
|
1751
|
+
}
|
1752
|
+
}
|
1753
|
+
|
1754
|
+
return formatted;
|
1323
1755
|
};
|
1324
1756
|
}
|
1325
1757
|
|
1758
|
+
if ($.isFunction(opts.tickFormatter))
|
1759
|
+
axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
|
1760
|
+
|
1326
1761
|
if (opts.alignTicksWithAxis != null) {
|
1327
1762
|
var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
|
1328
1763
|
if (otherAxis && otherAxis.used && otherAxis != axis) {
|
1329
1764
|
// consider snapping min/max to outermost nice ticks
|
1330
|
-
var niceTicks =
|
1765
|
+
var niceTicks = axis.tickGenerator(axis);
|
1331
1766
|
if (niceTicks.length > 0) {
|
1332
1767
|
if (opts.min == null)
|
1333
1768
|
axis.min = Math.min(axis.min, niceTicks[0]);
|
1334
1769
|
if (opts.max == null && niceTicks.length > 1)
|
1335
1770
|
axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
|
1336
1771
|
}
|
1337
|
-
|
1338
|
-
|
1772
|
+
|
1773
|
+
axis.tickGenerator = function (axis) {
|
1339
1774
|
// copy ticks, scaled to this axis
|
1340
1775
|
var ticks = [], v, i;
|
1341
1776
|
for (i = 0; i < otherAxis.ticks.length; ++i) {
|
@@ -1345,12 +1780,12 @@
|
|
1345
1780
|
}
|
1346
1781
|
return ticks;
|
1347
1782
|
};
|
1348
|
-
|
1783
|
+
|
1349
1784
|
// we might need an extra decimal since forced
|
1350
1785
|
// ticks don't necessarily fit naturally
|
1351
|
-
if (axis.mode
|
1352
|
-
var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),
|
1353
|
-
ts =
|
1786
|
+
if (!axis.mode && opts.tickDecimals == null) {
|
1787
|
+
var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
|
1788
|
+
ts = axis.tickGenerator(axis);
|
1354
1789
|
|
1355
1790
|
// only proceed if the tick interval rounded
|
1356
1791
|
// with an extra decimal doesn't give us a
|
@@ -1360,14 +1795,8 @@
|
|
1360
1795
|
}
|
1361
1796
|
}
|
1362
1797
|
}
|
1363
|
-
|
1364
|
-
axis.tickGenerator = generator;
|
1365
|
-
if ($.isFunction(opts.tickFormatter))
|
1366
|
-
axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
|
1367
|
-
else
|
1368
|
-
axis.tickFormatter = formatter;
|
1369
1798
|
}
|
1370
|
-
|
1799
|
+
|
1371
1800
|
function setTicks(axis) {
|
1372
1801
|
var oticks = axis.options.ticks, ticks = [];
|
1373
1802
|
if (oticks == null || (typeof oticks == "number" && oticks > 0))
|
@@ -1375,7 +1804,7 @@
|
|
1375
1804
|
else if (oticks) {
|
1376
1805
|
if ($.isFunction(oticks))
|
1377
1806
|
// generate the ticks
|
1378
|
-
ticks = oticks(
|
1807
|
+
ticks = oticks(axis);
|
1379
1808
|
else
|
1380
1809
|
ticks = oticks;
|
1381
1810
|
}
|
@@ -1409,18 +1838,22 @@
|
|
1409
1838
|
axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
|
1410
1839
|
}
|
1411
1840
|
}
|
1412
|
-
|
1841
|
+
|
1413
1842
|
function draw() {
|
1414
|
-
|
1843
|
+
|
1844
|
+
surface.clear();
|
1845
|
+
|
1846
|
+
executeHooks(hooks.drawBackground, [ctx]);
|
1415
1847
|
|
1416
1848
|
var grid = options.grid;
|
1417
1849
|
|
1418
1850
|
// draw background, if any
|
1419
1851
|
if (grid.show && grid.backgroundColor)
|
1420
1852
|
drawBackground();
|
1421
|
-
|
1422
|
-
if (grid.show && !grid.aboveData)
|
1853
|
+
|
1854
|
+
if (grid.show && !grid.aboveData) {
|
1423
1855
|
drawGrid();
|
1856
|
+
}
|
1424
1857
|
|
1425
1858
|
for (var i = 0; i < series.length; ++i) {
|
1426
1859
|
executeHooks(hooks.drawSeries, [ctx, series[i]]);
|
@@ -1428,15 +1861,23 @@
|
|
1428
1861
|
}
|
1429
1862
|
|
1430
1863
|
executeHooks(hooks.draw, [ctx]);
|
1431
|
-
|
1432
|
-
if (grid.show && grid.aboveData)
|
1864
|
+
|
1865
|
+
if (grid.show && grid.aboveData) {
|
1433
1866
|
drawGrid();
|
1867
|
+
}
|
1868
|
+
|
1869
|
+
surface.render();
|
1870
|
+
|
1871
|
+
// A draw implies that either the axes or data have changed, so we
|
1872
|
+
// should probably update the overlay highlights as well.
|
1873
|
+
|
1874
|
+
triggerRedrawOverlay();
|
1434
1875
|
}
|
1435
1876
|
|
1436
1877
|
function extractRange(ranges, coord) {
|
1437
1878
|
var axis, from, to, key, axes = allAxes();
|
1438
1879
|
|
1439
|
-
for (i = 0; i < axes.length; ++i) {
|
1880
|
+
for (var i = 0; i < axes.length; ++i) {
|
1440
1881
|
axis = axes[i];
|
1441
1882
|
if (axis.direction == coord) {
|
1442
1883
|
key = coord + axis.n + "axis";
|
@@ -1463,10 +1904,10 @@
|
|
1463
1904
|
from = to;
|
1464
1905
|
to = tmp;
|
1465
1906
|
}
|
1466
|
-
|
1907
|
+
|
1467
1908
|
return { from: from, to: to, axis: axis };
|
1468
1909
|
}
|
1469
|
-
|
1910
|
+
|
1470
1911
|
function drawBackground() {
|
1471
1912
|
ctx.save();
|
1472
1913
|
ctx.translate(plotOffset.left, plotOffset.top);
|
@@ -1477,8 +1918,8 @@
|
|
1477
1918
|
}
|
1478
1919
|
|
1479
1920
|
function drawGrid() {
|
1480
|
-
var i;
|
1481
|
-
|
1921
|
+
var i, axes, bw, bc;
|
1922
|
+
|
1482
1923
|
ctx.save();
|
1483
1924
|
ctx.translate(plotOffset.left, plotOffset.top);
|
1484
1925
|
|
@@ -1486,14 +1927,14 @@
|
|
1486
1927
|
var markings = options.grid.markings;
|
1487
1928
|
if (markings) {
|
1488
1929
|
if ($.isFunction(markings)) {
|
1489
|
-
|
1930
|
+
axes = plot.getAxes();
|
1490
1931
|
// xmin etc. is backwards compatibility, to be
|
1491
1932
|
// removed in the future
|
1492
1933
|
axes.xmin = axes.xaxis.min;
|
1493
1934
|
axes.xmax = axes.xaxis.max;
|
1494
1935
|
axes.ymin = axes.yaxis.min;
|
1495
1936
|
axes.ymax = axes.yaxis.max;
|
1496
|
-
|
1937
|
+
|
1497
1938
|
markings = markings(axes);
|
1498
1939
|
}
|
1499
1940
|
|
@@ -1530,7 +1971,7 @@
|
|
1530
1971
|
xrange.to = xrange.axis.p2c(xrange.to);
|
1531
1972
|
yrange.from = yrange.axis.p2c(yrange.from);
|
1532
1973
|
yrange.to = yrange.axis.p2c(yrange.to);
|
1533
|
-
|
1974
|
+
|
1534
1975
|
if (xrange.from == xrange.to || yrange.from == yrange.to) {
|
1535
1976
|
// draw line
|
1536
1977
|
ctx.beginPath();
|
@@ -1549,17 +1990,17 @@
|
|
1549
1990
|
}
|
1550
1991
|
}
|
1551
1992
|
}
|
1552
|
-
|
1993
|
+
|
1553
1994
|
// draw the ticks
|
1554
|
-
|
1995
|
+
axes = allAxes();
|
1996
|
+
bw = options.grid.borderWidth;
|
1555
1997
|
|
1556
1998
|
for (var j = 0; j < axes.length; ++j) {
|
1557
1999
|
var axis = axes[j], box = axis.box,
|
1558
2000
|
t = axis.tickLength, x, y, xoff, yoff;
|
1559
2001
|
if (!axis.show || axis.ticks.length == 0)
|
1560
|
-
continue
|
1561
|
-
|
1562
|
-
ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();
|
2002
|
+
continue;
|
2003
|
+
|
1563
2004
|
ctx.lineWidth = 1;
|
1564
2005
|
|
1565
2006
|
// find the edges
|
@@ -1577,19 +2018,23 @@
|
|
1577
2018
|
else
|
1578
2019
|
x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
|
1579
2020
|
}
|
1580
|
-
|
2021
|
+
|
1581
2022
|
// draw tick bar
|
1582
2023
|
if (!axis.innermost) {
|
2024
|
+
ctx.strokeStyle = axis.options.color;
|
1583
2025
|
ctx.beginPath();
|
1584
2026
|
xoff = yoff = 0;
|
1585
2027
|
if (axis.direction == "x")
|
1586
|
-
xoff = plotWidth;
|
2028
|
+
xoff = plotWidth + 1;
|
1587
2029
|
else
|
1588
|
-
yoff = plotHeight;
|
1589
|
-
|
2030
|
+
yoff = plotHeight + 1;
|
2031
|
+
|
1590
2032
|
if (ctx.lineWidth == 1) {
|
1591
|
-
|
1592
|
-
|
2033
|
+
if (axis.direction == "x") {
|
2034
|
+
y = Math.floor(y) + 0.5;
|
2035
|
+
} else {
|
2036
|
+
x = Math.floor(x) + 0.5;
|
2037
|
+
}
|
1593
2038
|
}
|
1594
2039
|
|
1595
2040
|
ctx.moveTo(x, y);
|
@@ -1598,29 +2043,33 @@
|
|
1598
2043
|
}
|
1599
2044
|
|
1600
2045
|
// draw ticks
|
2046
|
+
|
2047
|
+
ctx.strokeStyle = axis.options.tickColor;
|
2048
|
+
|
1601
2049
|
ctx.beginPath();
|
1602
2050
|
for (i = 0; i < axis.ticks.length; ++i) {
|
1603
2051
|
var v = axis.ticks[i].v;
|
1604
|
-
|
2052
|
+
|
1605
2053
|
xoff = yoff = 0;
|
1606
2054
|
|
1607
|
-
if (v < axis.min || v > axis.max
|
2055
|
+
if (isNaN(v) || v < axis.min || v > axis.max
|
1608
2056
|
// skip those lying on the axes if we got a border
|
1609
|
-
|| (t == "full"
|
2057
|
+
|| (t == "full"
|
2058
|
+
&& ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0)
|
1610
2059
|
&& (v == axis.min || v == axis.max)))
|
1611
2060
|
continue;
|
1612
2061
|
|
1613
2062
|
if (axis.direction == "x") {
|
1614
2063
|
x = axis.p2c(v);
|
1615
2064
|
yoff = t == "full" ? -plotHeight : t;
|
1616
|
-
|
2065
|
+
|
1617
2066
|
if (axis.position == "top")
|
1618
2067
|
yoff = -yoff;
|
1619
2068
|
}
|
1620
2069
|
else {
|
1621
2070
|
y = axis.p2c(v);
|
1622
2071
|
xoff = t == "full" ? -plotWidth : t;
|
1623
|
-
|
2072
|
+
|
1624
2073
|
if (axis.position == "left")
|
1625
2074
|
xoff = -xoff;
|
1626
2075
|
}
|
@@ -1635,74 +2084,117 @@
|
|
1635
2084
|
ctx.moveTo(x, y);
|
1636
2085
|
ctx.lineTo(x + xoff, y + yoff);
|
1637
2086
|
}
|
1638
|
-
|
2087
|
+
|
1639
2088
|
ctx.stroke();
|
1640
2089
|
}
|
1641
|
-
|
1642
|
-
|
2090
|
+
|
2091
|
+
|
1643
2092
|
// draw border
|
1644
2093
|
if (bw) {
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
2094
|
+
// If either borderWidth or borderColor is an object, then draw the border
|
2095
|
+
// line by line instead of as one rectangle
|
2096
|
+
bc = options.grid.borderColor;
|
2097
|
+
if(typeof bw == "object" || typeof bc == "object") {
|
2098
|
+
if (typeof bw !== "object") {
|
2099
|
+
bw = {top: bw, right: bw, bottom: bw, left: bw};
|
2100
|
+
}
|
2101
|
+
if (typeof bc !== "object") {
|
2102
|
+
bc = {top: bc, right: bc, bottom: bc, left: bc};
|
2103
|
+
}
|
2104
|
+
|
2105
|
+
if (bw.top > 0) {
|
2106
|
+
ctx.strokeStyle = bc.top;
|
2107
|
+
ctx.lineWidth = bw.top;
|
2108
|
+
ctx.beginPath();
|
2109
|
+
ctx.moveTo(0 - bw.left, 0 - bw.top/2);
|
2110
|
+
ctx.lineTo(plotWidth, 0 - bw.top/2);
|
2111
|
+
ctx.stroke();
|
2112
|
+
}
|
2113
|
+
|
2114
|
+
if (bw.right > 0) {
|
2115
|
+
ctx.strokeStyle = bc.right;
|
2116
|
+
ctx.lineWidth = bw.right;
|
2117
|
+
ctx.beginPath();
|
2118
|
+
ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top);
|
2119
|
+
ctx.lineTo(plotWidth + bw.right / 2, plotHeight);
|
2120
|
+
ctx.stroke();
|
2121
|
+
}
|
2122
|
+
|
2123
|
+
if (bw.bottom > 0) {
|
2124
|
+
ctx.strokeStyle = bc.bottom;
|
2125
|
+
ctx.lineWidth = bw.bottom;
|
2126
|
+
ctx.beginPath();
|
2127
|
+
ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2);
|
2128
|
+
ctx.lineTo(0, plotHeight + bw.bottom / 2);
|
2129
|
+
ctx.stroke();
|
2130
|
+
}
|
2131
|
+
|
2132
|
+
if (bw.left > 0) {
|
2133
|
+
ctx.strokeStyle = bc.left;
|
2134
|
+
ctx.lineWidth = bw.left;
|
2135
|
+
ctx.beginPath();
|
2136
|
+
ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom);
|
2137
|
+
ctx.lineTo(0- bw.left/2, 0);
|
2138
|
+
ctx.stroke();
|
2139
|
+
}
|
2140
|
+
}
|
2141
|
+
else {
|
2142
|
+
ctx.lineWidth = bw;
|
2143
|
+
ctx.strokeStyle = options.grid.borderColor;
|
2144
|
+
ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
|
2145
|
+
}
|
1648
2146
|
}
|
1649
2147
|
|
1650
2148
|
ctx.restore();
|
1651
2149
|
}
|
1652
2150
|
|
1653
|
-
function
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
2151
|
+
function drawAxisLabels() {
|
2152
|
+
|
2153
|
+
$.each(allAxes(), function (_, axis) {
|
2154
|
+
var box = axis.box,
|
2155
|
+
legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
|
2156
|
+
layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
|
2157
|
+
font = axis.options.font || "flot-tick-label tickLabel",
|
2158
|
+
tick, x, y, halign, valign;
|
2159
|
+
|
2160
|
+
// Remove text before checking for axis.show and ticks.length;
|
2161
|
+
// otherwise plugins, like flot-tickrotor, that draw their own
|
2162
|
+
// tick labels will end up with both theirs and the defaults.
|
2163
|
+
|
2164
|
+
surface.removeText(layer);
|
2165
|
+
|
2166
|
+
if (!axis.show || axis.ticks.length == 0)
|
2167
|
+
return;
|
1657
2168
|
|
1658
|
-
var axes = allAxes();
|
1659
|
-
for (var j = 0; j < axes.length; ++j) {
|
1660
|
-
var axis = axes[j], box = axis.box;
|
1661
|
-
if (!axis.show)
|
1662
|
-
continue;
|
1663
|
-
//debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
|
1664
|
-
html.push('<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis" style="color:' + axis.options.color + '">');
|
1665
2169
|
for (var i = 0; i < axis.ticks.length; ++i) {
|
1666
|
-
|
2170
|
+
|
2171
|
+
tick = axis.ticks[i];
|
1667
2172
|
if (!tick.label || tick.v < axis.min || tick.v > axis.max)
|
1668
2173
|
continue;
|
1669
2174
|
|
1670
|
-
var pos = {}, align;
|
1671
|
-
|
1672
2175
|
if (axis.direction == "x") {
|
1673
|
-
|
1674
|
-
|
1675
|
-
if (axis.position == "bottom")
|
1676
|
-
|
1677
|
-
else
|
1678
|
-
|
1679
|
-
|
1680
|
-
else {
|
1681
|
-
pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);
|
1682
|
-
if (axis.position == "left") {
|
1683
|
-
pos.right = canvasWidth - (box.left + box.width - box.padding)
|
1684
|
-
align = "right";
|
2176
|
+
halign = "center";
|
2177
|
+
x = plotOffset.left + axis.p2c(tick.v);
|
2178
|
+
if (axis.position == "bottom") {
|
2179
|
+
y = box.top + box.padding;
|
2180
|
+
} else {
|
2181
|
+
y = box.top + box.height - box.padding;
|
2182
|
+
valign = "bottom";
|
1685
2183
|
}
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
2184
|
+
} else {
|
2185
|
+
valign = "middle";
|
2186
|
+
y = plotOffset.top + axis.p2c(tick.v);
|
2187
|
+
if (axis.position == "left") {
|
2188
|
+
x = box.left + box.width - box.padding;
|
2189
|
+
halign = "right";
|
2190
|
+
} else {
|
2191
|
+
x = box.left + box.padding;
|
1689
2192
|
}
|
1690
2193
|
}
|
1691
2194
|
|
1692
|
-
|
1693
|
-
|
1694
|
-
var style = ["position:absolute", "text-align:" + align ];
|
1695
|
-
for (var a in pos)
|
1696
|
-
style.push(a + ":" + pos[a] + "px")
|
1697
|
-
|
1698
|
-
html.push('<div class="tickLabel" style="' + style.join(';') + '">' + tick.label + '</div>');
|
2195
|
+
surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);
|
1699
2196
|
}
|
1700
|
-
|
1701
|
-
}
|
1702
|
-
|
1703
|
-
html.push('</div>');
|
1704
|
-
|
1705
|
-
placeholder.append(html.join(""));
|
2197
|
+
});
|
1706
2198
|
}
|
1707
2199
|
|
1708
2200
|
function drawSeries(series) {
|
@@ -1713,18 +2205,18 @@
|
|
1713
2205
|
if (series.points.show)
|
1714
2206
|
drawSeriesPoints(series);
|
1715
2207
|
}
|
1716
|
-
|
2208
|
+
|
1717
2209
|
function drawSeriesLines(series) {
|
1718
2210
|
function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
|
1719
2211
|
var points = datapoints.points,
|
1720
2212
|
ps = datapoints.pointsize,
|
1721
2213
|
prevx = null, prevy = null;
|
1722
|
-
|
2214
|
+
|
1723
2215
|
ctx.beginPath();
|
1724
2216
|
for (var i = ps; i < points.length; i += ps) {
|
1725
2217
|
var x1 = points[i - ps], y1 = points[i - ps + 1],
|
1726
2218
|
x2 = points[i], y2 = points[i + 1];
|
1727
|
-
|
2219
|
+
|
1728
2220
|
if (x1 == null || x2 == null)
|
1729
2221
|
continue;
|
1730
2222
|
|
@@ -1787,7 +2279,7 @@
|
|
1787
2279
|
|
1788
2280
|
if (x1 != prevx || y1 != prevy)
|
1789
2281
|
ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
|
1790
|
-
|
2282
|
+
|
1791
2283
|
prevx = x2;
|
1792
2284
|
prevy = y2;
|
1793
2285
|
ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
|
@@ -1839,7 +2331,7 @@
|
|
1839
2331
|
continue;
|
1840
2332
|
|
1841
2333
|
// clip x values
|
1842
|
-
|
2334
|
+
|
1843
2335
|
// clip with xmin
|
1844
2336
|
if (x1 <= x2 && x1 < axisx.min) {
|
1845
2337
|
if (x2 < axisx.min)
|
@@ -1874,7 +2366,7 @@
|
|
1874
2366
|
ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
|
1875
2367
|
areaOpen = true;
|
1876
2368
|
}
|
1877
|
-
|
2369
|
+
|
1878
2370
|
// now first check the case where both is outside
|
1879
2371
|
if (y1 >= axisy.max && y2 >= axisy.max) {
|
1880
2372
|
ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
|
@@ -1886,7 +2378,7 @@
|
|
1886
2378
|
ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
|
1887
2379
|
continue;
|
1888
2380
|
}
|
1889
|
-
|
2381
|
+
|
1890
2382
|
// else it's a bit more complicated, there might
|
1891
2383
|
// be a flat maxed out rectangle first, then a
|
1892
2384
|
// triangular cutout or reverse; to find these
|
@@ -1895,7 +2387,7 @@
|
|
1895
2387
|
|
1896
2388
|
// clip the y values, without shortcutting, we
|
1897
2389
|
// go through all cases in turn
|
1898
|
-
|
2390
|
+
|
1899
2391
|
// clip with ymin
|
1900
2392
|
if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
|
1901
2393
|
x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
|
@@ -1922,7 +2414,7 @@
|
|
1922
2414
|
ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
|
1923
2415
|
// it goes to (x1, y1), but we fill that below
|
1924
2416
|
}
|
1925
|
-
|
2417
|
+
|
1926
2418
|
// fill triangular section, this sometimes result
|
1927
2419
|
// in redundant points if (x1, y1) hasn't changed
|
1928
2420
|
// from previous line to, but we just ignore that
|
@@ -1976,7 +2468,7 @@
|
|
1976
2468
|
var x = points[i], y = points[i + 1];
|
1977
2469
|
if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
|
1978
2470
|
continue;
|
1979
|
-
|
2471
|
+
|
1980
2472
|
ctx.beginPath();
|
1981
2473
|
x = axisx.p2c(x);
|
1982
2474
|
y = axisy.p2c(y) + offset;
|
@@ -1985,7 +2477,7 @@
|
|
1985
2477
|
else
|
1986
2478
|
symbol(ctx, x, y, radius, shadow);
|
1987
2479
|
ctx.closePath();
|
1988
|
-
|
2480
|
+
|
1989
2481
|
if (fillStyle) {
|
1990
2482
|
ctx.fillStyle = fillStyle;
|
1991
2483
|
ctx.fill();
|
@@ -1993,7 +2485,7 @@
|
|
1993
2485
|
ctx.stroke();
|
1994
2486
|
}
|
1995
2487
|
}
|
1996
|
-
|
2488
|
+
|
1997
2489
|
ctx.save();
|
1998
2490
|
ctx.translate(plotOffset.left, plotOffset.top);
|
1999
2491
|
|
@@ -2001,6 +2493,15 @@
|
|
2001
2493
|
sw = series.shadowSize,
|
2002
2494
|
radius = series.points.radius,
|
2003
2495
|
symbol = series.points.symbol;
|
2496
|
+
|
2497
|
+
// If the user sets the line width to 0, we change it to a very
|
2498
|
+
// small value. A line width of 0 seems to force the default of 1.
|
2499
|
+
// Doing the conditional here allows the shadow setting to still be
|
2500
|
+
// optional even with a lineWidth of 0.
|
2501
|
+
|
2502
|
+
if( lw == 0 )
|
2503
|
+
lw = 0.0001;
|
2504
|
+
|
2004
2505
|
if (lw > 0 && sw > 0) {
|
2005
2506
|
// draw shadow in two steps
|
2006
2507
|
var w = sw / 2;
|
@@ -2022,7 +2523,7 @@
|
|
2022
2523
|
ctx.restore();
|
2023
2524
|
}
|
2024
2525
|
|
2025
|
-
function drawBar(x, y, b, barLeft, barRight,
|
2526
|
+
function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
|
2026
2527
|
var left, right, bottom, top,
|
2027
2528
|
drawLeft, drawRight, drawTop, drawBottom,
|
2028
2529
|
tmp;
|
@@ -2064,12 +2565,12 @@
|
|
2064
2565
|
drawTop = false;
|
2065
2566
|
}
|
2066
2567
|
}
|
2067
|
-
|
2568
|
+
|
2068
2569
|
// clip
|
2069
2570
|
if (right < axisx.min || left > axisx.max ||
|
2070
2571
|
top < axisy.min || bottom > axisy.max)
|
2071
2572
|
return;
|
2072
|
-
|
2573
|
+
|
2073
2574
|
if (left < axisx.min) {
|
2074
2575
|
left = axisx.min;
|
2075
2576
|
drawLeft = false;
|
@@ -2084,7 +2585,7 @@
|
|
2084
2585
|
bottom = axisy.min;
|
2085
2586
|
drawBottom = false;
|
2086
2587
|
}
|
2087
|
-
|
2588
|
+
|
2088
2589
|
if (top > axisy.max) {
|
2089
2590
|
top = axisy.max;
|
2090
2591
|
drawTop = false;
|
@@ -2094,16 +2595,11 @@
|
|
2094
2595
|
bottom = axisy.p2c(bottom);
|
2095
2596
|
right = axisx.p2c(right);
|
2096
2597
|
top = axisy.p2c(top);
|
2097
|
-
|
2598
|
+
|
2098
2599
|
// fill the bar
|
2099
2600
|
if (fillStyleCallback) {
|
2100
|
-
c.beginPath();
|
2101
|
-
c.moveTo(left, bottom);
|
2102
|
-
c.lineTo(left, top);
|
2103
|
-
c.lineTo(right, top);
|
2104
|
-
c.lineTo(right, bottom);
|
2105
2601
|
c.fillStyle = fillStyleCallback(bottom, top);
|
2106
|
-
c.
|
2602
|
+
c.fillRect(left, top, right - left, bottom - top)
|
2107
2603
|
}
|
2108
2604
|
|
2109
2605
|
// draw outline
|
@@ -2111,35 +2607,35 @@
|
|
2111
2607
|
c.beginPath();
|
2112
2608
|
|
2113
2609
|
// FIXME: inline moveTo is buggy with excanvas
|
2114
|
-
c.moveTo(left, bottom
|
2610
|
+
c.moveTo(left, bottom);
|
2115
2611
|
if (drawLeft)
|
2116
|
-
c.lineTo(left, top
|
2612
|
+
c.lineTo(left, top);
|
2117
2613
|
else
|
2118
|
-
c.moveTo(left, top
|
2614
|
+
c.moveTo(left, top);
|
2119
2615
|
if (drawTop)
|
2120
|
-
c.lineTo(right, top
|
2616
|
+
c.lineTo(right, top);
|
2121
2617
|
else
|
2122
|
-
c.moveTo(right, top
|
2618
|
+
c.moveTo(right, top);
|
2123
2619
|
if (drawRight)
|
2124
|
-
c.lineTo(right, bottom
|
2620
|
+
c.lineTo(right, bottom);
|
2125
2621
|
else
|
2126
|
-
c.moveTo(right, bottom
|
2622
|
+
c.moveTo(right, bottom);
|
2127
2623
|
if (drawBottom)
|
2128
|
-
c.lineTo(left, bottom
|
2624
|
+
c.lineTo(left, bottom);
|
2129
2625
|
else
|
2130
|
-
c.moveTo(left, bottom
|
2626
|
+
c.moveTo(left, bottom);
|
2131
2627
|
c.stroke();
|
2132
2628
|
}
|
2133
2629
|
}
|
2134
|
-
|
2630
|
+
|
2135
2631
|
function drawSeriesBars(series) {
|
2136
|
-
function plotBars(datapoints, barLeft, barRight,
|
2632
|
+
function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
|
2137
2633
|
var points = datapoints.points, ps = datapoints.pointsize;
|
2138
|
-
|
2634
|
+
|
2139
2635
|
for (var i = 0; i < points.length; i += ps) {
|
2140
2636
|
if (points[i] == null)
|
2141
2637
|
continue;
|
2142
|
-
drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight,
|
2638
|
+
drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
|
2143
2639
|
}
|
2144
2640
|
}
|
2145
2641
|
|
@@ -2149,9 +2645,22 @@
|
|
2149
2645
|
// FIXME: figure out a way to add shadows (for instance along the right edge)
|
2150
2646
|
ctx.lineWidth = series.bars.lineWidth;
|
2151
2647
|
ctx.strokeStyle = series.color;
|
2152
|
-
|
2648
|
+
|
2649
|
+
var barLeft;
|
2650
|
+
|
2651
|
+
switch (series.bars.align) {
|
2652
|
+
case "left":
|
2653
|
+
barLeft = 0;
|
2654
|
+
break;
|
2655
|
+
case "right":
|
2656
|
+
barLeft = -series.bars.barWidth;
|
2657
|
+
break;
|
2658
|
+
default:
|
2659
|
+
barLeft = -series.bars.barWidth / 2;
|
2660
|
+
}
|
2661
|
+
|
2153
2662
|
var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
|
2154
|
-
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth,
|
2663
|
+
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
|
2155
2664
|
ctx.restore();
|
2156
2665
|
}
|
2157
2666
|
|
@@ -2162,27 +2671,66 @@
|
|
2162
2671
|
|
2163
2672
|
if (filloptions.fillColor)
|
2164
2673
|
return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
|
2165
|
-
|
2674
|
+
|
2166
2675
|
var c = $.color.parse(seriesColor);
|
2167
2676
|
c.a = typeof fill == "number" ? fill : 0.4;
|
2168
2677
|
c.normalize();
|
2169
2678
|
return c.toString();
|
2170
2679
|
}
|
2171
|
-
|
2680
|
+
|
2172
2681
|
function insertLegend() {
|
2173
|
-
placeholder.find(".legend").remove();
|
2174
2682
|
|
2175
|
-
if (
|
2683
|
+
if (options.legend.container != null) {
|
2684
|
+
$(options.legend.container).html("");
|
2685
|
+
} else {
|
2686
|
+
placeholder.find(".legend").remove();
|
2687
|
+
}
|
2688
|
+
|
2689
|
+
if (!options.legend.show) {
|
2176
2690
|
return;
|
2177
|
-
|
2178
|
-
|
2691
|
+
}
|
2692
|
+
|
2693
|
+
var fragments = [], entries = [], rowStarted = false,
|
2179
2694
|
lf = options.legend.labelFormatter, s, label;
|
2695
|
+
|
2696
|
+
// Build a list of legend entries, with each having a label and a color
|
2697
|
+
|
2180
2698
|
for (var i = 0; i < series.length; ++i) {
|
2181
2699
|
s = series[i];
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2700
|
+
if (s.label) {
|
2701
|
+
label = lf ? lf(s.label, s) : s.label;
|
2702
|
+
if (label) {
|
2703
|
+
entries.push({
|
2704
|
+
label: label,
|
2705
|
+
color: s.color
|
2706
|
+
});
|
2707
|
+
}
|
2708
|
+
}
|
2709
|
+
}
|
2710
|
+
|
2711
|
+
// Sort the legend using either the default or a custom comparator
|
2712
|
+
|
2713
|
+
if (options.legend.sorted) {
|
2714
|
+
if ($.isFunction(options.legend.sorted)) {
|
2715
|
+
entries.sort(options.legend.sorted);
|
2716
|
+
} else if (options.legend.sorted == "reverse") {
|
2717
|
+
entries.reverse();
|
2718
|
+
} else {
|
2719
|
+
var ascending = options.legend.sorted != "descending";
|
2720
|
+
entries.sort(function(a, b) {
|
2721
|
+
return a.label == b.label ? 0 : (
|
2722
|
+
(a.label < b.label) != ascending ? 1 : -1 // Logical XOR
|
2723
|
+
);
|
2724
|
+
});
|
2725
|
+
}
|
2726
|
+
}
|
2727
|
+
|
2728
|
+
// Generate markup for the list of entries, in their final order
|
2729
|
+
|
2730
|
+
for (var i = 0; i < entries.length; ++i) {
|
2731
|
+
|
2732
|
+
var entry = entries[i];
|
2733
|
+
|
2186
2734
|
if (i % options.legend.noColumns == 0) {
|
2187
2735
|
if (rowStarted)
|
2188
2736
|
fragments.push('</tr>');
|
@@ -2190,16 +2738,15 @@
|
|
2190
2738
|
rowStarted = true;
|
2191
2739
|
}
|
2192
2740
|
|
2193
|
-
if (lf)
|
2194
|
-
label = lf(label, s);
|
2195
|
-
|
2196
2741
|
fragments.push(
|
2197
|
-
'<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' +
|
2198
|
-
'<td class="legendLabel">' + label + '</td>'
|
2742
|
+
'<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' +
|
2743
|
+
'<td class="legendLabel">' + entry.label + '</td>'
|
2744
|
+
);
|
2199
2745
|
}
|
2746
|
+
|
2200
2747
|
if (rowStarted)
|
2201
2748
|
fragments.push('</tr>');
|
2202
|
-
|
2749
|
+
|
2203
2750
|
if (fragments.length == 0)
|
2204
2751
|
return;
|
2205
2752
|
|
@@ -2243,43 +2790,43 @@
|
|
2243
2790
|
|
2244
2791
|
|
2245
2792
|
// interactive features
|
2246
|
-
|
2793
|
+
|
2247
2794
|
var highlights = [],
|
2248
2795
|
redrawTimeout = null;
|
2249
|
-
|
2796
|
+
|
2250
2797
|
// returns the data item the mouse is over, or null if none is found
|
2251
2798
|
function findNearbyItem(mouseX, mouseY, seriesFilter) {
|
2252
2799
|
var maxDistance = options.grid.mouseActiveRadius,
|
2253
2800
|
smallestDistance = maxDistance * maxDistance + 1,
|
2254
|
-
item = null, foundPoint = false, i, j;
|
2801
|
+
item = null, foundPoint = false, i, j, ps;
|
2255
2802
|
|
2256
2803
|
for (i = series.length - 1; i >= 0; --i) {
|
2257
2804
|
if (!seriesFilter(series[i]))
|
2258
2805
|
continue;
|
2259
|
-
|
2806
|
+
|
2260
2807
|
var s = series[i],
|
2261
2808
|
axisx = s.xaxis,
|
2262
2809
|
axisy = s.yaxis,
|
2263
2810
|
points = s.datapoints.points,
|
2264
|
-
ps = s.datapoints.pointsize,
|
2265
2811
|
mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
|
2266
2812
|
my = axisy.c2p(mouseY),
|
2267
2813
|
maxx = maxDistance / axisx.scale,
|
2268
2814
|
maxy = maxDistance / axisy.scale;
|
2269
2815
|
|
2816
|
+
ps = s.datapoints.pointsize;
|
2270
2817
|
// with inverse transforms, we can't use the maxx/maxy
|
2271
2818
|
// optimization, sadly
|
2272
2819
|
if (axisx.options.inverseTransform)
|
2273
2820
|
maxx = Number.MAX_VALUE;
|
2274
2821
|
if (axisy.options.inverseTransform)
|
2275
2822
|
maxy = Number.MAX_VALUE;
|
2276
|
-
|
2823
|
+
|
2277
2824
|
if (s.lines.show || s.points.show) {
|
2278
2825
|
for (j = 0; j < points.length; j += ps) {
|
2279
2826
|
var x = points[j], y = points[j + 1];
|
2280
2827
|
if (x == null)
|
2281
2828
|
continue;
|
2282
|
-
|
2829
|
+
|
2283
2830
|
// For points and lines, the cursor must be within a
|
2284
2831
|
// certain distance to the data point
|
2285
2832
|
if (x - mx > maxx || x - mx < -maxx ||
|
@@ -2300,19 +2847,32 @@
|
|
2300
2847
|
}
|
2301
2848
|
}
|
2302
2849
|
}
|
2303
|
-
|
2850
|
+
|
2304
2851
|
if (s.bars.show && !item) { // no other point can be nearby
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2852
|
+
|
2853
|
+
var barLeft, barRight;
|
2854
|
+
|
2855
|
+
switch (s.bars.align) {
|
2856
|
+
case "left":
|
2857
|
+
barLeft = 0;
|
2858
|
+
break;
|
2859
|
+
case "right":
|
2860
|
+
barLeft = -s.bars.barWidth;
|
2861
|
+
break;
|
2862
|
+
default:
|
2863
|
+
barLeft = -s.bars.barWidth / 2;
|
2864
|
+
}
|
2865
|
+
|
2866
|
+
barRight = barLeft + s.bars.barWidth;
|
2867
|
+
|
2308
2868
|
for (j = 0; j < points.length; j += ps) {
|
2309
2869
|
var x = points[j], y = points[j + 1], b = points[j + 2];
|
2310
2870
|
if (x == null)
|
2311
2871
|
continue;
|
2312
|
-
|
2872
|
+
|
2313
2873
|
// for a bar graph, the cursor must be inside the bar
|
2314
|
-
if (series[i].bars.horizontal ?
|
2315
|
-
(mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
|
2874
|
+
if (series[i].bars.horizontal ?
|
2875
|
+
(mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
|
2316
2876
|
my >= y + barLeft && my <= y + barRight) :
|
2317
2877
|
(mx >= x + barLeft && mx <= x + barRight &&
|
2318
2878
|
my >= Math.min(b, y) && my <= Math.max(b, y)))
|
@@ -2325,13 +2885,13 @@
|
|
2325
2885
|
i = item[0];
|
2326
2886
|
j = item[1];
|
2327
2887
|
ps = series[i].datapoints.pointsize;
|
2328
|
-
|
2888
|
+
|
2329
2889
|
return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
|
2330
2890
|
dataIndex: j,
|
2331
2891
|
series: series[i],
|
2332
2892
|
seriesIndex: i };
|
2333
2893
|
}
|
2334
|
-
|
2894
|
+
|
2335
2895
|
return null;
|
2336
2896
|
}
|
2337
2897
|
|
@@ -2367,8 +2927,8 @@
|
|
2367
2927
|
|
2368
2928
|
if (item) {
|
2369
2929
|
// fill in mouse pos for any listeners out there
|
2370
|
-
item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);
|
2371
|
-
item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);
|
2930
|
+
item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10);
|
2931
|
+
item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10);
|
2372
2932
|
}
|
2373
2933
|
|
2374
2934
|
if (options.grid.autoHighlight) {
|
@@ -2381,17 +2941,23 @@
|
|
2381
2941
|
h.point[1] == item.datapoint[1]))
|
2382
2942
|
unhighlight(h.series, h.point);
|
2383
2943
|
}
|
2384
|
-
|
2944
|
+
|
2385
2945
|
if (item)
|
2386
2946
|
highlight(item.series, item.datapoint, eventname);
|
2387
2947
|
}
|
2388
|
-
|
2948
|
+
|
2389
2949
|
placeholder.trigger(eventname, [ pos, item ]);
|
2390
2950
|
}
|
2391
2951
|
|
2392
2952
|
function triggerRedrawOverlay() {
|
2953
|
+
var t = options.interaction.redrawOverlayInterval;
|
2954
|
+
if (t == -1) { // skip event queue
|
2955
|
+
drawOverlay();
|
2956
|
+
return;
|
2957
|
+
}
|
2958
|
+
|
2393
2959
|
if (!redrawTimeout)
|
2394
|
-
redrawTimeout = setTimeout(drawOverlay,
|
2960
|
+
redrawTimeout = setTimeout(drawOverlay, t);
|
2395
2961
|
}
|
2396
2962
|
|
2397
2963
|
function drawOverlay() {
|
@@ -2399,9 +2965,9 @@
|
|
2399
2965
|
|
2400
2966
|
// draw highlights
|
2401
2967
|
octx.save();
|
2402
|
-
|
2968
|
+
overlay.clear();
|
2403
2969
|
octx.translate(plotOffset.left, plotOffset.top);
|
2404
|
-
|
2970
|
+
|
2405
2971
|
var i, hi;
|
2406
2972
|
for (i = 0; i < highlights.length; ++i) {
|
2407
2973
|
hi = highlights[i];
|
@@ -2412,10 +2978,10 @@
|
|
2412
2978
|
drawPointHighlight(hi.series, hi.point);
|
2413
2979
|
}
|
2414
2980
|
octx.restore();
|
2415
|
-
|
2981
|
+
|
2416
2982
|
executeHooks(hooks.drawOverlay, [octx]);
|
2417
2983
|
}
|
2418
|
-
|
2984
|
+
|
2419
2985
|
function highlight(s, point, auto) {
|
2420
2986
|
if (typeof s == "number")
|
2421
2987
|
s = series[s];
|
@@ -2434,18 +3000,21 @@
|
|
2434
3000
|
else if (!auto)
|
2435
3001
|
highlights[i].auto = false;
|
2436
3002
|
}
|
2437
|
-
|
3003
|
+
|
2438
3004
|
function unhighlight(s, point) {
|
2439
3005
|
if (s == null && point == null) {
|
2440
3006
|
highlights = [];
|
2441
3007
|
triggerRedrawOverlay();
|
3008
|
+
return;
|
2442
3009
|
}
|
2443
|
-
|
3010
|
+
|
2444
3011
|
if (typeof s == "number")
|
2445
3012
|
s = series[s];
|
2446
3013
|
|
2447
|
-
if (typeof point == "number")
|
2448
|
-
|
3014
|
+
if (typeof point == "number") {
|
3015
|
+
var ps = s.datapoints.pointsize;
|
3016
|
+
point = s.datapoints.points.slice(ps * point, ps * (point + 1));
|
3017
|
+
}
|
2449
3018
|
|
2450
3019
|
var i = indexOfHighlight(s, point);
|
2451
3020
|
if (i != -1) {
|
@@ -2454,7 +3023,7 @@
|
|
2454
3023
|
triggerRedrawOverlay();
|
2455
3024
|
}
|
2456
3025
|
}
|
2457
|
-
|
3026
|
+
|
2458
3027
|
function indexOfHighlight(s, p) {
|
2459
3028
|
for (var i = 0; i < highlights.length; ++i) {
|
2460
3029
|
var h = highlights[i];
|
@@ -2464,21 +3033,22 @@
|
|
2464
3033
|
}
|
2465
3034
|
return -1;
|
2466
3035
|
}
|
2467
|
-
|
3036
|
+
|
2468
3037
|
function drawPointHighlight(series, point) {
|
2469
3038
|
var x = point[0], y = point[1],
|
2470
|
-
axisx = series.xaxis, axisy = series.yaxis
|
2471
|
-
|
3039
|
+
axisx = series.xaxis, axisy = series.yaxis,
|
3040
|
+
highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();
|
3041
|
+
|
2472
3042
|
if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
|
2473
3043
|
return;
|
2474
|
-
|
3044
|
+
|
2475
3045
|
var pointRadius = series.points.radius + series.points.lineWidth / 2;
|
2476
3046
|
octx.lineWidth = pointRadius;
|
2477
|
-
octx.strokeStyle =
|
2478
|
-
var radius = 1.5 * pointRadius
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
3047
|
+
octx.strokeStyle = highlightColor;
|
3048
|
+
var radius = 1.5 * pointRadius;
|
3049
|
+
x = axisx.p2c(x);
|
3050
|
+
y = axisy.p2c(y);
|
3051
|
+
|
2482
3052
|
octx.beginPath();
|
2483
3053
|
if (series.points.symbol == "circle")
|
2484
3054
|
octx.arc(x, y, radius, 0, 2 * Math.PI, false);
|
@@ -2489,12 +3059,26 @@
|
|
2489
3059
|
}
|
2490
3060
|
|
2491
3061
|
function drawBarHighlight(series, point) {
|
3062
|
+
var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
|
3063
|
+
fillStyle = highlightColor,
|
3064
|
+
barLeft;
|
3065
|
+
|
3066
|
+
switch (series.bars.align) {
|
3067
|
+
case "left":
|
3068
|
+
barLeft = 0;
|
3069
|
+
break;
|
3070
|
+
case "right":
|
3071
|
+
barLeft = -series.bars.barWidth;
|
3072
|
+
break;
|
3073
|
+
default:
|
3074
|
+
barLeft = -series.bars.barWidth / 2;
|
3075
|
+
}
|
3076
|
+
|
2492
3077
|
octx.lineWidth = series.bars.lineWidth;
|
2493
|
-
octx.strokeStyle =
|
2494
|
-
|
2495
|
-
var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
|
3078
|
+
octx.strokeStyle = highlightColor;
|
3079
|
+
|
2496
3080
|
drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
|
2497
|
-
|
3081
|
+
function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
|
2498
3082
|
}
|
2499
3083
|
|
2500
3084
|
function getColorOrGradient(spec, bottom, top, defaultColor) {
|
@@ -2505,25 +3089,27 @@
|
|
2505
3089
|
// supports a simple vertical gradient properly, so that's
|
2506
3090
|
// what we support too
|
2507
3091
|
var gradient = ctx.createLinearGradient(0, top, 0, bottom);
|
2508
|
-
|
3092
|
+
|
2509
3093
|
for (var i = 0, l = spec.colors.length; i < l; ++i) {
|
2510
3094
|
var c = spec.colors[i];
|
2511
3095
|
if (typeof c != "string") {
|
2512
3096
|
var co = $.color.parse(defaultColor);
|
2513
3097
|
if (c.brightness != null)
|
2514
|
-
co = co.scale('rgb', c.brightness)
|
3098
|
+
co = co.scale('rgb', c.brightness);
|
2515
3099
|
if (c.opacity != null)
|
2516
3100
|
co.a *= c.opacity;
|
2517
3101
|
c = co.toString();
|
2518
3102
|
}
|
2519
3103
|
gradient.addColorStop(i / (l - 1), c);
|
2520
3104
|
}
|
2521
|
-
|
3105
|
+
|
2522
3106
|
return gradient;
|
2523
3107
|
}
|
2524
3108
|
}
|
2525
3109
|
}
|
2526
3110
|
|
3111
|
+
// Add the plot function to the top level of the jQuery object
|
3112
|
+
|
2527
3113
|
$.plot = function(placeholder, data, options) {
|
2528
3114
|
//var t0 = new Date();
|
2529
3115
|
var plot = new Plot($(placeholder), data, options, $.plot.plugins);
|
@@ -2531,69 +3117,21 @@
|
|
2531
3117
|
return plot;
|
2532
3118
|
};
|
2533
3119
|
|
2534
|
-
$.plot.version = "0.
|
2535
|
-
|
3120
|
+
$.plot.version = "0.8.2";
|
3121
|
+
|
2536
3122
|
$.plot.plugins = [];
|
2537
3123
|
|
2538
|
-
//
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2543
|
-
};
|
2544
|
-
|
2545
|
-
var r = [];
|
2546
|
-
var escape = false, padNext = false;
|
2547
|
-
var hours = d.getUTCHours();
|
2548
|
-
var isAM = hours < 12;
|
2549
|
-
if (monthNames == null)
|
2550
|
-
monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
2551
|
-
|
2552
|
-
if (fmt.search(/%p|%P/) != -1) {
|
2553
|
-
if (hours > 12) {
|
2554
|
-
hours = hours - 12;
|
2555
|
-
} else if (hours == 0) {
|
2556
|
-
hours = 12;
|
2557
|
-
}
|
2558
|
-
}
|
2559
|
-
for (var i = 0; i < fmt.length; ++i) {
|
2560
|
-
var c = fmt.charAt(i);
|
2561
|
-
|
2562
|
-
if (escape) {
|
2563
|
-
switch (c) {
|
2564
|
-
case 'h': c = "" + hours; break;
|
2565
|
-
case 'H': c = leftPad(hours); break;
|
2566
|
-
case 'M': c = leftPad(d.getUTCMinutes()); break;
|
2567
|
-
case 'S': c = leftPad(d.getUTCSeconds()); break;
|
2568
|
-
case 'd': c = "" + d.getUTCDate(); break;
|
2569
|
-
case 'm': c = "" + (d.getUTCMonth() + 1); break;
|
2570
|
-
case 'y': c = "" + d.getUTCFullYear(); break;
|
2571
|
-
case 'b': c = "" + monthNames[d.getUTCMonth()]; break;
|
2572
|
-
case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
|
2573
|
-
case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
|
2574
|
-
case '0': c = ""; padNext = true; break;
|
2575
|
-
}
|
2576
|
-
if (c && padNext) {
|
2577
|
-
c = leftPad(c);
|
2578
|
-
padNext = false;
|
2579
|
-
}
|
2580
|
-
r.push(c);
|
2581
|
-
if (!padNext)
|
2582
|
-
escape = false;
|
2583
|
-
}
|
2584
|
-
else {
|
2585
|
-
if (c == "%")
|
2586
|
-
escape = true;
|
2587
|
-
else
|
2588
|
-
r.push(c);
|
2589
|
-
}
|
2590
|
-
}
|
2591
|
-
return r.join("");
|
3124
|
+
// Also add the plot function as a chainable property
|
3125
|
+
|
3126
|
+
$.fn.plot = function(data, options) {
|
3127
|
+
return this.each(function() {
|
3128
|
+
$.plot(this, data, options);
|
3129
|
+
});
|
2592
3130
|
};
|
2593
|
-
|
3131
|
+
|
2594
3132
|
// round to nearby lower multiple of base
|
2595
3133
|
function floorInBase(n, base) {
|
2596
3134
|
return base * Math.floor(n / base);
|
2597
3135
|
}
|
2598
|
-
|
3136
|
+
|
2599
3137
|
})(jQuery);
|