Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit, based on https://glmatrix.googlecode.com/hg/

These benchmarks are adapted from Brandon Jones benchmarks
in his glmatrix library: https://glmatrix.googlecode.com/hg/

It's based on his code as of this commit:

  e5ad8f6975eef038de668914a44ed36e2c611966
  Date:	October 10, 2010 12:49:00 PM EDT
  Upped version to 0.9.5

Changes include:

This only includes the benchmarks.

I've updated to the latest mjs as of Dec 15: 16:8e5b0944ef1e

I've also added a graph display of the results using flotr,
see: http://solutoire.com/flotr/
  • Loading branch information...
commit 5bfb32ce694c793216c08a722b86f817036d682d 0 parents
@stepheneb authored
1  flotr/flotr-min.js
@@ -0,0 +1 @@
+var Flotr={version:"0.2.0-alpha",revision:("$Revision$".match(/(\d+)/)||[null,null])[1],author:["Bas Wenneker","Fabien M�nager"],website:"http://www.solutoire.com",isIphone:/iphone/i.test(navigator.userAgent),isIE9:document.documentMode==9,graphTypes:{},plugins:{},addType:function(a,b){Flotr.graphTypes[a]=b;Flotr.defaultOptions[a]=b.options||{};Flotr.defaultOptions.defaultType=Flotr.defaultOptions.defaultType||a},addPlugin:function(a,b){Flotr.plugins[a]=b;Flotr.defaultOptions[a]=b.options||{}},draw:function(b,c,a,d){d=d||Flotr.Graph;return new d(b,c,a)},getSeries:function(a){return a.collect(function(c){c=(c.data)?Object.clone(c):{data:c};for(var b=c.data.length-1;b>-1;--b){c.data[b][1]=(c.data[b][1]===null?null:parseFloat(c.data[b][1]))}return c})},merge:function(e,c){var d,b,a=c||{};for(d in e){b=e[d];a[d]=(b&&typeof(b)==="object"&&!(b.constructor===Array||b.constructor===RegExp)&&!Object.isElement(b))?Flotr.merge(b,c[d]):a[d]=b}return a},clone:function(b){var c,a,d={};for(c in b){a=b[c];d[c]=(a&&typeof(a)==="object"&&!(a.constructor===Array||a.constructor===RegExp)&&!Object.isElement(a))?Flotr.clone(a):a}return d},getTickSize:function(e,d,a,b){var h=(a-d)/e,g=Flotr.getMagnitude(h),f=10,c=h/g;if(c<1.5){f=1}else{if(c<2.25){f=2}else{if(c<3){f=((b==0)?2:2.5)}else{if(c<7.5){f=5}}}}return f*g},defaultTickFormatter:function(a){return a+""},defaultTrackFormatter:function(a){return"("+a.x+", "+a.y+")"},engineeringNotation:function(e,a,d){var c=["Y","Z","E","P","T","G","M","k",""],f=["y","z","a","f","p","n","�","m",""],b=c.length;d=d||1000;a=Math.pow(10,a||2);if(e==0){return 0}if(e>1){while(b--&&(e>=d)){e/=d}}else{c=f;b=c.length;while(b--&&(e<1)){e*=d}}return(Math.round(e*a)/a)+c[b]},getMagnitude:function(a){return Math.pow(10,Math.floor(Math.log(a)/Math.LN10))},toPixel:function(a){return Math.floor(a)+0.5},toRad:function(a){return -a*(Math.PI/180)},floorInBase:function(b,a){return a*Math.floor(b/a)},drawText:function(b,d,a,e,c){if(!b.fillText||Flotr.isIphone){b.drawText(d,a,e,c);return}c=Object.extend({size:Flotr.defaultOptions.fontSize,color:"#000000",textAlign:"left",textBaseline:"bottom",weight:1,angle:0},c);b.save();b.translate(a,e);b.rotate(c.angle);b.fillStyle=c.color;b.font=(c.weight>1?"bold ":"")+(c.size*1.3)+"px sans-serif";b.textAlign=c.textAlign;b.textBaseline=c.textBaseline;b.fillText(d,0,0);b.restore()},measureText:function(a,d,c){if(!a.fillText||Flotr.isIphone){return{width:a.measure(d,c)}}c=Object.extend({size:Flotr.defaultOptions.fontSize,weight:1,angle:0},c);a.save();a.rotate(c.angle);a.font=(c.weight>1?"bold ":"")+(c.size*1.3)+"px sans-serif";var b=a.measureText(d);a.restore();return b},getBestTextAlign:function(b,a){a=a||{textAlign:"center",textBaseline:"middle"};b+=Flotr.getTextAngleFromAlign(a);if(Math.abs(Math.cos(b))>0.01){a.textAlign=(Math.cos(b)>0?"right":"left")}if(Math.abs(Math.sin(b))>0.01){a.textBaseline=(Math.sin(b)>0?"top":"bottom")}return a},alignTable:{"right middle":0,"right top":Math.PI/4,"center top":Math.PI/2,"left top":3*(Math.PI/4),"left middle":Math.PI,"left bottom":-3*(Math.PI/4),"center bottom":-Math.PI/2,"right bottom":-Math.PI/4,"center middle":0},getTextAngleFromAlign:function(a){return Flotr.alignTable[a.textAlign+" "+a.textBaseline]||0}};Flotr.defaultOptions={colors:["#00A8F0","#C0D800","#CB4B4B","#4DA74D","#9440ED"],title:null,subtitle:null,shadowSize:4,defaultType:null,HtmlText:true,fontSize:7.5,resolution:1,legend:{show:true,noColumns:1,labelFormatter:function(a){return a},labelBoxBorderColor:"#CCCCCC",labelBoxWidth:14,labelBoxHeight:10,labelBoxMargin:5,container:null,position:"nw",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{ticks:null,minorTicks:null,showLabels:true,showMinorLabels:false,labelsAngle:0,title:null,titleAngle:0,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null,mode:"normal",timeFormat:null,scaling:"linear",base:Math.E,titleAlign:"center",margin:true},x2axis:{},yaxis:{ticks:null,minorTicks:null,showLabels:true,showMinorLabels:false,labelsAngle:0,title:null,titleAngle:90,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null,scaling:"linear",base:Math.E,titleAlign:"center",margin:true},y2axis:{titleAngle:270},grid:{color:"#545454",backgroundColor:null,backgroundImage:null,watermarkAlpha:0.4,tickColor:"#DDDDDD",labelMargin:3,verticalLines:true,minorVerticalLines:null,horizontalLines:true,minorHorizontalLines:null,outlineWidth:2,circular:false},selection:{mode:null,color:"#B6D9FF",fps:20},crosshair:{mode:null,color:"#FF0000",hideCursor:true},mouse:{track:false,trackAll:false,position:"se",relative:false,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:"#FF3F19",trackDecimals:1,sensibility:2,trackY:true,radius:3,fillColor:null,fillOpacity:0.4}};Flotr.Graph=Class.create({initialize:function(c,d,a){try{this.el=$(c);if(!this.el){throw"The target container doesn't exist"}if(!this.el.clientWidth){throw"The target container must be visible"}this.registerPlugins();this.el.fire("flotr:beforeinit",[this]);this.el.graph=this;this.data=d;this.lastMousePos={pageX:null,pageY:null};this.selection={first:{x:-1,y:-1},second:{x:-1,y:-1}};this.plotOffset={left:0,right:0,top:0,bottom:0};this.prevSelection=null;this.selectionInterval=null;this.ignoreClick=false;this.prevHit=null;this.series=Flotr.getSeries(d);this.setOptions(a);var b,g;for(b in Flotr.graphTypes){this[b]=Object.clone(Flotr.graphTypes[b]);for(g in this[b]){if(Object.isFunction(this[b][g])){this[b][g]=this[b][g].bind(this)}}}this.constructCanvas();this.el.fire("flotr:afterconstruct",[this]);this.initEvents();this.findDataRanges();this.calculateTicks(this.axes.x);this.calculateTicks(this.axes.x2);this.calculateTicks(this.axes.y);this.calculateTicks(this.axes.y2);this.calculateSpacing();this.setupAxes();this.draw(function(){this.insertLegend();this.el.fire("flotr:afterinit",[this])}.bind(this))}catch(f){try{console.error(f)}catch(f){}}},setOptions:function(b){var v=Flotr.clone(Flotr.defaultOptions);v.x2axis=Object.extend(Object.clone(v.xaxis),v.x2axis);v.y2axis=Object.extend(Object.clone(v.yaxis),v.y2axis);this.options=Flotr.merge(b||{},v);this.axes={x:{options:this.options.xaxis,n:1},x2:{options:this.options.x2axis,n:2},y:{options:this.options.yaxis,n:1},y2:{options:this.options.y2axis,n:2}};if(this.options.grid.minorVerticalLines===null&&this.options.xaxis.scaling==="logarithmic"){this.options.grid.minorVerticalLines=true}if(this.options.grid.minorHorizontalLines===null&&this.options.yaxis.scaling==="logarithmic"){this.options.grid.minorHorizontalLines=true}var h=[],d=[],m=this.series.length,q=this.series.length,e=this.options.colors,a=[],g=0,o,l,k,u;for(l=q-1;l>-1;--l){o=this.series[l].color;if(o){--q;if(Object.isNumber(o)){h.push(o)}else{a.push(Flotr.Color.parse(o))}}}for(l=h.length-1;l>-1;--l){q=Math.max(q,h[l]+1)}for(l=0;d.length<q;){o=(e.length==l)?new Flotr.Color(100,100,100):Flotr.Color.parse(e[l]);var f=g%2==1?-1:1,n=1+f*Math.ceil(g/2)*0.2;o.scale(n,n,n);d.push(o);if(++l>=e.length){l=0;++g}}for(l=0,k=0;l<m;++l){u=this.series[l];if(u.color==null){u.color=d[k++].toString()}else{if(Object.isNumber(u.color)){u.color=d[u.color].toString()}}if(!u.xaxis){u.xaxis=this.axes.x}if(u.xaxis==1){u.xaxis=this.axes.x}else{if(u.xaxis==2){u.xaxis=this.axes.x2}}if(!u.yaxis){u.yaxis=this.axes.y}if(u.yaxis==1){u.yaxis=this.axes.y}else{if(u.yaxis==2){u.yaxis=this.axes.y2}}for(var r in Flotr.graphTypes){u[r]=Object.extend(Object.clone(this.options[r]),u[r])}u.mouse=Object.extend(Object.clone(this.options.mouse),u.mouse);if(u.shadowSize==null){u.shadowSize=this.options.shadowSize}}},setupAxes:function(){function f(j,k){if(k.scaling==="logarithmic"){j=Math.log(Math.max(j,Number.MIN_VALUE));if(k.base!==Math.E){j/=Math.log(k.base)}}return j}function c(j,k){if(k.scaling==="logarithmic"){j=(k.base===Math.E)?Math.exp(j):Math.pow(k.base,j)}return j}var a=this.axes.x,b=this.axes.x2,h=this.axes.y,d=this.axes.y2;var e=this.plotWidth,g=this.plotHeight;a.scale=e/(f(a.max,a.options)-f(a.min,a.options));b.scale=e/(f(b.max,b.options)-f(b.min,b.options));h.scale=g/(f(h.max,h.options)-f(h.min,h.options));d.scale=g/(f(d.max,d.options)-f(d.min,d.options));if(this.options.scaling==="logarithmic"){a.d2p=b.d2p=function(j){var k=this.options;return(f(j,k)-f(this.min,k))*this.scale};a.p2d=this.axes.x2.p2d=function(j){var k=this.options;return c(j/this.scale+f(this.min,k),k)};h.d2p=d.d2p=function(k){var j=this.options;return g-(f(k,j)-f(this.min,j))*this.scale};h.p2d=d.p2d=function(k){var j=this.options;return c((g-k)/this.scale+f(this.min,j),j)}}else{a.d2p=b.d2p=function(j){return(j-this.min)*this.scale};a.p2d=this.axes.x2.p2d=function(j){return j/this.scale+this.min};h.d2p=d.d2p=function(j){return g-(j-this.min)*this.scale};h.p2d=d.p2d=function(j){return(g-j)/this.scale+this.min}}},constructCanvas:function(){var e=this.el,b,g,a;this.canvas=e.select(".flotr-canvas")[0];this.overlay=e.select(".flotr-overlay")[0];e.descendants().invoke("remove");e.style.position="relative";e.style.cursor=e.style.cursor||"default";b=e.getDimensions();this.canvasWidth=b.width;this.canvasHeight=b.height;var d={width:b.width+"px",height:b.height+"px"};var f=this.options;b.width*=f.resolution;b.height*=f.resolution;if(this.canvasWidth<=0||this.canvasHeight<=0){throw"Invalid dimensions for plot, width = "+this.canvasWidth+", height = "+this.canvasHeight}if(!this.canvas){g=this.canvas=$(document.createElement("canvas"));g.className="flotr-canvas";g.style.cssText="position:absolute;left:0px;top:0px;"}g=this.canvas.writeAttribute(b).show().setStyle(d);g.context_=null;e.insert(g);if(!this.overlay){a=this.overlay=$(document.createElement("canvas"));a.className="flotr-overlay";a.style.cssText="position:absolute;left:0px;top:0px;"}a=this.overlay.writeAttribute(b).show().setStyle(d);a.context_=null;e.insert(a);if(window.G_vmlCanvasManager){window.G_vmlCanvasManager.initElement(g);window.G_vmlCanvasManager.initElement(a)}this.ctx=g.getContext("2d");this.octx=a.getContext("2d");if(!window.G_vmlCanvasManager){this.ctx.scale(f.resolution,f.resolution);this.octx.scale(f.resolution,f.resolution)}this.textEnabled=!!this.ctx.drawText},processColor:function(a,b){if(!a){return"rgba(0, 0, 0, 0)"}b=Object.extend({x1:0,y1:0,x2:this.plotWidth,y2:this.plotHeight,opacity:1,ctx:this.ctx},b);if(a instanceof Flotr.Color){return a.adjust(null,null,null,b.opacity).toString()}if(Object.isString(a)){return Flotr.Color.parse(a).scale(null,null,null,b.opacity).toString()}var h=a.colors?a:{colors:a};if(!b.ctx){if(!Object.isArray(h.colors)){return"rgba(0, 0, 0, 0)"}return Flotr.Color.parse(Object.isArray(h.colors[0])?h.colors[0][1]:h.colors[0]).scale(null,null,null,b.opacity).toString()}h=Object.extend({start:"top",end:"bottom"},h);if(/top/i.test(h.start)){b.x1=0}if(/left/i.test(h.start)){b.y1=0}if(/bottom/i.test(h.end)){b.x2=0}if(/right/i.test(h.end)){b.y2=0}var e,g,d,f=b.ctx.createLinearGradient(b.x1,b.y1,b.x2,b.y2);for(e=0;e<h.colors.length;e++){g=h.colors[e];if(Object.isArray(g)){d=g[0];g=g[1]}else{d=e/(h.colors.length-1)}f.addColorStop(d,Flotr.Color.parse(g).scale(null,null,null,b.opacity))}return f},registerPlugins:function(){var a,b,d;for(a in Flotr.plugins){b=Flotr.plugins[a];for(d in b.callbacks){this.el.stopObserving(d).observe(d,b.callbacks[d].bindAsEventListener(this))}this[a]=Object.clone(b);for(p in this[a]){if(Object.isFunction(this[a][p])){this[a][p]=this[a][p].bind(this)}}}},getTextDimensions:function(g,c,b,d){if(!g){return{width:0,height:0}}if(!this.options.HtmlText&&this.textEnabled){var e=this.ctx.getTextBounds(g,c);return{width:e.width+2,height:e.height+6}}else{var a=this.el.insert('<div style="position:absolute;top:-10000px;'+b+'" class="'+d+' flotr-dummy-div">'+g+"</div>").select(".flotr-dummy-div")[0],f=a.getDimensions();a.remove();return f}},loadDataGrid:function(){if(this.seriesData){return this.seriesData}var a=this.series,b=[];for(i=0;i<a.length;++i){a[i].data.each(function(d){var c=d[0],g=d[1],f=b.find(function(h){return h[0]==c});if(f){f[i+1]=g}else{var e=[];e[0]=c;e[i+1]=g;b.push(e)}})}return this.seriesData=b.sortBy(function(c){return c[0]})},initEvents:function(){this.overlay.stopObserving().observe("mousedown",this.mouseDownHandler.bindAsEventListener(this)).observe("mousemove",this.mouseMoveHandler.bindAsEventListener(this)).observe("mouseout",this.clearHit.bindAsEventListener(this)).observe("click",this.clickHandler.bindAsEventListener(this))},findDataRanges:function(){var n=this.series,k=this.axes;k.x.datamin=k.x2.datamin=k.y.datamin=k.y2.datamin=Number.MAX_VALUE;k.x.datamax=k.x2.datamax=k.y.datamax=k.y2.datamax=-Number.MAX_VALUE;if(n.length>0){var d,b,e,l,g,c,m,f;for(d=0;d<n.length;++d){c=n[d].data,m=n[d].xaxis,f=n[d].yaxis;if(c.length>0&&!n[d].hide){for(e=c.length-1;e>-1;--e){l=c[e][0];if((l<=0)&&(m.options.scaling==="logarithmic")){continue}if(l<m.datamin){m.datamin=l;m.used=true}if(l>m.datamax){m.datamax=l;m.used=true}for(b=1;b<c[e].length;b++){g=c[e][b];if((g<=0)&&(f.options.scaling==="logarithmic")){continue}if(g<f.datamin){f.datamin=g;f.used=true}if(g>f.datamax){f.datamax=g;f.used=true}}}}}}this.findXAxesValues();this.calculateRange(k.x,"x");if(k.x2.used){this.calculateRange(k.x2,"x")}this.calculateRange(k.y,"y");if(k.y2.used){this.calculateRange(k.y2,"y")}},extendRange:function(c,b){var d=(b==="y")?"extendYRange":"extendXRange";for(var a in Flotr.graphTypes){if(this.series[b]&&this.series[b].show){if(this[a][d]){this[a][d](c)}}}},calculateRange:function(d,g){var c=d.options,f=c.min!=null?c.min:d.datamin,h=c.max!=null?c.max:d.datamax,e=c.autoscaleMargin;if(c.scaling=="logarithmic"){if(f<=0){f=d.datamin}if(h<=0){h=f}}if(h-f==0){var b=(h==0)?1:0.01;f-=b;h+=b}if(c.scaling==="logarithmic"){if(f<0){f=h/c.base}var a=Math.log(h);if(c.base!=Math.E){a/=Math.log(c.base)}a=Math.ceil(a);var j=Math.log(f);if(c.base!=Math.E){j/=Math.log(c.base)}j=Math.ceil(j);d.tickSize=Flotr.getTickSize(c.noTicks,j,a,c.tickDecimals===null?0:c.tickDecimals);if(c.minorTickFreq===null){if(a-j>10){c.minorTickFreq=0}else{if(a-j>5){c.minorTickFreq=2}else{c.minorTickFreq=5}}}}else{d.tickSize=Flotr.getTickSize(c.noTicks,f,h,c.tickDecimals)}if(c.min==null&&e!=0){f-=d.tickSize*e;if(f<0&&d.datamin>=0){f=0}f=d.tickSize*Math.floor(f/d.tickSize)}if(c.max==null&&e!=0){h+=d.tickSize*e;if(h>0&&d.datamax<=0&&d.datamax!=d.datamin){h=0}h=d.tickSize*Math.ceil(h/d.tickSize)}if(f==h){h=f+1}d.min=f;d.max=h;this.extendRange(d,g)},findXAxesValues:function(){var b,a,c;for(b=this.series.length-1;b>-1;--b){c=this.series[b];c.xaxis.values=c.xaxis.values||{};for(a=c.data.length-1;a>-1;--a){c.xaxis.values[c.data[a][0]+""]={}}}},calculateTicks:function(e){var u=e.options,A,m;e.ticks=[];e.minorTicks=[];if(u.ticks){var E=u.ticks,b=u.minorTicks||[],n,l;if(Object.isFunction(E)){E=E({min:e.min,max:e.max})}if(Object.isFunction(b)){b=b({min:e.min,max:e.max})}for(A=0;A<E.length;++A){n=E[A];if(typeof(n)==="object"){m=n[0];l=(n.length>1)?n[1]:u.tickFormatter(m)}else{m=n;l=u.tickFormatter(m)}e.ticks[A]={v:m,label:l}}for(A=0;A<b.length;++A){n=b[A];if(typeof(n)==="object"){m=n[0];l=(n.length>1)?n[1]:u.tickFormatter(m)}else{m=n;l=u.tickFormatter(m)}e.minorTicks[A]={v:m,label:l}}}else{if(u.mode=="time"){var G=Flotr.Date.timeUnits,k=Flotr.Date.spec,D=(e.max-e.min)/e.options.noTicks,r,q;for(A=0;A<k.length-1;++A){var C=k[A][0]*G[k[A][1]];if(D<(C+k[A+1][0]*G[k[A+1][1]])/2&&C>=e.tickSize){break}}r=k[A][0];q=k[A][1];if(q=="year"){r=Flotr.getTickSize(e.options.noTicks*G.year,e.min,e.max,0)}e.tickSize=r;e.tickUnit=q;e.ticks=Flotr.Date.generator(e)}else{if(u.scaling==="logarithmic"){var z=Math.log(e.max);if(u.base!=Math.E){z/=Math.log(u.base)}z=Math.ceil(z);var w=Math.log(e.min);if(u.base!=Math.E){w/=Math.log(u.base)}w=Math.ceil(w);for(A=w;A<z;A+=e.tickSize){var a=(u.base==Math.E)?Math.exp(A):Math.pow(u.base,A);var f=a*((u.base==Math.E)?Math.exp(e.tickSize):Math.pow(u.base,e.tickSize));var h=(f-a)/u.minorTickFreq;e.ticks.push({v:a,label:u.tickFormatter(a)});for(m=a+h;m<f;m+=h){e.minorTicks.push({v:m,label:u.tickFormatter(m)})}}var a=(u.base==Math.E)?Math.exp(A):Math.pow(u.base,A);e.ticks.push({v:a,label:u.tickFormatter(a)})}else{var g=e.tickSize*Math.ceil(e.min/e.tickSize),F,B,c;if(u.minorTickFreq){B=e.tickSize/u.minorTickFreq}for(A=0;g+A*e.tickSize<=e.max;++A){m=c=g+A*e.tickSize;F=u.tickDecimals;if(F==null){F=1-Math.floor(Math.log(e.tickSize)/Math.LN10)}if(F<0){F=0}m=m.toFixed(F);e.ticks.push({v:m,label:u.tickFormatter(m)});if(u.minorTickFreq){for(var x=0;x<u.minorTickFreq&&(A*e.tickSize+x*B)<e.max;++x){m=c+x*B;m=m.toFixed(F);e.minorTicks.push({v:m,label:u.tickFormatter(m)})}}}}}}},calculateSpacing:function(){var q=this.axes,t=this.options,k=this.series,e=t.grid.labelMargin,r=q.x,b=q.x2,n=q.y,o=q.y2,g=2,h,f,d,m;[r,b,n,o].each(function(j){var a="";if(j.options.showLabels){for(h=0;h<j.ticks.length;++h){d=j.ticks[h].label.length;if(d>a.length){a=j.ticks[h].label}}}j.maxLabel=this.getTextDimensions(a,{size:t.fontSize,angle:Flotr.toRad(j.options.labelsAngle)},"font-size:smaller;","flotr-grid-label");j.titleSize=this.getTextDimensions(j.options.title,{size:t.fontSize*1.2,angle:Flotr.toRad(j.options.titleAngle)},"font-weight:bold;","flotr-axis-title")},this);m=this.getTextDimensions(t.title,{size:t.fontSize*1.5},"font-size:1em;font-weight:bold;","flotr-title");this.titleHeight=m.height;m=this.getTextDimensions(t.subtitle,{size:t.fontSize},"font-size:smaller;","flotr-subtitle");this.subtitleHeight=m.height;if(t.show){g=Math.max(g,t.points.radius+t.points.lineWidth/2)}for(f=0;f<t.length;++f){if(k[f].points.show){g=Math.max(g,k[f].points.radius+k[f].points.lineWidth/2)}}var c=this.plotOffset;if(r.options.margin===false){c.bottom=0;c.top=0}else{c.bottom+=(t.grid.circular?0:(r.options.showLabels?(r.maxLabel.height+e):0))+(r.options.title?(r.titleSize.height+e):0)+g;c.top+=(t.grid.circular?0:(b.options.showLabels?(b.maxLabel.height+e):0))+(b.options.title?(b.titleSize.height+e):0)+this.subtitleHeight+this.titleHeight+g}if(n.options.margin===false){c.left=0;c.right=0}else{c.left+=(t.grid.circular?0:(n.options.showLabels?(n.maxLabel.width+e):0))+(n.options.title?(n.titleSize.width+e):0)+g;c.right+=(t.grid.circular?0:(o.options.showLabels?(o.maxLabel.width+e):0))+(o.options.title?(o.titleSize.width+e):0)+g}c.top=Math.floor(c.top);this.plotWidth=this.canvasWidth-c.left-c.right;this.plotHeight=this.canvasHeight-c.bottom-c.top},draw:function(d){var c=function(){this.drawGrid();this.drawLabels();this.drawTitles();if(this.series.length){this.el.fire("flotr:beforedraw",[this.series,this]);for(var e=0;e<this.series.length;e++){if(!this.series[e].hide){this.drawSeries(this.series[e])}}}this.drawOutline();this.el.fire("flotr:afterdraw",[this.series,this]);d()}.bind(this);var b=this.options.grid;if(b&&b.backgroundImage){if(Object.isString(b.backgroundImage)){b.backgroundImage={src:b.backgroundImage,left:0,top:0}}else{b.backgroundImage=Object.extend({left:0,top:0},b.backgroundImage)}var a=new Image();a.onload=function(){var g=this.plotOffset.left+(parseInt(b.backgroundImage.left)||0);var f=this.plotOffset.top+(parseInt(b.backgroundImage.top)||0);var e=this.ctx.globalAlpha;this.ctx.globalAlpha=(b.backgroundImage.alpha||e);this.ctx.drawImage(a,g,f);this.ctx.globalAlpha=e;c()}.bind(this);a.onabort=a.onerror=c;a.src=b.backgroundImage.src}else{c()}},drawGrid:function(){var m,b=this.options,n=this.ctx,l;if(b.grid.verticalLines||b.grid.minorVerticalLines||b.grid.horizontalLines||b.grid.minorHorizontalLines){this.el.fire("flotr:beforegrid",[this.axes.x,this.axes.y,b,this])}n.save();n.lineWidth=1;n.strokeStyle=b.grid.tickColor;if(b.grid.circular){n.translate(this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+this.plotHeight/2);var h=Math.min(this.plotHeight,this.plotWidth)*b.radar.radiusRatio/2,c=this.axes.x.ticks.length,g=2*(Math.PI/c),d=-Math.PI/2;n.beginPath();if(b.grid.horizontalLines){l=this.axes.y;for(var f=0;f<l.ticks.length;++f){m=l.ticks[f].v;var k=m/l.max;for(var e=0;e<=c;++e){n[e==0?"moveTo":"lineTo"](Math.cos(e*g+d)*h*k,Math.sin(e*g+d)*h*k)}}}if(b.grid.minorHorizontalLines){l=this.axes.y;for(var f=0;f<l.minorTicks.length;++f){m=l.minorTicks[f].v;var k=m/l.max;for(var e=0;e<=c;++e){n[e==0?"moveTo":"lineTo"](Math.cos(e*g+d)*h*k,Math.sin(e*g+d)*h*k)}}}if(b.grid.verticalLines){for(var f=0;f<c;++f){n.moveTo(0,0);n.lineTo(Math.cos(f*g+d)*h,Math.sin(f*g+d)*h)}}n.stroke()}else{n.translate(this.plotOffset.left,this.plotOffset.top);if(b.grid.backgroundColor!=null){n.fillStyle=this.processColor(b.grid.backgroundColor,{x1:0,y1:0,x2:this.plotWidth,y2:this.plotHeight});n.fillRect(0,0,this.plotWidth,this.plotHeight)}n.beginPath();if(b.grid.verticalLines){l=this.axes.x;for(var f=0;f<l.ticks.length;++f){m=l.ticks[f].v;if((m<=l.min||m>=l.max)||(m==l.min||m==l.max)&&b.grid.outlineWidth!=0){continue}n.moveTo(Math.floor(l.d2p(m))+n.lineWidth/2,0);n.lineTo(Math.floor(l.d2p(m))+n.lineWidth/2,this.plotHeight)}}if(b.grid.minorVerticalLines){l=this.axes.x;for(var f=0;f<l.minorTicks.length;++f){m=l.minorTicks[f].v;if((m<=l.min||m>=l.max)||(m==l.min||m==l.max)&&b.grid.outlineWidth!=0){continue}n.moveTo(Math.floor(l.d2p(m))+n.lineWidth/2,0);n.lineTo(Math.floor(l.d2p(m))+n.lineWidth/2,this.plotHeight)}}if(b.grid.horizontalLines){l=this.axes.y;for(var e=0;e<l.ticks.length;++e){m=l.ticks[e].v;if((m<=l.min||m>=l.max)||(m==l.min||m==l.max)&&b.grid.outlineWidth!=0){continue}n.moveTo(0,Math.floor(l.d2p(m))+n.lineWidth/2);n.lineTo(this.plotWidth,Math.floor(l.d2p(m))+n.lineWidth/2)}}if(b.grid.minorHorizontalLines){l=this.axes.y;for(var e=0;e<l.minorTicks.length;++e){m=l.minorTicks[e].v;if((m<=l.min||m>=l.max)||(m==l.min||m==l.max)&&b.grid.outlineWidth!=0){continue}n.moveTo(0,Math.floor(l.d2p(m))+n.lineWidth/2);n.lineTo(this.plotWidth,Math.floor(l.d2p(m))+n.lineWidth/2)}}n.stroke()}n.restore();if(b.grid.verticalLines||b.grid.minorVerticalLines||b.grid.horizontalLines||b.grid.minorHorizontalLines){this.el.fire("flotr:aftergrid",[this.axes.x,this.axes.y,b,this])}},drawOutline:function(){var j,a=this.options,k=this.ctx;if(a.grid.outlineWidth==0){return}k.save();if(a.grid.circular){k.translate(this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+this.plotHeight/2);var g=Math.min(this.plotHeight,this.plotWidth)*a.radar.radiusRatio/2,b=this.axes.x.ticks.length,f=2*(Math.PI/b),d=-Math.PI/2;k.beginPath();k.lineWidth=a.grid.outlineWidth;k.strokeStyle=a.grid.color;k.lineJoin="round";for(var e=0;e<=b;++e){k[e==0?"moveTo":"lineTo"](Math.cos(e*f+d)*g,Math.sin(e*f+d)*g)}k.stroke()}else{k.translate(this.plotOffset.left,this.plotOffset.top);var c=a.grid.outlineWidth,h=0.5-c+((c+1)%2/2);k.lineWidth=c;k.strokeStyle=a.grid.color;k.lineJoin="miter";k.strokeRect(h,h,this.plotWidth,this.plotHeight)}k.restore()},drawLabels:function(){var c=0,d,m,o,k,q,g,l,e=this.options,n=this.ctx,v=this.axes;for(o=0;o<v.x.ticks.length;++o){if(v.x.ticks[o].label){++c}}m=this.plotWidth/c;if(e.grid.circular){n.save();n.translate(this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+this.plotHeight/2);var f=this.plotHeight*e.radar.radiusRatio/2+e.fontSize,u=this.axes.x.ticks.length,b=2*(Math.PI/u),t=-Math.PI/2;var r={size:e.fontSize};d=v.x;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels;++o){q=d.ticks[o];q.label+="";if(!q.label||q.label.length==0){continue}var j=Math.cos(o*b+t)*f,h=Math.sin(o*b+t)*f;r.angle=Flotr.toRad(d.options.labelsAngle);r.textBaseline="middle";r.textAlign=(Math.abs(j)<0.1?"center":(j<0?"right":"left"));Flotr.drawText(n,q.label,j,h,r)}for(o=0;o<d.minorTicks.length&&d.options.showMinorLabels;++o){q=d.minorTicks[o];q.label+="";if(!q.label||q.label.length==0){continue}var j=Math.cos(o*b+t)*f,h=Math.sin(o*b+t)*f;r.angle=Flotr.toRad(d.options.labelsAngle);r.textBaseline="middle";r.textAlign=(Math.abs(j)<0.1?"center":(j<0?"right":"left"));Flotr.drawText(n,q.label,j,h,r)}d=v.y;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels;++o){q=d.ticks[o];q.label+="";if(!q.label||q.label.length==0){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textBaseline="middle";r.textAlign="left";Flotr.drawText(n,q.label,3,-(d.ticks[o].v/d.max)*(f-e.fontSize),r)}for(o=0;o<d.minorTicks.length&&d.options.showMinorLabels;++o){q=d.minorTicks[o];q.label+="";if(!q.label||q.label.length==0){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textBaseline="middle";r.textAlign="left";Flotr.drawText(n,q.label,3,-(d.ticks[o].v/d.max)*(f-e.fontSize),r)}n.restore();return}if(!e.HtmlText&&this.textEnabled){var r={size:e.fontSize};d=v.x;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels&&d.used;++o){q=d.ticks[o];if(!q.label||q.label.length==0){continue}g=d.d2p(q.v);if(g<0||g>this.plotWidth){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textAlign="center";r.textBaseline="top";r=Flotr.getBestTextAlign(r.angle,r);Flotr.drawText(n,q.label,this.plotOffset.left+g,this.plotOffset.top+this.plotHeight+e.grid.labelMargin,r)}d=v.x2;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels&&d.used;++o){q=d.ticks[o];if(!q.label||q.label.length==0){continue}g=d.d2p(q.v);if(g<0||g>this.plotWidth){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textAlign="center";r.textBaseline="bottom";r=Flotr.getBestTextAlign(r.angle,r);Flotr.drawText(n,q.label,this.plotOffset.left+g,this.plotOffset.top+e.grid.labelMargin,r)}d=v.y;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels&&d.used;++o){q=d.ticks[o];if(!q.label||q.label.length==0){continue}l=d.d2p(q.v);if(l<0||l>this.plotHeight){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textAlign="right";r.textBaseline="middle";r=Flotr.getBestTextAlign(r.angle,r);Flotr.drawText(n,q.label,this.plotOffset.left-e.grid.labelMargin,this.plotOffset.top+l,r)}d=v.y2;r.color=d.options.color||e.grid.color;for(o=0;o<d.ticks.length&&d.options.showLabels&&d.used;++o){q=d.ticks[o];if(!q.label||q.label.length==0){continue}l=d.d2p(q.v);if(l<0||l>this.plotHeight){continue}r.angle=Flotr.toRad(d.options.labelsAngle);r.textAlign="left";r.textBaseline="middle";r=Flotr.getBestTextAlign(r.angle,r);Flotr.drawText(n,q.label,this.plotOffset.left+this.plotWidth+e.grid.labelMargin,this.plotOffset.top+l,r);n.save();n.strokeStyle=r.color;n.beginPath();n.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+d.d2p(q.v));n.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+d.d2p(q.v));n.stroke();n.restore()}}else{if(v.x.options.showLabels||v.x2.options.showLabels||v.y.options.showLabels||v.y2.options.showLabels){k=['<div style="font-size:smaller;color:'+e.grid.color+';" class="flotr-labels">'];d=v.x;if(d.options.showLabels){for(o=0;o<d.ticks.length;++o){q=d.ticks[o];if(!q.label||q.label.length==0||(this.plotOffset.left+d.d2p(q.v)<0)||(this.plotOffset.left+d.d2p(q.v)>this.canvasWidth)){continue}k.push('<div style="position:absolute;top:',(this.plotOffset.top+this.plotHeight+e.grid.labelMargin),"px;left:",(this.plotOffset.left+d.d2p(q.v)-m/2),"px;width:",m,"px;text-align:center;",(d.options.color?("color:"+d.options.color+";"):""),'" class="flotr-grid-label">',q.label,"</div>")}}d=v.x2;if(d.options.showLabels&&d.used){for(o=0;o<d.ticks.length;++o){q=d.ticks[o];if(!q.label||q.label.length==0||(this.plotOffset.left+d.d2p(q.v)<0)||(this.plotOffset.left+d.d2p(q.v)>this.canvasWidth)){continue}k.push('<div style="position:absolute;top:',(this.plotOffset.top-e.grid.labelMargin-d.maxLabel.height),"px;left:",(this.plotOffset.left+d.d2p(q.v)-m/2),"px;width:",m,"px;text-align:center;",(d.options.color?("color:"+d.options.color+";"):""),'" class="flotr-grid-label">',q.label,"</div>")}}d=v.y;if(d.options.showLabels){for(o=0;o<d.ticks.length;++o){q=d.ticks[o];if(!q.label||q.label.length==0||(this.plotOffset.top+d.d2p(q.v)<0)||(this.plotOffset.top+d.d2p(q.v)>this.canvasHeight)){continue}k.push('<div style="position:absolute;top:',(this.plotOffset.top+d.d2p(q.v)-d.maxLabel.height/2),"px;left:0;width:",(this.plotOffset.left-e.grid.labelMargin),"px;text-align:right;",(d.options.color?("color:"+d.options.color+";"):""),'" class="flotr-grid-label flotr-grid-label-y">',q.label,"</div>")}}d=v.y2;if(d.options.showLabels&&d.used){n.save();n.strokeStyle=d.options.color||e.grid.color;n.beginPath();for(o=0;o<d.ticks.length;++o){q=d.ticks[o];if(!q.label||q.label.length==0||(this.plotOffset.top+d.d2p(q.v)<0)||(this.plotOffset.top+d.d2p(q.v)>this.canvasHeight)){continue}k.push('<div style="position:absolute;top:',(this.plotOffset.top+d.d2p(q.v)-d.maxLabel.height/2),"px;right:0;width:",(this.plotOffset.right-e.grid.labelMargin),"px;text-align:left;",(d.options.color?("color:"+d.options.color+";"):""),'" class="flotr-grid-label flotr-grid-label-y">',q.label,"</div>");n.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+d.d2p(q.v));n.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+d.d2p(q.v))}n.stroke();n.restore()}k.push("</div>");this.el.insert(k.join(""))}}},drawTitles:function(){var e,d=this.options,g=d.grid.labelMargin,c=this.ctx,b=this.axes;if(!d.HtmlText&&this.textEnabled){var f={size:d.fontSize,color:d.grid.color,textAlign:"center"};if(d.subtitle){Flotr.drawText(c,d.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,f)}f.weight=1.5;f.size*=1.5;if(d.title){Flotr.drawText(c,d.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,f)}f.weight=1.8;f.size*=0.8;if(b.x.options.title&&b.x.used){f.textAlign=b.x.options.titleAlign||"center";f.textBaseline="top";f.angle=Flotr.toRad(b.x.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+b.x.maxLabel.height+this.plotHeight+2*g,f)}if(b.x2.options.title&&b.x2.used){f.textAlign=b.x2.options.titleAlign||"center";f.textBaseline="bottom";f.angle=Flotr.toRad(b.x2.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-b.x2.maxLabel.height-2*g,f)}if(b.y.options.title&&b.y.used){f.textAlign=b.y.options.titleAlign||"right";f.textBaseline="middle";f.angle=Flotr.toRad(b.y.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.y.options.title,this.plotOffset.left-b.y.maxLabel.width-2*g,this.plotOffset.top+this.plotHeight/2,f)}if(b.y2.options.title&&b.y2.used){f.textAlign=b.y2.options.titleAlign||"left";f.textBaseline="middle";f.angle=Flotr.toRad(b.y2.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.y2.options.title,this.plotOffset.left+this.plotWidth+b.y2.maxLabel.width+2*g,this.plotOffset.top+this.plotHeight/2,f)}}else{e=['<div style="color:'+d.grid.color+';" class="flotr-titles">'];if(d.title){e.push('<div style="position:absolute;top:0;left:',this.plotOffset.left,"px;font-size:1em;font-weight:bold;text-align:center;width:",this.plotWidth,'px;" class="flotr-title">',d.title,"</div>")}if(d.subtitle){e.push('<div style="position:absolute;top:',this.titleHeight,"px;left:",this.plotOffset.left,"px;font-size:smaller;text-align:center;width:",this.plotWidth,'px;" class="flotr-subtitle">',d.subtitle,"</div>")}e.push("</div>");e.push('<div class="flotr-axis-title" style="font-weight:bold;">');if(b.x.options.title&&b.x.used){e.push('<div style="position:absolute;top:',(this.plotOffset.top+this.plotHeight+d.grid.labelMargin+b.x.titleSize.height),"px;left:",this.plotOffset.left,"px;width:",this.plotWidth,'px;text-align:center;" class="flotr-axis-title">',b.x.options.title,"</div>")}if(b.x2.options.title&&b.x2.used){e.push('<div style="position:absolute;top:0;left:',this.plotOffset.left,"px;width:",this.plotWidth,'px;text-align:center;" class="flotr-axis-title">',b.x2.options.title,"</div>")}if(b.y.options.title&&b.y.used){e.push('<div style="position:absolute;top:',(this.plotOffset.top+this.plotHeight/2-b.y.titleSize.height/2),'px;left:0;text-align:right;" class="flotr-axis-title">',b.y.options.title,"</div>")}if(b.y2.options.title&&b.y2.used){e.push('<div style="position:absolute;top:',(this.plotOffset.top+this.plotHeight/2-b.y.titleSize.height/2),'px;right:0;text-align:right;" class="flotr-axis-title">',b.y2.options.title,"</div>")}e.push("</div>");this.el.insert(e.join(""))}},drawSeries:function(a){a=a||this.series;var b=false;for(type in Flotr.graphTypes){if(a[type]&&a[type].show){b=true;this[type].draw(a)}}if(!b){this[this.options.defaultType].draw(a)}},insertLegend:function(){if(!this.options.legend.show){return}var o=this.series,q=this.plotOffset,e=this.options,a=e.legend,N=[],b=false,A=this.ctx,D;var C=o.findAll(function(c){return(c.label&&!c.hide)}).length;if(C){if(!e.HtmlText&&this.textEnabled&&!$(a.container)){var F={size:e.fontSize*1.1,color:e.grid.color};var w=a.position,z=a.margin,v=a.labelBoxWidth,M=a.labelBoxHeight,E=a.labelBoxMargin,I=q.left+z,G=q.top+z;var L=0;for(D=o.length-1;D>-1;--D){if(!o[D].label||o[D].hide){continue}var j=a.labelFormatter(o[D].label);L=Math.max(L,Flotr.measureText(A,j,F).width)}var u=Math.round(v+E*3+L),f=Math.round(C*(E+M)+E);if(w.charAt(0)=="s"){G=q.top+this.plotHeight-(z+f)}if(w.charAt(1)=="e"){I=q.left+this.plotWidth-(z+u)}var B=this.processColor(e.legend.backgroundColor||"rgb(240,240,240)",{opacity:e.legend.backgroundOpacity||0.1});A.fillStyle=B;A.fillRect(I,G,u,f);A.strokeStyle=e.legend.labelBoxBorderColor;A.strokeRect(Flotr.toPixel(I),Flotr.toPixel(G),u,f);var n=I+E;var l=G+E;for(D=0;D<o.length;D++){if(!o[D].label||o[D].hide){continue}var j=a.labelFormatter(o[D].label);A.fillStyle=o[D].color;A.fillRect(n,l,v-1,M-1);A.strokeStyle=a.labelBoxBorderColor;A.lineWidth=1;A.strokeRect(Math.ceil(n)-1.5,Math.ceil(l)-1.5,v+2,M+2);Flotr.drawText(A,j,n+v+E,l+(M+F.size-A.fontDescent(F))/2,F);l+=M+E}}else{for(D=0;D<o.length;++D){if(!o[D].label||o[D].hide){continue}if(D%e.legend.noColumns==0){N.push(b?"</tr><tr>":"<tr>");b=true}var t=o[D],j=a.labelFormatter(t.label),k=a.labelBoxWidth,h=a.labelBoxHeight,d="opacity:"+t.bars.fillOpacity+";filter:alpha(opacity="+t.bars.fillOpacity*100+");",B="background-color:"+((t.bars.show&&t.bars.fillColor&&t.bars.fill)?t.bars.fillColor:t.color)+";";N.push('<td class="flotr-legend-color-box">','<div style="border:1px solid ',a.labelBoxBorderColor,';padding:1px">','<div style="width:',(k-1),"px;height:",(h-1),"px;border:1px solid ",o[D].color,'">','<div style="width:',k,"px;height:",h,"px;",d,B,'"></div>',"</div>","</div>","</td>",'<td class="flotr-legend-label">',j,"</td>")}if(b){N.push("</tr>")}if(N.length>0){var H='<table style="font-size:smaller;color:'+e.grid.color+'">'+N.join("")+"</table>";if(e.legend.container!=null){$(e.legend.container).innerHTML=H}else{var g="",w=e.legend.position,z=e.legend.margin;if(w.charAt(0)=="n"){g+="top:"+(z+q.top)+"px;bottom:auto;"}else{if(w.charAt(0)=="s"){g+="bottom:"+(z+q.bottom)+"px;top:auto;"}}if(w.charAt(1)=="e"){g+="right:"+(z+q.right)+"px;left:auto;"}else{if(w.charAt(1)=="w"){g+="left:"+(z+q.left)+"px;right:auto;"}}var r=this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;'+g+'">'+H+"</div>").select("div.flotr-legend")[0];if(e.legend.backgroundOpacity!=0){var K=e.legend.backgroundColor;if(K==null){var J=(e.grid.backgroundColor!=null)?e.grid.backgroundColor:Flotr.Color.extract(r);K=this.processColor(J,null,{opacity:1})}this.el.insert('<div class="flotr-legend-bg" style="position:absolute;width:'+r.getWidth()+"px;height:"+r.getHeight()+"px;"+g+"background-color:"+K+';"> </div>').select("div.flotr-legend-bg")[0].setOpacity(e.legend.backgroundOpacity)}}}}}},getEventPosition:function(a){var e=this.overlay.cumulativeOffset(),d=Event.pointer(a),c=(d.x-e.left-this.plotOffset.left),b=(d.y-e.top-this.plotOffset.top);return{x:this.axes.x.p2d(c),x2:this.axes.x2.p2d(c),y:this.axes.y.p2d(b),y2:this.axes.y2.p2d(b),relX:c,relY:b,absX:d.x,absY:d.y}},clickHandler:function(a){if(this.ignoreClick){return this.ignoreClick=false}this.el.fire("flotr:click",[this.getEventPosition(a),this])},mouseMoveHandler:function(a){var b=this.getEventPosition(a);this.lastMousePos.pageX=b.absX;this.lastMousePos.pageY=b.absY;if(this.options.crosshair.mode){this.clearCrosshair()}if(this.selectionInterval==null&&(this.options.mouse.track||this.series.any(function(c){return c.mouse&&c.mouse.track}))){this.hit(b)}if(this.options.crosshair.mode){this.drawCrosshair(b)}this.el.fire("flotr:mousemove",[a,b,this])},mouseDownHandler:function(c){if(c.isRightClick()){c.stop();var b=this.overlay;b.hide();function a(){b.show();document.stopObserving("mousemove",a)}document.observe("mousemove",a);return}if(!this.options.selection.mode||!c.isLeftClick()){return}this.setSelectionPos(this.selection.first,c);if(this.selectionInterval!=null){clearInterval(this.selectionInterval)}this.lastMousePos.pageX=null;this.selectionInterval=setInterval(this.updateSelection.bindAsEventListener(this),1000/this.options.selection.fps);this.mouseUpHandler=this.mouseUpHandler.bindAsEventListener(this);document.observe("mouseup",this.mouseUpHandler)},fireSelectEvent:function(){var b=this.axes,g=this.selection,d,c,f,e;d=b.x.p2d(g.first.x);c=b.x.p2d(g.second.x);f=b.y.p2d(g.first.y);e=b.y.p2d(g.second.y);this.el.fire("flotr:select",[{x1:Math.min(d,c),y1:Math.min(f,e),x2:Math.max(d,c),y2:Math.max(f,e),xfirst:d,xsecond:c,yfirst:f,ysecond:e},this])},mouseUpHandler:function(a){document.stopObserving("mouseup",this.mouseUpHandler);a.stop();if(this.selectionInterval!=null){clearInterval(this.selectionInterval);this.selectionInterval=null}this.setSelectionPos(this.selection.second,a);this.clearSelection();if(this.selectionIsSane()){this.drawSelection();this.fireSelectEvent();this.ignoreClick=true}},setSelectionPos:function(d,b){var a=this.options,c=this.overlay.cumulativeOffset();if(a.selection.mode.indexOf("x")==-1){d.x=(d==this.selection.first)?0:this.plotWidth}else{d.x=b.pageX-c.left-this.plotOffset.left;d.x=Math.min(Math.max(0,d.x),this.plotWidth)}if(a.selection.mode.indexOf("y")==-1){d.y=(d==this.selection.first)?0:this.plotHeight}else{d.y=b.pageY-c.top-this.plotOffset.top;d.y=Math.min(Math.max(0,d.y),this.plotHeight)}},updateSelection:function(){if(this.lastMousePos.pageX==null){return}this.setSelectionPos(this.selection.second,this.lastMousePos);this.clearSelection();if(this.selectionIsSane()){this.drawSelection()}},clearSelection:function(){if(this.prevSelection==null){return}var g=this.prevSelection,e=this.octx.lineWidth,c=this.plotOffset,a=Math.min(g.first.x,g.second.x),f=Math.min(g.first.y,g.second.y),b=Math.abs(g.second.x-g.first.x),d=Math.abs(g.second.y-g.first.y);this.octx.clearRect(a+c.left-e/2+0.5,f+c.top-e/2+0.5,b+e,d+e);this.prevSelection=null},setSelection:function(b,g){var j=this.options,a=this.axes.x,f=this.axes.y,c=f.scale,h=a.scale,e=j.selection.mode.indexOf("x")!=-1,d=j.selection.mode.indexOf("y")!=-1;this.clearSelection();this.selection.first.y=(e&&!d)?0:(f.max-b.y1)*c;this.selection.second.y=(e&&!d)?this.plotHeight:(f.max-b.y2)*c;this.selection.first.x=(d&&!e)?0:(b.x1-a.min)*h;this.selection.second.x=(d&&!e)?this.plotWidth:(b.x2-a.min)*h;this.drawSelection();if(!g){this.fireSelectEvent()}},drawSelection:function(){var c=this.prevSelection,j=this.selection,g=this.octx,k=this.options,a=this.plotOffset;if(c!=null&&j.first.x==c.first.x&&j.first.y==c.first.y&&j.second.x==c.second.x&&j.second.y==c.second.y){return}g.save();g.strokeStyle=this.processColor(k.selection.color,{opacity:0.8});g.lineWidth=1;g.lineJoin="miter";g.fillStyle=this.processColor(k.selection.color,{opacity:0.4});this.prevSelection={first:{x:j.first.x,y:j.first.y},second:{x:j.second.x,y:j.second.y}};var e=Math.min(j.first.x,j.second.x),d=Math.min(j.first.y,j.second.y),f=Math.abs(j.second.x-j.first.x),b=Math.abs(j.second.y-j.first.y);g.fillRect(e+a.left+0.5,d+a.top+0.5,f,b);g.strokeRect(e+a.left+0.5,d+a.top+0.5,f,b);g.restore()},drawCrosshair:function(f){var d=this.octx,c=this.options,b=this.plotOffset,a=b.left+f.relX+0.5,e=b.top+f.relY+0.5;if(f.relX<0||f.relY<0||f.relX>this.plotWidth||f.relY>this.plotHeight){this.el.style.cursor=null;this.el.removeClassName("flotr-crosshair");return}this.lastMousePos.relX=null;this.lastMousePos.relY=null;if(c.crosshair.hideCursor){this.el.style.cursor=Prototype.Browser.Gecko?"none":"url(blank.cur),crosshair";this.el.addClassName("flotr-crosshair")}d.save();d.strokeStyle=c.crosshair.color;d.lineWidth=1;d.beginPath();if(c.crosshair.mode.indexOf("x")!=-1){d.moveTo(a,b.top);d.lineTo(a,b.top+this.plotHeight);this.lastMousePos.relX=a}if(c.crosshair.mode.indexOf("y")!=-1){d.moveTo(b.left,e);d.lineTo(b.left+this.plotWidth,e);this.lastMousePos.relY=e}d.stroke();d.restore()},clearCrosshair:function(){if(this.lastMousePos.relX!=null){this.octx.clearRect(this.lastMousePos.relX-0.5,this.plotOffset.top,1,this.plotHeight+1)}if(this.lastMousePos.relY!=null){this.octx.clearRect(this.plotOffset.left,this.lastMousePos.relY-0.5,this.plotWidth+1,1)}},selectionIsSane:function(){return Math.abs(this.selection.second.x-this.selection.first.x)>=5&&Math.abs(this.selection.second.y-this.selection.first.y)>=5},clearHit:function(){if(!this.prevHit){return}var d=this.prevHit,e=this.plotOffset,m=d.series,f=m.bars.lineWidth,c=m.pie.lineWidth,b=d.xaxis,k=d.yaxis;if(!m.bars.show&&!m.pie.show){var h=m.mouse.radius+f;this.octx.clearRect(e.left+b.d2p(d.x)-h,e.top+k.d2p(d.y)-h,h*2,h*2)}else{if(m.bars.show){var l=m.bars.barWidth;this.octx.clearRect(b.d2p(d.x-l/2)+e.left-f,k.d2p(d.y>=0?d.y:0)+e.top-f,b.d2p(l+b.min)+f*2,k.d2p(d.y<0?d.y:0)+f*2)}else{var a={x:e.left+(this.plotWidth)/2,y:e.top+(this.plotHeight)/2},j=(Math.min(this.canvasWidth,this.canvasHeight)*m.pie.sizeRatio)/2,g=(d.series.pie.explode+c)*4;this.octx.clearRect(a.x-j-g,a.y-j-g,2*(j+g),2*(j+g))}}},drawHit:function(c){var k=this.octx,l=c.series,a=c.xaxis,h=c.yaxis;if(l.mouse.lineColor!=null){k.save();k.lineWidth=l.points.lineWidth;k.strokeStyle=l.mouse.lineColor;k.fillStyle=this.processColor(l.mouse.fillColor||"#ffffff",{opacity:l.mouse.fillOpacity});if(!l.bars.show&&!l.pie.show){k.translate(this.plotOffset.left,this.plotOffset.top);k.beginPath();k.arc(a.d2p(c.x),h.d2p(c.y),l.mouse.radius,0,2*Math.PI,true);k.fill();k.stroke();k.closePath()}else{if(l.bars.show){k.save();k.translate(this.plotOffset.left,this.plotOffset.top);k.beginPath();if(l.mouse.trackAll){k.moveTo(a.d2p(c.x),h.d2p(0));k.lineTo(a.d2p(c.x),h.d2p(c.yaxis.max))}else{var j=l.bars.barWidth;k.moveTo(a.d2p(c.x-(j/2)),h.d2p(this.axes.y.min));k.lineTo(a.d2p(c.x-(j/2)),h.d2p(c.y));k.lineTo(a.d2p(c.x+(j/2)),h.d2p(c.y));k.lineTo(a.d2p(c.x+(j/2)),h.d2p(this.axes.y.min));if(l.mouse.fillColor){k.fill()}}k.stroke();k.closePath();k.restore()}else{k.save();k.translate(this.plotOffset.left,this.plotOffset.top);k.beginPath();if(l.mouse.trackAll){k.moveTo(a.d2p(c.x),h.d2p(0));k.lineTo(a.d2p(c.x),h.d2p(c.yaxis.max))}else{var b={x:(this.plotWidth)/2,y:(this.plotHeight)/2},f=(Math.min(this.canvasWidth,this.canvasHeight)*l.pie.sizeRatio)/2;var e=c.sAngle<c.eAngle?(c.sAngle+c.eAngle)/2:(c.sAngle+c.eAngle+2*Math.PI)/2,g=b.x+Math.cos(e)*c.series.pie.explode,d=b.y+Math.sin(e)*c.series.pie.explode;k.beginPath();k.moveTo(g,d);if(c.fraction!=1){k.arc(g,d,f,c.sAngle,c.eAngle,false)}else{k.arc(g,d,f,c.sAngle,c.eAngle-0.00001,false)}k.lineTo(g,d);k.closePath()}k.stroke();k.closePath();k.restore()}}k.restore()}this.prevHit=c},newHit:function(d){var f=this.series,c=this.options,a,b;for(var e=f.length-1;e>-1;--e){s=f[e];if(!s.mouse.track){continue}for(var j in Flotr.graphTypes){if(!this[j].getHit){continue}var g=this[j].getHit(s,d);if(g.index!==undefined){a=s.mouse.trackDecimals;if(a==null||a<0){a=0}b=s.mouse.trackFormatter(g);this.drawTooltip(b,g.x,g.y,s.mouse);this.mouseTrack.fire("flotr:hit",[g,this])}}}},hit:function(O){var h=this.series,I=this.options,e=this.prevHit,G=this.plotOffset,ah=this.octx,ad,D,L,v,S,Q,X,J,g,f,ac,Z={dist:Number.MAX_VALUE,x:null,y:null,relX:O.relX,relY:O.relY,absX:O.absX,absY:O.absY,sAngle:null,eAngle:null,fraction:null,mouse:null,xaxis:null,yaxis:null,series:null,index:null,seriesIndex:null};if(I.mouse.trackAll){for(ac=0;ac<h.length;ac++){U=h[0];ad=U.data;X=U.xaxis;J=U.yaxis;L=(2*I.points.lineWidth)/X.scale*U.mouse.sensibility;g=X.p2d(O.relX);f=J.p2d(O.relY);for(var ab=0;ab<ad.length;ab++){S=ad[ab][0];Q=ad[ab][1];if(Q===null||X.min>S||X.max<S||J.min>Q||J.max<Q||g<X.min||g>X.max||f<J.min||f>J.max){continue}var P=Math.abs(S-g);if((!U.bars.show&&P<L)||(U.bars.show&&P<U.bars.barWidth/2)||(Q<0&&f<0&&f>Q)){var E=P;if(E<Z.dist){Z.dist=E;Z.x=S;Z.y=Q;Z.xaxis=X;Z.yaxis=J;Z.mouse=U.mouse;Z.series=U;Z.allSeries=h;Z.index=ab}}}}}else{if(!I.pie.show){for(ac=0;ac<h.length;ac++){U=h[ac];if(!U.mouse.track){continue}ad=U.data;X=U.xaxis;J=U.yaxis;D=2*I.points.lineWidth*U.mouse.sensibility;L=D/X.scale;v=D/J.scale;g=X.p2d(O.relX);f=J.p2d(O.relY);for(var ab=0,Y,o;ab<ad.length;ab++){S=ad[ab][0];Q=ad[ab][1];if(Q===null||X.min>S||X.max<S||J.min>Q||J.max<Q){continue}var P=Math.abs(S-g),F=Math.abs(Q-f);if(((!U.bars.show)&&P<L&&(!U.mouse.trackY||F<v))||(U.bars.show&&P<U.bars.barWidth/2&&((Q>0&&f>0&&f<Q)||(Q<0&&f<0&&f>Q)))){var E=Math.sqrt(P*P+F*F);if(E<Z.dist){Z.dist=E;Z.x=S;Z.y=Q;Z.xaxis=X;Z.yaxis=J;Z.mouse=U.mouse;Z.series=U;Z.allSeries=h;Z.index=ab;Z.seriesIndex=ac}}}}}else{var V=(Math.min(this.canvasWidth,this.canvasHeight)*I.pie.sizeRatio)/2,u=1,d={x:(this.plotWidth)/2,y:(this.plotHeight)/2},t=this.series.collect(function(b,a){if(b.pie.show&&b.data[0][1]!==null){return{name:(b.label||b.data[0][1]),value:[a,b.data[0][1]],options:b.pie,series:b}}}),A=t.pluck("value").pluck(1).inject(0,function(a,b){return a+b}),z=0,C=I.pie.startAngle,T=0;var r=t.collect(function(a){C+=z;T=parseFloat(a.value[1]);z=T/A;return{name:a.name,fraction:z,x:a.value[0],y:T,value:T,options:a.options,series:a.series,startAngle:2*C*Math.PI,endAngle:2*(C+z)*Math.PI}});for(ac=0;ac<h.length;ac++){U=h[ac];S=U.data[0][0];Q=U.data[0][1];if(Q===null){continue}var ag=(O.relX-d.x),af=(O.relY-d.y),ae=Math.sqrt(Math.pow(ag,2)+Math.pow(af,2)),H=(r[ac].startAngle)%(2*Math.PI),q=(r[ac].endAngle)%(2*Math.PI),H=(H>0)?H:H+(2*Math.PI),q=(q>0)?q:q+(2*Math.PI),l=af/ae,R=Math.asin(l)%(2*Math.PI),R=(R>0)?R:R+(2*Math.PI),w=Math.asin(-l)+(Math.PI);if(ae<V+10&&((((ag>0&&H<R&&q>R))||(ag<0&&H<w&&q>w))||((H>q||r[ac].fraction==1)&&((ag>0&&(H<R||q>R))||(ag<0&&(H<w||q>w)))))){Z.x=S;Z.y=Q;Z.sAngle=H;Z.eAngle=q,Z.mouse=U.mouse;Z.series=U;Z.allSeries=h;Z.seriesIndex=ac;Z.fraction=r[ac].fraction}}}}if(Z.series&&(Z.mouse&&Z.mouse.track&&!e||(e))){var k=this.mouseTrack,N="",U=Z.series,W=Z.mouse.position,aa=Z.mouse.margin,M="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;";if(!Z.mouse.relative){if(W.charAt(0)=="n"){N+="top:"+(aa+G.top)+"px;bottom:auto;"}else{if(W.charAt(0)=="s"){N+="bottom:"+(aa+G.bottom)+"px;top:auto;"}}if(W.charAt(1)=="e"){N+="right:"+(aa+G.right)+"px;left:auto;"}else{if(W.charAt(1)=="w"){N+="left:"+(aa+G.left)+"px;right:auto;"}}}else{if(!U.bars.show&&!U.pie.show){if(W.charAt(0)=="n"){N+="bottom:"+(aa-G.top-Z.yaxis.d2p(Z.y)+this.canvasHeight)+"px;top:auto;"}else{if(W.charAt(0)=="s"){N+="top:"+(aa+G.top+Z.yaxis.d2p(Z.y))+"px;bottom:auto;"}}if(W.charAt(1)=="e"){N+="left:"+(aa+G.left+Z.xaxis.d2p(Z.x))+"px;right:auto;"}else{if(W.charAt(1)=="w"){N+="right:"+(aa-G.left-Z.xaxis.d2p(Z.x)+this.canvasWidth)+"px;left:auto;"}}}else{if(U.bars.show){N+="bottom:"+(aa-G.top-Z.yaxis.d2p(Z.y/2)+this.canvasHeight)+"px;top:auto;";N+="left:"+(aa+G.left+Z.xaxis.d2p(Z.x-I.bars.barWidth/2))+"px;right:auto;"}else{var d={x:(this.plotWidth)/2,y:(this.plotHeight)/2},V=(Math.min(this.canvasWidth,this.canvasHeight)*U.pie.sizeRatio)/2,B=Z.sAngle<Z.eAngle?(Z.sAngle+Z.eAngle)/2:(Z.sAngle+Z.eAngle+2*Math.PI)/2;N+="bottom:"+(aa-G.top-d.y-Math.sin(B)*V/2+ +this.canvasHeight)+"px;top:auto;";N+="left:"+(aa+G.left+d.x+Math.cos(B)*V/2)+"px;right:auto;"}}}M+=N;if(!k){this.el.insert('<div class="flotr-mouse-value" style="'+M+'"></div>');k=this.mouseTrack=this.el.select(".flotr-mouse-value")[0]}else{k.style.cssText=M;this.mouseTrack=k}if(Z.x!==null&&Z.y!==null){k.show();this.clearHit();this.drawHit(Z);var K=Z.mouse.trackDecimals;if(K==null||K<0){K=0}k.innerHTML=Z.mouse.trackFormatter({x:Z.x.toFixed(K),y:Z.y.toFixed(K),series:Z.series,index:Z.index,nearest:Z,fraction:Z.fraction});k.fire("flotr:hit",[Z,this])}else{if(e){k.hide();this.clearHit()}}}else{if(this.prevHit){this.mouseTrack.hide();this.clearHit()}}},drawTooltip:function(f,h,g,j){var a=this.mouseTrack,b="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;",c=j.position,e=j.margin,d=this.plotOffset;if(!a){this.el.insert('<div class="flotr-mouse-value"></div>');a=this.mouseTrack=this.el.select(".flotr-mouse-value")[0]}if(h!==null&&g!==null){if(!j.relative){if(c.charAt(0)=="n"){b+="top:"+(e+d.top)+"px;bottom:auto;"}else{if(c.charAt(0)=="s"){b+="bottom:"+(e+d.bottom)+"px;top:auto;"}}if(c.charAt(1)=="e"){b+="right:"+(e+d.right)+"px;left:auto;"}else{if(c.charAt(1)=="w"){b+="left:"+(e+d.left)+"px;right:auto;"}}}else{if(c.charAt(0)=="n"){b+="bottom:"+(e-d.top-g+this.canvasHeight)+"px;top:auto;"}else{if(c.charAt(0)=="s"){b+="top:"+(e+d.top+g)+"px;bottom:auto;"}}if(c.charAt(1)=="e"){b+="left:"+(e+d.left+h)+"px;right:auto;"}else{if(c.charAt(1)=="w"){b+="right:"+(e-d.left-h+this.canvasWidth)+"px;left:auto;"}}}a.style.cssText=b;a.update(f).show()}else{a.hide()}},saveImage:function(d,c,a,b){var e=null;if(Prototype.Browser.IE&&!Flotr.isIE9){e="<html><body>"+this.canvas.firstChild.innerHTML+"</body></html>";return window.open().document.write(e)}switch(d){case"jpeg":case"jpg":e=Canvas2Image.saveAsJPEG(this.canvas,b,c,a);break;default:case"png":e=Canvas2Image.saveAsPNG(this.canvas,b,c,a);break;case"bmp":e=Canvas2Image.saveAsBMP(this.canvas,b,c,a);break}if(Object.isElement(e)&&b){this.restoreCanvas();this.canvas.hide();this.overlay.hide();this.el.insert(e.setStyle({position:"absolute"}))}},restoreCanvas:function(){this.canvas.show();this.overlay.show();this.el.select("img").invoke("remove")}});Flotr.Color=Class.create({initialize:function(h,f,d,e){this.rgba=["r","g","b","a"];var c=4;while(-1<--c){this[this.rgba[c]]=arguments[c]||((c==3)?1:0)}this.normalize()},adjust:function(d,c,e,b){var a=4;while(-1<--a){if(arguments[a]!=null){this[this.rgba[a]]+=arguments[a]}}return this.normalize()},scale:function(d,c,e,b){var a=4;while(-1<--a){if(arguments[a]!=null){this[this.rgba[a]]*=arguments[a]}}return this.normalize()},clone:function(){return new Flotr.Color(this.r,this.b,this.g,this.a)},limit:function(b,a,c){return Math.max(Math.min(b,c),a)},normalize:function(){var a=this.limit;this.r=a(parseInt(this.r),0,255);this.g=a(parseInt(this.g),0,255);this.b=a(parseInt(this.b),0,255);this.a=a(this.a,0,1);return this},distance:function(b){if(!b){return}b=new Flotr.Color.parse(b);var c=0,a=3;while(-1<--a){c+=Math.abs(this[this.rgba[a]]-b[this.rgba[a]])}return c},toString:function(){return(this.a>=1)?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"}});Object.extend(Flotr.Color,{parse:function(b){if(b instanceof Flotr.Color){return b}var a,d=Flotr.Color;if((a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))){return new d(parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16))}if((a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))){return new d(parseInt(a[1]),parseInt(a[2]),parseInt(a[3]))}if((a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))){return new d(parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16))}if((a=/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(b))){return new d(parseInt(a[1]),parseInt(a[2]),parseInt(a[3]),parseFloat(a[4]))}if((a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))){return new d(parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55)}if((a=/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(b))){return new d(parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55,parseFloat(a[4]))}var c=(b+"").strip().toLowerCase();if(c=="transparent"){return new d(255,255,255,0)}return(a=d.names[c])?new d(a[0],a[1],a[2]):new d(0,0,0,0)},extract:function(b){var a;do{a=b.getStyle("background-color").toLowerCase();if(!(a==""||a=="transparent")){break}b=b.up()}while(!b.nodeName.match(/^body$/i));return new Flotr.Color(a=="rgba(0, 0, 0, 0)"?"transparent":a)},names:{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]}});Flotr.Date={format:function(j,h){if(!j){return}var g={h:j.getUTCHours().toString(),H:a(j.getUTCHours()),M:a(j.getUTCMinutes()),S:a(j.getUTCSeconds()),s:j.getUTCMilliseconds(),d:j.getUTCDate().toString(),m:(j.getUTCMonth()+1).toString(),y:j.getUTCFullYear().toString(),b:Flotr.Date.monthNames[j.getUTCMonth()]};function a(c){c+="";return c.length==1?"0"+c:c}var f=[],k,e=false;for(var b=0;b<h.length;++b){k=h.charAt(b);if(e){f.push(g[k]||k);e=false}else{if(k=="%"){e=true}else{f.push(k)}}}return f.join("")},getFormat:function(c,b){var a=Flotr.Date.timeUnits;if(c<a.second){return"%h:%M:%S.%s"}else{if(c<a.minute){return"%h:%M:%S"}else{if(c<a.day){return(b<2*a.day)?"%h:%M":"%b %d %h:%M"}else{if(c<a.month){return"%b %d"}else{if(c<a.year){return(b<a.year)?"%b":"%b %y"}else{return"%y"}}}}}},formatter:function(a,e){var f=new Date(a);if(e.options.timeFormat!=null){return Flotr.Date.format(f,e.options.timeFormat)}var c=e.max-e.min,b=e.tickSize*Flotr.Date.timeUnits[e.tickUnit];return Flotr.Date.format(f,Flotr.Date.getFormat(b,c))},generator:function(c){var j=[],h=new Date(c.min),g=Flotr.Date.timeUnits;var b=c.tickSize*g[c.tickUnit];switch(c.tickUnit){case"millisecond":h.setUTCMilliseconds(Flotr.floorInBase(h.getUTCMilliseconds(),c.tickSize));break;case"second":h.setUTCSeconds(Flotr.floorInBase(h.getUTCSeconds(),c.tickSize));break;case"minute":h.setUTCMinutes(Flotr.floorInBase(h.getUTCMinutes(),c.tickSize));break;case"hour":h.setUTCHours(Flotr.floorInBase(h.getUTCHours(),c.tickSize));break;case"month":h.setUTCMonth(Flotr.floorInBase(h.getUTCMonth(),c.tickSize));break;case"year":h.setUTCFullYear(Flotr.floorInBase(h.getUTCFullYear(),c.tickSize));break}if(b>=g.second){h.setUTCMilliseconds(0)}if(b>=g.minute){h.setUTCSeconds(0)}if(b>=g.hour){h.setUTCMinutes(0)}if(b>=g.day){h.setUTCHours(0)}if(b>=g.day*4){h.setUTCDate(1)}if(b>=g.year){h.setUTCMonth(0)}var l=0,k=Number.NaN,e;do{e=k;k=h.getTime();j.push({v:k,label:Flotr.Date.formatter(k,c)});if(c.tickUnit=="month"){if(c.tickSize<1){h.setUTCDate(1);var a=h.getTime();h.setUTCMonth(h.getUTCMonth()+1);var f=h.getTime();h.setTime(k+l*g.hour+(f-a)*c.tickSize);l=h.getUTCHours();h.setUTCHours(0)}else{h.setUTCMonth(h.getUTCMonth()+c.tickSize)}}else{if(c.tickUnit=="year"){h.setUTCFullYear(h.getUTCFullYear()+c.tickSize)}else{h.setTime(k+b)}}}while(k<c.max&&k!=e);return j},timeUnits:{millisecond:1,second:1000,minute:1000*60,hour:1000*60*60,day:1000*60*60*24,month:1000*60*60*24*30,year:1000*60*60*24*365.2425},spec:[[1,"millisecond"],[20,"millisecond"],[50,"millisecond"],[100,"millisecond"],[200,"millisecond"],[500,"millisecond"],[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]};Flotr.addType("lines",{options:{show:false,lineWidth:2,fill:false,fillColor:null,fillOpacity:0.4},draw:function(c){c=c||this.series;var b=this.ctx;b.save();b.translate(this.plotOffset.left,this.plotOffset.top);b.lineJoin="round";var d=c.lines.lineWidth;var a=c.shadowSize;if(a>0){b.lineWidth=a/2;var e=d/2+b.lineWidth/2;b.strokeStyle="rgba(0,0,0,0.1)";this.lines.plot(c,e+a/2);b.strokeStyle="rgba(0,0,0,0.2)";this.lines.plot(c,e);if(c.lines.fill){b.fillStyle="rgba(0,0,0,0.05)";this.lines.plotArea(c,e+a/2)}}b.lineWidth=d;b.strokeStyle=c.color;if(c.lines.fill){b.fillStyle=this.processColor(c.lines.fillColor||c.color,{opacity:c.lines.fillOpacity});this.lines.plotArea(c,0)}this.lines.plot(c,0);b.restore()},plot:function(j,g){var r=this.ctx,a=j.xaxis,n=j.yaxis,h=j.data,e=h.length-1,k;if(h.length<2){return}var m=this.plotWidth,l=this.plotHeight,f=null,d=null;r.beginPath();for(k=0;k<e;++k){if(h[k][1]===null||h[k+1][1]===null){continue}if(a.options.scaling==="logarithmic"&&(h[k][0]<=0||h[k+1][0]<=0)){continue}if(n.options.scaling=="logarithmic"&&(h[k][1]<=0||h[k+1][1]<=0)){continue}var c=a.d2p(h[k][0]),q=n.d2p(h[k][1]),b=a.d2p(h[k+1][0]),o=n.d2p(h[k+1][1]);if(q>=o&&q>=l){if(o>=l){continue}c=c-(q-l-1)/(o-q)*(b-c);q=l-1}else{if(o>=q&&o>=l){if(q>=l){continue}b=c-(q-l-1)/(o-q)*(b-c);o=l-1}}if(q<=o&&q<0){if(o<0){continue}c=c-q/(o-q)*(b-c);q=0}else{if(o<=q&&o<0){if(q<0){continue}b=c-q/(o-q)*(b-c);o=0}}if(c<=b&&c<0){if(b<0){continue}q=q-c/(b-c)*(o-q);c=0}else{if(b<=c&&b<0){if(c<0){continue}o=q-c/(b-c)*(o-q);b=0}}if(c>=b&&c>=m){if(b>=m){continue}q=q+(m-c)/(b-c)*(o-q);c=m-1}else{if(b>=c&&b>=m){if(c>=m){continue}o=q+(m-c)/(b-c)*(o-q);b=m-1}}if((f!=c)||(d!=q+g)){r.moveTo(c,q+g)}f=b;d=o+g;r.lineTo(f,d)}r.stroke();r.closePath()},plotArea:function(k,e){var n=this.ctx,r=k.xaxis,b=k.yaxis,u=k.data,d=u.length-1,m,h=Math.min(Math.max(0,b.min),b.max),g=0,f=true;if(u.length<2){return}n.beginPath();for(var o=0;o<d;++o){var t=u[o][0],c=u[o][1],q=u[o+1][0],a=u[o+1][1];if(t<=q&&t<r.min){if(q<r.min){continue}c=(r.min-t)/(q-t)*(a-c)+c;t=r.min}else{if(q<=t&&q<r.min){if(t<r.min){continue}a=(r.min-t)/(q-t)*(a-c)+c;q=r.min}}if(t>=q&&t>r.max){if(q>r.max){continue}c=(r.max-t)/(q-t)*(a-c)+c;t=r.max}else{if(q>=t&&q>r.max){if(t>r.max){continue}a=(r.max-t)/(q-t)*(a-c)+c;q=r.max}}if(f){n.moveTo(r.d2p(t),b.d2p(h)+e);f=false}if(c>=b.max&&a>=b.max){n.lineTo(r.d2p(t),b.d2p(b.max)+e);n.lineTo(r.d2p(q),b.d2p(b.max)+e);continue}else{if(c<=b.min&&a<=b.min){n.lineTo(r.d2p(t),b.d2p(b.min)+e);n.lineTo(r.d2p(q),b.d2p(b.min)+e);continue}}var j=t,l=q;if(c<=a&&c<b.min&&a>=b.min){t=(b.min-c)/(a-c)*(q-t)+t;c=b.min}else{if(a<=c&&a<b.min&&c>=b.min){q=(b.min-c)/(a-c)*(q-t)+t;a=b.min}}if(c>=a&&c>b.max&&a<=b.max){t=(b.max-c)/(a-c)*(q-t)+t;c=b.max}else{if(a>=c&&a>b.max&&c<=b.max){q=(b.max-c)/(a-c)*(q-t)+t;a=b.max}}if(t!=j){m=(c<=b.min)?m=b.min:b.max;n.lineTo(r.d2p(j),b.d2p(m)+e);n.lineTo(r.d2p(t),b.d2p(m)+e)}n.lineTo(r.d2p(t),b.d2p(c)+e);n.lineTo(r.d2p(q),b.d2p(a)+e);if(q!=l){m=(a<=b.min)?b.min:b.max;n.lineTo(r.d2p(l),b.d2p(m)+e);n.lineTo(r.d2p(q),b.d2p(m)+e)}g=Math.max(q,l)}n.lineTo(r.d2p(r.max),b.d2p(h)+e);n.closePath();n.fill()}});Flotr.addType("bars",{options:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,horizontal:false,stacked:false,centered:true},draw:function(c){var a=this.ctx,e=c.bars.barWidth,d=Math.min(c.bars.lineWidth,e);a.save();a.translate(this.plotOffset.left,this.plotOffset.top);a.lineJoin="miter";a.lineWidth=d;a.strokeStyle=c.color;a.save();this.bars.plotShadows(c,e,0,c.bars.fill);a.restore();if(c.bars.fill){var b=c.bars.fillColor||c.color;a.fillStyle=this.processColor(b,{opacity:c.bars.fillOpacity})}this.bars.plot(c,e,0,c.bars.fill);a.restore()},plot:function(l,o,e,r){var B=l.data;if(B.length<1){return}var v=l.xaxis,c=l.yaxis,q=this.ctx,u;for(u=0;u<B.length;u++){var k=B[u][0],j=B[u][1],f=true,m=true,a=true;if(j===null){continue}var h=0;if(l.bars.stacked){$H(v.values).each(function(x){if(x.key==k){h=x.value.stack||0;x.value.stack=h+j}})}if(l.bars.horizontal){var d=h,w=k+h,g=j,n=j+o}else{var d=k-(l.bars.centered?o/2:0),w=k+o-(l.bars.centered?o/2:0),g=h,n=j+h}if(w<v.min||d>v.max||n<c.min||g>c.max){continue}if(d<v.min){d=v.min;f=false}if(w>v.max){w=v.max;if(v.lastSerie!=l&&l.bars.horizontal){m=false}}if(g<c.min){g=c.min}if(n>c.max){n=c.max;if(c.lastSerie!=l&&!l.bars.horizontal){m=false}}var b=v.d2p(d),t=v.d2p(w),A=c.d2p(n),z=c.d2p(g);if(r){q.fillRect(b,A,t-b,z-A)}if(l.bars.lineWidth!=0&&(f||a||m)){q.beginPath();q.moveTo(b,z+e);q[f?"lineTo":"moveTo"](b,A+e);q[m?"lineTo":"moveTo"](t,A+e);q[a?"lineTo":"moveTo"](t,z+e);q.stroke();q.closePath()}}},plotShadows:function(h,j,c){var u=h.data;if(u.length<1){return}var q,g,f,r=h.xaxis,a=h.yaxis,o=this.ctx,m=this.options.shadowSize;for(q=0;q<u.length;q++){g=u[q][0];f=u[q][1];if(f===null){continue}var d=0;if(h.bars.stacked){$H(r.values).each(function(v){if(v.key==g){d=v.value.stackShadow||0;v.value.stackShadow=d+f}})}if(h.bars.horizontal){var b=d,t=g+d,e=f,k=f+j}else{var b=g-(h.bars.centered?j/2:0),t=g+j-(h.bars.centered?j/2:0),e=d,k=f+d}if(t<r.min||b>r.max||k<a.min||e>a.max){continue}if(b<r.min){b=r.min}if(t>r.max){t=r.max}if(e<a.min){e=a.min}if(k>a.max){k=a.max}var n=r.d2p(t)-r.d2p(b)-((r.d2p(t)+m<=this.plotWidth)?0:m);var l=Math.max(0,a.d2p(e)-a.d2p(k)-((a.d2p(e)+m<=this.plotHeight)?0:m));o.fillStyle="rgba(0,0,0,0.05)";o.fillRect(Math.min(r.d2p(b)+m,this.plotWidth),Math.min(a.d2p(k)+m,this.plotWidth),n,l)}},extendXRange:function(a){if(a.options.max==null){var c=a.min,g=a.max,e,d,k,m,h,l=[],f=null;for(e=0;e<this.series.length;++e){m=this.series[e];h=m.bars;if(h.show&&m.xaxis==a){if(h.centered){g=Math.max(a.datamax+0.5,g);c=Math.min(a.datamin-0.5,c)}if(!h.horizontal&&(h.barWidth+a.datamax>g)){g=a.max+(h.centered?h.barWidth/2:h.barWidth)}if(h.stacked&&h.horizontal){for(d=0;d<m.data.length;d++){if(h.show&&h.stacked){k=m.data[d][0]+"";l[k]=(l[k]||0)+m.data[d][1];f=m}}for(d in l){g=Math.max(l[d],g)}}}}a.lastSerie=f;a.max=g;a.min=c}},extendYRange:function(a){if(a.options.max==null){var f=a.max,h,d,c,l,g,k={},e=null;for(d=0;d<this.series.length;++d){l=this.series[d];g=l.bars;if(g.show&&!l.hide&&l.yaxis==a){if(g.horizontal&&(g.barWidth+a.datamax>f)){f=a.max+g.barWidth}if(g.stacked&&!g.horizontal){for(c=0;c<l.data.length;c++){if(l.bars.show&&l.bars.stacked){h=l.data[c][0]+"";k[h]=(k[h]||0)+l.data[c][1];e=l}}for(c in k){f=Math.max(k[c],f)}}}}a.lastSerie=e;a.max=f}}});Flotr.addType("points",{options:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#FFFFFF",fillOpacity:0.4},draw:function(c){var b=this.ctx,d=c.lines.lineWidth,a=c.shadowSize;b.save();b.translate(this.plotOffset.left,this.plotOffset.top);if(a>0){b.lineWidth=a/2;b.strokeStyle="rgba(0,0,0,0.1)";this.points.plotShadows(c,a/2+b.lineWidth/2,c.points.radius);b.strokeStyle="rgba(0,0,0,0.2)";this.points.plotShadows(c,b.lineWidth/2,c.points.radius)}b.lineWidth=c.points.lineWidth;b.strokeStyle=c.color;b.fillStyle=c.points.fillColor!=null?c.points.fillColor:c.color;this.points.plot(c,c.points.radius,c.points.fill);b.restore()},plot:function(c,e,h){var a=c.xaxis,f=c.yaxis,j=this.ctx,d,g,b=c.data;for(d=b.length-1;d>-1;--d){g=b[d][0],y=b[d][1];if(y===null||g<a.min||g>a.max||y<f.min||y>f.max){continue}j.beginPath();j.arc(a.d2p(g),f.d2p(y),e,0,2*Math.PI,true);if(h){j.fill()}j.stroke();j.closePath()}},plotShadows:function(d,b,f){var a=d.xaxis,g=d.yaxis,j=this.ctx,e,h,c=d.data;for(e=c.length-1;e>-1;--e){h=c[e][0],y=c[e][1];if(y===null||h<a.min||h>a.max||y<g.min||y>g.max){continue}j.beginPath();j.arc(a.d2p(h),g.d2p(y)+b,f,0,Math.PI,false);j.stroke();j.closePath()}},getHit:function(g,n){var e,c,h,j,l,q,m,b=g.points,f=g.data,k=g.mouse.sensibility*(b.lineWidth+b.radius),a={index:null,series:g,distance:Number.MAX_VALUE,x:null,y:null,precision:1};for(h=f.length-1;h>-1;--h){j=f[h];q=g.xaxis.d2p(j[0]);m=g.yaxis.d2p(j[1]);e=q-n.relX;c=m-n.relY;l=Math.sqrt(e*e+c*c);if(l<k&&l<a.distance){a={index:h,series:g,distance:l,data:j,x:q,y:m,precision:1}}}return a},drawHit:function(b,a){},clearHit:function(b,a){}});Flotr.defaultPieLabelFormatter=function(a){return(a.fraction*100).toFixed(2)+"%"};Flotr.addType("pie",{options:{show:false,lineWidth:1,fill:true,fillColor:null,fillOpacity:0.6,explode:6,sizeRatio:0.6,startAngle:Math.PI/4,labelFormatter:Flotr.defaultPieLabelFormatter,pie3D:false,pie3DviewAngle:(Math.PI/2*0.8),pie3DspliceThickness:20},draw:function(g){if(this.options.pie.drawn){return}var m=this.ctx,c=this.options,e=g.pie.lineWidth,k=g.shadowSize,v=g.data,h=this.plotOffset,d=(Math.min(this.canvasWidth,this.canvasHeight)*g.pie.sizeRatio)/2,j=[],n=1,t=Math.sin(g.pie.viewAngle)*g.pie.spliceThickness/n,o={size:c.fontSize*1.2,color:c.grid.color,weight:1.5},u={x:h.left+(this.plotWidth)/2,y:h.top+(this.plotHeight)/2},r=this.series.collect(function(x,w){if(x.pie.show&&x.data[0][1]!==null){return{name:(x.label||x.data[0][1]),value:[w,x.data[0][1]],options:x.pie,series:x}}}),b=r.pluck("value").pluck(1).inject(0,function(w,x){return w+x}),f=0,q=g.pie.startAngle,l=0;var a=r.collect(function(w){q+=f;l=parseFloat(w.value[1]);f=l/b;return{name:w.name,fraction:f,x:w.value[0],y:l,value:l,options:w.options,series:w.series,startAngle:2*q*Math.PI,endAngle:2*(q+f)*Math.PI}});m.save();if(k>0){a.each(function(A){if(A.startAngle==A.endAngle){return}var w=(A.startAngle+A.endAngle)/2,x=u.x+Math.cos(w)*A.options.explode+k,z=u.y+Math.sin(w)*A.options.explode+k;this.pie.plotSlice(x,z,d,A.startAngle,A.endAngle,false,n);if(g.pie.fill){m.fillStyle="rgba(0,0,0,0.1)";m.fill()}},this)}if(c.HtmlText||!this.textEnabled){j=['<div style="color:'+this.options.grid.color+'" class="flotr-labels">']}a.each(function(K,F){if(K.startAngle==K.endAngle){return}var E=(K.startAngle+K.endAngle)/2,C=K.series.color,x=K.options.fillColor||C,G=u.x+Math.cos(E)*K.options.explode,A=u.y+Math.sin(E)*K.options.explode;this.pie.plotSlice(G,A,d,K.startAngle,K.endAngle,false,n);if(g.pie.fill){m.fillStyle=this.processColor(x,{opacity:g.pie.fillOpacity});m.fill()}m.lineWidth=e;m.strokeStyle=C;m.stroke();var J=c.pie.labelFormatter(K),w=(Math.cos(E)<0),L=(Math.sin(E)>0),B=(K.options.explode||g.pie.explode)+d+4,I=u.x+Math.cos(E)*B,H=u.y+Math.sin(E)*B;if(K.fraction&&J){if(c.HtmlText||!this.textEnabled){var D=L?(H-5):(this.plotHeight-H+5),z="position:absolute;"+(L?"top":"bottom")+":"+D+"px;";if(w){z+="right:"+(this.canvasWidth-I)+"px;text-align:right;"}else{z+="left:"+I+"px;text-align:left;"}j.push('<div style="',z,'" class="flotr-grid-label">',J,"</div>")}else{o.textAlign=w?"right":"left";o.textBaseline=L?"top":"bottom";Flotr.drawText(m,J,I,H,o)}}},this);if(c.HtmlText||!this.textEnabled){j.push("</div>");this.el.insert(j.join(""))}m.restore();c.pie.drawn=true},plotSlice:function(b,h,a,e,d,f,g){var c=this.ctx;g=g||1;c.scale(1,g);c.beginPath();c.moveTo(b,h);c.arc(b,h,a,e,d,f);c.lineTo(b,h);c.closePath()}});Flotr.addType("candles",{options:{show:false,lineWidth:1,wickLineWidth:1,candleWidth:0.6,fill:true,upFillColor:"#00A8F0",downFillColor:"#CB4B4B",fillOpacity:0.5,barcharts:false},draw:function(b){var a=this.ctx,c=b.candles.candleWidth;a.save();a.translate(this.plotOffset.left,this.plotOffset.top);a.lineJoin="miter";a.lineWidth=b.candles.lineWidth;this.candles.plotShadows(b,c/2);this.candles.plot(b,c/2);a.restore()},plot:function(l,e){var A=l.data;if(A.length<1){return}var v=l.xaxis,b=l.yaxis,q=this.ctx;for(var u=0;u<A.length;u++){var w=A[u],k=w[0],m=w[1],j=w[2],B=w[3],n=w[4];var c=k-l.candles.candleWidth/2,z=k+l.candles.candleWidth/2,g=Math.max(b.min,B),o=Math.min(b.max,j),a=Math.max(b.min,Math.min(m,n)),t=Math.min(b.max,Math.max(m,n));if(z<v.min||c>v.max||o<b.min||g>b.max){continue}var r=l.candles[m>n?"downFillColor":"upFillColor"];if(l.candles.fill&&!l.candles.barcharts){q.fillStyle=this.processColor(r,{opacity:l.candles.fillOpacity});q.fillRect(v.d2p(c),b.d2p(t)+e,v.d2p(z)-v.d2p(c),b.d2p(a)-b.d2p(t))}if(l.candles.lineWidth||l.candles.wickLineWidth){var k,h,f=(l.candles.wickLineWidth%2)/2;k=Math.floor(v.d2p((c+z)/2))+f;q.save();q.strokeStyle=r;q.lineWidth=l.candles.wickLineWidth;q.lineCap="butt";if(l.candles.barcharts){q.beginPath();q.moveTo(k,Math.floor(b.d2p(o)+e));q.lineTo(k,Math.floor(b.d2p(g)+e));h=Math.floor(b.d2p(m)+e)+0.5;q.moveTo(Math.floor(v.d2p(c))+f,h);q.lineTo(k,h);h=Math.floor(b.d2p(n)+e)+0.5;q.moveTo(Math.floor(v.d2p(z))+f,h);q.lineTo(k,h)}else{q.strokeRect(v.d2p(c),b.d2p(t)+e,v.d2p(z)-v.d2p(c),b.d2p(a)-b.d2p(t));q.beginPath();q.moveTo(k,Math.floor(b.d2p(t)+e));q.lineTo(k,Math.floor(b.d2p(o)+e));q.moveTo(k,Math.floor(b.d2p(a)+e));q.lineTo(k,Math.floor(b.d2p(g)+e))}q.stroke();q.closePath();q.restore()}}},plotShadows:function(h,c){var v=h.data;if(v.length<1||h.candles.barcharts){return}var r=h.xaxis,a=h.yaxis,n=this.options.shadowSize;for(var q=0;q<v.length;q++){var t=v[q],g=t[0],j=t[1],f=t[2],w=t[3],k=t[4];var b=g-h.candles.candleWidth/2,u=g+h.candles.candleWidth/2,e=Math.max(a.min,Math.min(j,k)),l=Math.min(a.max,Math.max(j,k));if(u<r.min||b>r.max||l<a.min||e>a.max){continue}var o=r.d2p(u)-r.d2p(b)-((r.d2p(u)+n<=this.plotWidth)?0:n);var m=Math.max(0,a.d2p(e)-a.d2p(l)-((a.d2p(e)+n<=this.plotHeight)?0:n));this.ctx.fillStyle="rgba(0,0,0,0.05)";this.ctx.fillRect(Math.min(r.d2p(b)+n,this.plotWidth),Math.min(a.d2p(l)+n,this.plotWidth),o,m)}},extendXRange:function(d){if(d.options.max==null){var a=d.min,e=d.max,b,f;for(b=0;b<this.series.length;++b){f=this.series[b].candles;if(f.show&&this.series[b].xaxis==d){e=Math.max(d.datamax+0.5,e);a=Math.min(d.datamin-0.5,a)}}d.max=e;d.min=a}}});Flotr.defaultMarkerFormatter=function(a){return(Math.round(a.y*100)/100)+""};Flotr.addType("markers",{options:{show:false,lineWidth:1,fill:false,fillColor:"#FFFFFF",fillOpacity:0.4,stroke:false,position:"ct",labelFormatter:Flotr.defaultMarkerFormatter,fontSize:Flotr.defaultOptions.fontSize},draw:function(d){d=d||this.series;var l=this.ctx,a=d.xaxis,g=d.yaxis,m=d.markers,c=d.data;l.save();l.translate(this.plotOffset.left,this.plotOffset.top);l.lineJoin="round";l.lineWidth=m.lineWidth;l.strokeStyle="rgba(0,0,0,0.5)";l.fillStyle=this.processColor(m.fillColor,{opacity:m.fillOpacity});for(var e=0;e<c.length;++e){var k=c[e][0],f=a.d2p(k),h=c[e][1],b=g.d2p(h),j=m.labelFormatter({x:k,y:h,index:e,data:c});this.markers.plot(f,b,j,m)}l.restore()},plot:function(g,e,f,j){var h=this.ctx,c=this.getTextDimensions(f,null,null),b=2,a=g,d=e;c.width=Math.floor(c.width+b*2);c.height=Math.floor(c.height+b*2);if(j.position.indexOf("c")!=-1){a-=c.width/2+b}else{if(j.position.indexOf("l")!=-1){a-=c.width}}if(j.position.indexOf("m")!=-1){d-=c.height/2+b}else{if(j.position.indexOf("t")!=-1){d-=c.height}}a=Math.floor(a)+0.5;d=Math.floor(d)+0.5;if(j.fill){h.fillRect(a,d,c.width,c.height)}if(j.stroke){h.strokeRect(a,d,c.width,c.height)}Flotr.drawText(h,f,a+b,d+b,{textBaseline:"top",textAlign:"left",size:j.fontSize})}});Flotr.addType("radar",{options:{show:false,lineWidth:2,fill:true,fillOpacity:0.4,radiusRatio:0.9},draw:function(c){var a=this.ctx,b=this.options;a.save();a.translate(this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+this.plotHeight/2);a.lineWidth=c.radar.lineWidth;a.fillStyle="rgba(0,0,0,0.05)";a.strokeStyle="rgba(0,0,0,0.05)";this.radar.plot(c,c.shadowSize/2);a.strokeStyle="rgba(0,0,0,0.1)";this.radar.plot(c,c.shadowSize/4);a.strokeStyle=c.color;a.fillStyle=this.processColor(c.color,{opacity:c.radar.fillOpacity});this.radar.plot(c);a.restore()},plot:function(e,b){var l=this.ctx,m=this.options,d=e.data,g=Math.min(this.plotHeight,this.plotWidth)*m.radar.radiusRatio/2,f=2*(Math.PI/d.length),a=-Math.PI/2;b=b||0;l.beginPath();for(var c=0;c<d.length;++c){var k=d[c][0],j=d[c][1],h=j/this.axes.y.max;l[c==0?"moveTo":"lineTo"](Math.cos(c*f+a)*g*h+b,Math.sin(c*f+a)*g*h+b)}l.closePath();if(e.radar.fill){l.fill()}l.stroke()}});Flotr.addType("bubbles",{options:{show:false,lineWidth:2,fill:true,fillOpacity:0.4,baseRadius:2},draw:function(c){var a=this.ctx,b=this.options;a.save();a.translate(this.plotOffset.left,this.plotOffset.top);a.lineWidth=c.bubbles.lineWidth;a.fillStyle="rgba(0,0,0,0.05)";a.strokeStyle="rgba(0,0,0,0.05)";this.bubbles.plot(c,c.shadowSize/2);a.strokeStyle="rgba(0,0,0,0.1)";this.bubbles.plot(c,c.shadowSize/4);a.strokeStyle=c.color;a.fillStyle=this.processColor(c.color,{opacity:c.radar.fillOpacity});this.bubbles.plot(c);a.restore()},plot:function(c,a){var j=this.ctx,k=this.options,b=c.data,e=k.bubbles.baseRadius;a=a||0;for(var d=0;d<b.length;++d){var h=b[d][0],g=b[d][1],f=b[d][2];j.beginPath();j.arc(c.xaxis.d2p(h)+a,c.yaxis.d2p(g)+a,e*f,0,Math.PI*2,true);j.stroke();if(c.bubbles.fill){j.fill()}j.closePath()}}});Flotr.addPlugin("spreadsheet",{options:{show:false,tabGraphLabel:"Graph",tabDataLabel:"Data",toolbarDownload:"Download CSV",toolbarSelectAll:"Select all",csvFileSeparator:",",decimalSeparator:".",tickFormatter:null},callbacks:{"flotr:afterconstruct":function(){this.el.select(".flotr-tabs-group,.flotr-datagrid-container").invoke("remove");if(!this.options.spreadsheet.show){return}var a=this.spreadsheet;a.tabsContainer=new Element("div",{style:"position:absolute;left:0px;width:"+this.canvasWidth+"px"}).addClassName("flotr-tabs-group");a.tabs={graph:new Element("div",{style:"float:left"}).addClassName("flotr-tab selected").update(this.options.spreadsheet.tabGraphLabel),data:new Element("div",{style:"float:left"}).addClassName("flotr-tab").update(this.options.spreadsheet.tabDataLabel)};a.tabsContainer.insert(a.tabs.graph).insert(a.tabs.data);this.el.insert({bottom:a.tabsContainer});var b=a.tabs.data.getHeight()+2;this.plotOffset.bottom+=b;a.tabsContainer.setStyle({top:this.canvasHeight-b+"px"});a.tabs.graph.observe("click",function(){a.showTab("graph")});a.tabs.data.observe("click",function(){a.showTab("data")})}},constructDataGrid:function(){if(this.spreadsheet.datagrid){return this.spreadsheet.datagrid}var d,b,n=this.series,l=this.loadDataGrid(),m=this.spreadsheet.datagrid=new Element("table").addClassName("flotr-datagrid"),c=["<colgroup><col />"];var f=['<tr class="first-row">'];f.push("<th>&nbsp;</th>");for(d=0;d<n.length;++d){f.push('<th scope="col">'+(n[d].label||String.fromCharCode(65+d))+"</th>");c.push("<col />")}f.push("</tr>");for(b=0;b<l.length;++b){f.push("<tr>");for(d=0;d<n.length+1;++d){var o="td",g=(l[b][d]!=null?Math.round(l[b][d]*100000)/100000:"");if(d==0){o="th";var k;if(this.options.xaxis.ticks){var e=this.options.xaxis.ticks.find(function(j){return j[0]==l[b][d]});if(e){k=e[1]}}else{if(this.options.spreadsheet.tickFormatter){k=this.options.spreadsheet.tickFormatter(g)}else{k=this.options.xaxis.tickFormatter(g)}}if(k){g=k}}f.push("<"+o+(o=="th"?' scope="row"':"")+">"+g+"</"+o+">")}f.push("</tr>")}c.push("</colgroup>");m.update(c.join("")+f.join(""));if(!Prototype.Browser.IE||Flotr.isIE9){m.select("td").each(function(j){j.observe("mouseover",function(q){j=q.element();var r=j.previousSiblings();m.select("th[scope=col]")[r.length-1].addClassName("hover");m.select("colgroup col")[r.length].addClassName("hover")}).observe("mouseout",function(){m.select("colgroup col.hover, th.hover").invoke("removeClassName","hover")})})}var h=new Element("div").addClassName("flotr-datagrid-toolbar").insert(new Element("button",{type:"button"}).addClassName("flotr-datagrid-toolbar-button").update(this.options.spreadsheet.toolbarDownload).observe("click",this.spreadsheet.downloadCSV.bindAsEventListener(this))).insert(new Element("button",{type:"button"}).addClassName("flotr-datagrid-toolbar-button").update(this.options.spreadsheet.toolbarSelectAll).observe("click",this.spreadsheet.selectAllData.bindAsEventListener(this)));var a=new Element("div",{style:"left:0px;top:0px;width:"+this.canvasWidth+"px;height:"+(this.canvasHeight-this.spreadsheet.tabsContainer.getHeight()-2)+"px;overflow:auto;"}).addClassName("flotr-datagrid-container");a.insert(h);m.wrap(a.hide());this.el.insert(a);return m},showTab:function(b){var a="canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle";switch(b){case"graph":if(this.spreadsheet.datagrid){this.spreadsheet.datagrid.up().hide()}this.el.select(a).invoke("show");this.spreadsheet.tabs.data.removeClassName("selected");this.spreadsheet.tabs.graph.addClassName("selected");break;case"data":this.spreadsheet.constructDataGrid();this.spreadsheet.datagrid.up().show();this.el.select(a).invoke("hide");this.spreadsheet.tabs.data.addClassName("selected");this.spreadsheet.tabs.graph.removeClassName("selected");break}},selectAllData:function(){if(this.spreadsheet.tabs){var b,a,e,d,c=this.spreadsheet.constructDataGrid();this.spreadsheet.showTab("data");setTimeout(function(){if((e=c.ownerDocument)&&(d=e.defaultView)&&d.getSelection&&e.createRange&&(b=window.getSelection())&&b.removeAllRanges){a=e.createRange();a.selectNode(c);b.removeAllRanges();b.addRange(a)}else{if(document.body&&document.body.createTextRange&&(a=document.body.createTextRange())){a.moveToElementText(c);a.select()}}},0);return true}else{return false}},downloadCSV:function(){var b,a="",c=this.series,j=this.options,f=this.loadDataGrid(),d=encodeURIComponent(j.spreadsheet.csvFileSeparator);if(j.spreadsheet.decimalSeparator===j.spreadsheet.csvFileSeparator){throw"The decimal separator is the same as the column separator ("+j.spreadsheet.decimalSeparator+")"}for(b=0;b<c.length;++b){a+=d+'"'+(c[b].label||String.fromCharCode(65+b)).replace(/\"/g,'\\"')+'"'}a+="%0D%0A";for(b=0;b<f.length;++b){var h="";if(j.xaxis.ticks){var e=j.xaxis.ticks.find(function(k){return k[0]==f[b][0]});if(e){h=e[1]}}else{if(j.spreadsheet.tickFormatter){h=j.spreadsheet.tickFormatter(f[b][0])}else{h=j.xaxis.tickFormatter(f[b][0])}}h='"'+(h+"").replace(/\"/g,'\\"')+'"';var g=f[b].slice(1).join(d);if(j.spreadsheet.decimalSeparator!=="."){g=g.replace(/\./g,j.spreadsheet.decimalSeparator)}a+=h+d+g+"%0D%0A"}if(Prototype.Browser.IE&&!Flotr.isIE9){a=a.replace(new RegExp(d,"g"),decodeURIComponent(d)).replace(/%0A/g,"\n").replace(/%0D/g,"\r");window.open().document.write(a)}else{window.open("data:text/csv,"+a)}}});Flotr.addType("gantt",{options:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,centered:true},draw:function(c){var a=this.ctx,e=c.gantt.barWidth,d=Math.min(c.gantt.lineWidth,e);a.save();a.translate(this.plotOffset.left,this.plotOffset.top);a.lineJoin="miter";a.lineWidth=d;a.strokeStyle=c.color;a.save();this.gantt.plotShadows(c,e,0,c.gantt.fill);a.restore();if(c.gantt.fill){var b=c.gantt.fillColor||c.color;a.fillStyle=this.processColor(b,{opacity:c.gantt.fillOpacity})}this.gantt.plot(c,e,0,c.gantt.fill);a.restore()},plot:function(j,n,e,q){var w=j.data;if(w.length<1){return}var t=j.xaxis,b=j.yaxis,o=this.ctx,r;for(r=0;r<w.length;r++){var h=w[r][0],l=w[r][1],u=w[r][2],f=true,k=true,a=true;if(l===null||u===null){continue}var c=l,v=l+u,g=h-(j.gantt.centered?n/2:0),m=h+n-(j.gantt.centered?n/2:0);if(v<t.min||c>t.max||m<b.min||g>b.max){continue}if(c<t.min){c=t.min;f=false}if(v>t.max){v=t.max;if(t.lastSerie!=j){k=false}}if(g<b.min){g=b.min}if(m>b.max){m=b.max;if(b.lastSerie!=j){k=false}}if(q){o.beginPath();o.moveTo(t.d2p(c),b.d2p(g)+e);o.lineTo(t.d2p(c),b.d2p(m)+e);o.lineTo(t.d2p(v),b.d2p(m)+e);o.lineTo(t.d2p(v),b.d2p(g)+e);o.fill();o.closePath()}if(j.gantt.lineWidth!=0&&(f||a||k)){o.beginPath();o.moveTo(t.d2p(c),b.d2p(g)+e);o[f?"lineTo":"moveTo"](t.d2p(c),b.d2p(m)+e);o[k?"lineTo":"moveTo"](t.d2p(v),b.d2p(m)+e);o[a?"lineTo":"moveTo"](t.d2p(v),b.d2p(g)+e);o.stroke();o.closePath()}}},plotShadows:function(g,j,c){var v=g.data;if(v.length<1){return}var q,f,h,t,r=g.xaxis,a=g.yaxis,o=this.ctx,m=this.options.shadowSize;for(q=0;q<v.length;q++){f=v[q][0];h=v[q][1];t=v[q][2];if(h===null||t===null){continue}var b=h,u=h+t,e=f-(g.gantt.centered?j/2:0),k=f+j-(g.gantt.centered?j/2:0);if(u<r.min||b>r.max||k<a.min||e>a.max){continue}if(b<r.min){b=r.min}if(u>r.max){u=r.max}if(e<a.min){e=a.min}if(k>a.max){k=a.max}var n=r.d2p(u)-r.d2p(b)-((r.d2p(u)+m<=this.plotWidth)?0:m);var l=a.d2p(e)-a.d2p(k)-((a.d2p(e)+m<=this.plotHeight)?0:m);o.fillStyle="rgba(0,0,0,0.05)";o.fillRect(Math.min(r.d2p(b)+m,this.plotWidth),Math.min(a.d2p(k)+m,this.plotHeight),n,l)}},extendXRange:function(b){if(b.options.max==null){var c=b.min,k=b.max,e,d,m,n,h,a={},l={},f=null;for(e=0;e<this.series.length;++e){n=this.series[e];h=n.gantt;if(h.show&&n.xaxis==b){for(d=0;d<n.data.length;d++){if(h.show){y=n.data[d][0]+"";a[y]=Math.max((a[y]||0),n.data[d][1]+n.data[d][2]);f=n}}for(d in a){k=Math.max(a[d],k)}}}b.lastSerie=f;b.max=k;b.min=c}},extendYRange:function(b){if(b.options.max==null){var l=Number.MIN_VALUE,d=Number.MAX_VALUE,f,e,o,k,a={},m={},h=null;for(f=0;f<this.series.length;++f){o=this.series[f];k=o.gantt;if(k.show&&!o.hide&&o.yaxis==b){var c=Number.MIN_VALUE,n=Number.MAX_VALUE;for(e=0;e<o.data.length;e++){c=Math.max(c,o.data[e][0]);n=Math.min(n,o.data[e][0])}if(k.centered){l=Math.max(c+0.5,l);d=Math.min(n-0.5,d)}else{l=Math.max(c+1,l);d=Math.min(n,d)}if(k.barWidth+c>l){l=b.max+k.barWidth}}}b.lastSerie=h;b.max=l;b.min=d;b.tickSize=Flotr.getTickSize(b.options.noTicks,d,l,b.options.tickDecimals)}}});
66 flotr/flotr.css
@@ -0,0 +1,66 @@
+
+.flotr-datagrid-container {
+ border: 1px solid #999;
+ border-bottom: none;
+ background: #fff;
+}
+.flotr-datagrid {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.flotr-datagrid td, .flotr-datagrid th {
+ border: 1px solid #ccc;
+ padding: 1px 3px;
+ min-width: 2em;
+}
+.flotr-datagrid tr:hover, .flotr-datagrid col.hover {
+ background: #f3f3f3;
+}
+.flotr-datagrid tr:hover th, .flotr-datagrid th.hover {
+ background: #999;
+ color: #fff;
+}
+.flotr-datagrid th {
+ text-align: left;
+ background: #e3e3e3;
+ border: 2px outset #fff;
+}
+.flotr-datagrid-toolbar {
+ padding: 1px;
+ border-bottom: 1px solid #ccc;
+ background: #f9f9f9;
+}
+.flotr-datagrid td:hover {
+ background: #ccc;
+}
+.flotr-datagrid .first-row th {
+ text-align: center;
+}
+.flotr-canvas {
+ margin-bottom: -3px;
+ padding-bottom: 1px;
+}
+.flotr-tabs-group {
+ border-top: 1px solid #999;
+}
+.flotr-tab {
+ border: 1px solid #666;
+ border-top: none;
+ margin: 0 3px;
+ padding: 1px 4px;
+ cursor: pointer;
+ -moz-border-radius: 0 0 4px 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ border-radius: 0 0 4px 4px;
+ opacity: 0.5;
+ -moz-opacity: 0.5;
+}
+.flotr-tab.selected {
+ background: #ddd;
+ opacity: 1;
+ -moz-opacity: 1;
+}
+.flotr-tab:hover {
+ background: #ccc;
+}
4,807 flotr/flotr.js
4,807 additions, 0 deletions not shown
113 flotr/lib/base64.js
@@ -0,0 +1,113 @@
+/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
+ * Version: 1.0
+ * LastModified: Dec 25 1999
+ * This library is free. You can redistribute it and/or modify it.
+ */
+
+/*
+ * Interfaces:
+ * b64 = base64encode(data);
+ * data = base64decode(b64);
+ */
+
+(function() {
+
+var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var base64DecodeChars = [
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1];
+
+function base64encode(str) {
+ var out, i, len;
+ var c1, c2, c3;
+
+ len = str.length;
+ i = 0;
+ out = "";
+ while(i < len) {
+ c1 = str.charCodeAt(i++) & 0xff;
+ if(i == len)
+ {
+ out += base64EncodeChars.charAt(c1 >> 2);
+ out += base64EncodeChars.charAt((c1 & 0x3) << 4);
+ out += "==";
+ break;
+ }
+ c2 = str.charCodeAt(i++);
+ if(i == len)
+ {
+ out += base64EncodeChars.charAt(c1 >> 2);
+ out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
+ out += base64EncodeChars.charAt((c2 & 0xF) << 2);
+ out += "=";
+ break;
+ }
+ c3 = str.charCodeAt(i++);
+ out += base64EncodeChars.charAt(c1 >> 2);
+ out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
+ out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
+ out += base64EncodeChars.charAt(c3 & 0x3F);
+ }
+ return out;
+}
+
+function base64decode(str) {
+ var c1, c2, c3, c4;
+ var i, len, out;
+
+ len = str.length;
+ i = 0;
+ out = "";
+ while(i < len) {
+ /* c1 */
+ do {
+ c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
+ } while(i < len && c1 == -1);
+ if(c1 == -1)
+ break;
+
+ /* c2 */
+ do {
+ c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
+ } while(i < len && c2 == -1);
+ if(c2 == -1)
+ break;
+
+ out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
+
+ /* c3 */
+ do {
+ c3 = str.charCodeAt(i++) & 0xff;
+ if(c3 == 61)
+ return out;
+ c3 = base64DecodeChars[c3];
+ } while(i < len && c3 == -1);
+ if(c3 == -1)
+ break;
+
+ out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
+
+ /* c4 */
+ do {
+ c4 = str.charCodeAt(i++) & 0xff;
+ if(c4 == 61)
+ return out;
+ c4 = base64DecodeChars[c4];
+ } while(i < len && c4 == -1);
+ if(c4 == -1)
+ break;
+ out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
+ }
+ return out;
+}
+
+if (!window.btoa) window.btoa = base64encode;
+if (!window.atob) window.atob = base64decode;
+
+})();
198 flotr/lib/canvas2image.js
@@ -0,0 +1,198 @@
+/*
+ * Canvas2Image v0.1
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
+ */
+
+var Canvas2Image = (function() {
+ // check if we have canvas support
+ var oCanvas = document.createElement("canvas"),
+ sc = String.fromCharCode,
+ strDownloadMime = "image/octet-stream",
+ bReplaceDownloadMime = false;
+
+ // no canvas, bail out.
+ if (!oCanvas.getContext) {
+ return {
+ saveAsBMP : function(){},
+ saveAsPNG : function(){},
+ saveAsJPEG : function(){}
+ }
+ }
+
+ var bHasImageData = !!(oCanvas.getContext("2d").getImageData),
+ bHasDataURL = !!(oCanvas.toDataURL),
+ bHasBase64 = !!(window.btoa);
+
+ // ok, we're good
+ var readCanvasData = function(oCanvas) {
+ var iWidth = parseInt(oCanvas.width),
+ iHeight = parseInt(oCanvas.height);
+ return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
+ }
+
+ // base64 encodes either a string or an array of charcodes
+ var encodeData = function(data) {
+ var i, aData, strData = "";
+
+ if (typeof data == "string") {
+ strData = data;
+ } else {
+ aData = data;
+ for (i = 0; i < aData.length; i++) {
+ strData += sc(aData[i]);
+ }
+ }
+ return btoa(strData);
+ }
+
+ // creates a base64 encoded string containing BMP data takes an imagedata object as argument
+ var createBMP = function(oData) {
+ var strHeader = '',
+ iWidth = oData.width,
+ iHeight = oData.height;
+
+ strHeader += 'BM';
+
+ var iFileSize = iWidth*iHeight*4 + 54; // total header size = 54 bytes
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
+ strHeader += sc(iFileSize % 256);
+
+ strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
+ strHeader += sc(40, 0, 0, 0); // info header size
+
+ var iImageWidth = iWidth;
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
+ strHeader += sc(iImageWidth % 256);
+
+ var iImageHeight = iHeight;
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
+ strHeader += sc(iImageHeight % 256);
+
+ strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
+ strHeader += sc(0, 0, 0, 0); // compression = none
+
+ var iDataSize = iWidth*iHeight*4;
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
+ strHeader += sc(iDataSize % 256);
+
+ strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
+
+ var aImgData = oData.data,
+ strPixelData = "",
+ c, x, y = iHeight,
+ iOffsetX, iOffsetY, strPixelRow;
+
+ do {
+ iOffsetY = iWidth*(y-1)*4;
+ strPixelRow = "";
+ for (x = 0; x < iWidth; x++) {
+ iOffsetX = 4*x;
+ strPixelRow += sc(
+ aImgData[iOffsetY + iOffsetX + 2], // B
+ aImgData[iOffsetY + iOffsetX + 1], // G
+ aImgData[iOffsetY + iOffsetX], // R
+ aImgData[iOffsetY + iOffsetX + 3] // A
+ );
+ }
+ strPixelData += strPixelRow;
+ } while (--y);
+
+ return encodeData(strHeader + strPixelData);
+ }
+
+ // sends the generated file to the client
+ var saveFile = function(strData) {
+ if (!window.open(strData)) {
+ document.location.href = strData;
+ }
+ }
+
+ var makeDataURI = function(strData, strMime) {
+ return "data:" + strMime + ";base64," + strData;
+ }
+
+ // generates a <img> object containing the imagedata
+ var makeImageObject = function(strSource) {
+ var oImgElement = document.createElement("img");
+ oImgElement.src = strSource;
+ return oImgElement;
+ }
+
+ var scaleCanvas = function(oCanvas, iWidth, iHeight) {
+ if (iWidth && iHeight) {
+ var oSaveCanvas = document.createElement("canvas");
+
+ oSaveCanvas.width = iWidth;
+ oSaveCanvas.height = iHeight;
+ oSaveCanvas.style.width = iWidth+"px";
+ oSaveCanvas.style.height = iHeight+"px";
+
+ var oSaveCtx = oSaveCanvas.getContext("2d");
+
+ oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
+
+ return oSaveCanvas;
+ }
+ return oCanvas;
+ }
+
+ return {
+ saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
+ if (!bHasDataURL) return false;
+
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
+ strMime = "image/png",
+ strData = oScaledCanvas.toDataURL(strMime);
+
+ if (bReturnImg) {
+ return makeImageObject(strData);
+ } else {
+ saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
+ }
+ return true;
+ },
+
+ saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
+ if (!bHasDataURL) return false;
+
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
+ strMime = "image/jpeg",
+ strData = oScaledCanvas.toDataURL(strMime);
+
+ // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
+ if (strData.indexOf(strMime) != 5) return false;
+
+ if (bReturnImg) {
+ return makeImageObject(strData);
+ } else {
+ saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
+ }
+ return true;
+ },
+
+ saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
+ if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
+
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
+ strMime = "image/bmp",
+ oData = readCanvasData(oScaledCanvas),
+ strImgData = createBMP(oData);
+
+ if (bReturnImg) {
+ return makeImageObject(makeDataURI(strImgData, strMime));
+ } else {
+ saveFile(makeDataURI(strImgData, strMime));
+ }
+ return true;
+ }
+ };
+})();
429 flotr/lib/canvastext.js
@@ -0,0 +1,429 @@
+/**
+ * This code is released to the public domain by Jim Studt, 2007.
+ * He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
+ * It as been modified by Fabien Ménager to handle font style like size, weight, color and rotation.
+ * A partial support for special characters has been added too.
+ */
+var CanvasText = {
+ /** The letters definition. It is a list of letters,
+ * with their width, and the coordinates of points compositing them.
+ * The syntax for the points is : [x, y], null value means "pen up"
+ */
+ letters: {
+ '\n':{ width: -1, points: [] },
+ ' ': { width: 10, points: [] },
+ '!': { width: 10, points: [[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '"': { width: 16, points: [[4,21],[4,14],null,[12,21],[12,14]] },
+ '#': { width: 21, points: [[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]] },
+ '$': { width: 20, points: [[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ '%': { width: 24, points: [[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
+ '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
+ '\'':{ width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
+ '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
+ ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
+ '*': { width: 16, points: [[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]] },
+ '+': { width: 26, points: [[13,18],[13,0],null,[4,9],[22,9]] },
+ ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '-': { width: 26, points: [[4,9],[22,9]] },
+ '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '/': { width: 22, points: [[20,25],[2,-7]] },
+ '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
+ '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
+ '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
+ '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '4': { width: 20, points: [[13,21],[3,7],[18,7],null,[13,21],[13,0]] },
+ '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
+ '7': { width: 20, points: [[17,21],[7,0],null,[3,21],[17,21]] },
+ '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
+ '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
+ ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '<': { width: 24, points: [[20,18],[4,9],[20,0]] },
+ '=': { width: 26, points: [[4,12],[22,12],null,[4,6],[22,6]] },
+ '>': { width: 24, points: [[4,18],[20,9],[4,0]] },
+ '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]] },
+ '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]] },
+ 'A': { width: 18, points: [[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]] },
+ 'B': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
+ 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
+ 'D': { width: 21, points: [[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
+ 'E': { width: 19, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]] },
+ 'F': { width: 18, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]] },
+ 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]] },
+ 'H': { width: 22, points: [[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]] },
+ 'I': { width: 8, points: [[4,21],[4,0]] },
+ 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
+ 'K': { width: 21, points: [[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]] },
+ 'L': { width: 17, points: [[4,21],[4,0],null,[4,0],[16,0]] },
+ 'M': { width: 24, points: [[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]] },
+ 'N': { width: 22, points: [[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]] },
+ 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
+ 'P': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
+ 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]] },
+ 'R': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]] },
+ 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ 'T': { width: 16, points: [[8,21],[8,0],null,[1,21],[15,21]] },
+ 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
+ 'V': { width: 18, points: [[1,21],[9,0],null,[17,21],[9,0]] },
+ 'W': { width: 24, points: [[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]] },
+ 'X': { width: 20, points: [[3,21],[17,0],null,[17,21],[3,0]] },
+ 'Y': { width: 18, points: [[1,21],[9,11],[9,0],null,[17,21],[9,11]] },
+ 'Z': { width: 20, points: [[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]] },
+ '[': { width: 14, points: [[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]] },
+ '\\':{ width: 14, points: [[0,21],[14,-3]] },
+ ']': { width: 14, points: [[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]] },
+ '^': { width: 14, points: [[3,10],[8,18],[13,10]] },
+ '_': { width: 16, points: [[0,-2],[16,-2]] },
+ '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
+ 'a': { width: 19, points: [[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'b': { width: 19, points: [[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'd': { width: 19, points: [[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]] },
+ 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'h': { width: 19, points: [[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]] },
+ 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
+ 'k': { width: 17, points: [[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]] },
+ 'l': { width: 8, points: [[4,21],[4,0]] },
+ 'm': { width: 30, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
+ 'n': { width: 19, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
+ 'p': { width: 19, points: [[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'q': { width: 19, points: [[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'r': { width: 13, points: [[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]] },
+ 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
+ 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]] },
+ 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]] },
+ 'v': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0]] },
+ 'w': { width: 22, points: [[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]] },
+ 'x': { width: 17, points: [[3,14],[14,0],null,[14,14],[3,0]] },
+ 'y': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
+ 'z': { width: 17, points: [[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]] },
+ '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
+ '|': { width: 8, points: [[4,25],[4,-7]] },
+ '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
+ '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] },
+
+ // Lower case Latin-1
+ 'à': { diacritic: '`', letter: 'a' },
+ 'á': { diacritic: '´', letter: 'a' },
+ 'â': { diacritic: '^', letter: 'a' },
+ 'ä': { diacritic: '¨', letter: 'a' },
+ 'ã': { diacritic: '~', letter: 'a' },
+
+ 'è': { diacritic: '`', letter: 'e' },
+ 'é': { diacritic: '´', letter: 'e' },
+ 'ê': { diacritic: '^', letter: 'e' },
+ 'ë': { diacritic: '¨', letter: 'e' },
+
+ 'ì': { diacritic: '`', letter: 'i' },
+ 'í': { diacritic: '´', letter: 'i' },
+ 'î': { diacritic: '^', letter: 'i' },
+ 'ï': { diacritic: '¨', letter: 'i' },
+
+ 'ò': { diacritic: '`', letter: 'o' },
+ 'ó': { diacritic: '´', letter: 'o' },
+ 'ô': { diacritic: '^', letter: 'o' },
+ 'ö': { diacritic: '¨', letter: 'o' },
+ 'õ': { diacritic: '~', letter: 'o' },
+
+ 'ù': { diacritic: '`', letter: 'u' },
+ 'ú': { diacritic: '´', letter: 'u' },
+ 'û': { diacritic: '^', letter: 'u' },
+ 'ü': { diacritic: '¨', letter: 'u' },
+
+ 'ý': { diacritic: '´', letter: 'y' },
+ 'ÿ': { diacritic: '¨', letter: 'y' },
+
+ 'ç': { diacritic: '¸', letter: 'c' },
+ 'ñ': { diacritic: '~', letter: 'n' },
+
+ // Upper case Latin-1
+ 'À': { diacritic: '`', letter: 'A' },
+ 'Á': { diacritic: '´', letter: 'A' },
+ 'Â': { diacritic: '^', letter: 'A' },
+ 'Ä': { diacritic: '¨', letter: 'A' },
+ 'Ã': { diacritic: '~', letter: 'A' },
+
+ 'È': { diacritic: '`', letter: 'E' },
+ 'É': { diacritic: '´', letter: 'E' },
+ 'Ê': { diacritic: '^', letter: 'E' },
+ 'Ë': { diacritic: '¨', letter: 'E' },
+
+ 'Ì': { diacritic: '`', letter: 'I' },
+ 'Í': { diacritic: '´', letter: 'I' },
+ 'Î': { diacritic: '^', letter: 'I' },
+ 'Ï': { diacritic: '¨', letter: 'I' },
+
+ 'Ò': { diacritic: '`', letter: 'O' },
+ 'Ó': { diacritic: '´', letter: 'O' },
+ 'Ô': { diacritic: '^', letter: 'O' },
+ 'Ö': { diacritic: '¨', letter: 'O' },
+ 'Õ': { diacritic: '~', letter: 'O' },
+
+ 'Ù': { diacritic: '`', letter: 'U' },
+ 'Ú': { diacritic: '´', letter: 'U' },
+ 'Û': { diacritic: '^', letter: 'U' },
+ 'Ü': { diacritic: '¨', letter: 'U' },
+
+ 'Ý': { diacritic: '´', letter: 'Y' },
+
+ 'Ç': { diacritic: '¸', letter: 'C' },
+ 'Ñ': { diacritic: '~', letter: 'N' }
+ },
+
+ specialchars: {
+ 'pi': { width: 19, points: [[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]] }
+ },
+
+ /** Diacritics, used to draw accentuated letters */
+ diacritics: {
+ '¸': { entity: 'cedil', points: [[6,-4],[4,-6],[2,-7],[1,-7]] },
+ '´': { entity: 'acute', points: [[8,19],[13,22]] },
+ '`': { entity: 'grave', points: [[7,22],[12,19]] },
+ '^': { entity: 'circ', points: [[5.5,19],[9.5,23],[12.5,19]] },
+ '¨': { entity: 'trema', points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[12,21],[13,20],[14,21],[13,22],[12,21]] },
+ '~': { entity: 'tilde', points: [[4,18],[7,22],[10,18],[13,22]] }
+ },
+
+ /** The default font styling */
+ style: {
+ size: 8, // font height in pixels
+ font: null, // not yet implemented
+ color: '#000000', // font color
+ weight: 1, // float, 1 for 'normal'
+ textAlign: 'left', // left, right, center
+ textBaseline: 'bottom', // top, middle, bottom
+ adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position
+ angle: 0, // in radians, anticlockwise
+ tracking: 1, // space between the letters, float, 1 for 'normal'
+ boundingBoxColor: '#ff0000', // color of the bounding box (null to hide), can be used for debug and font drawing
+ originPointColor: '#000000' // color of the bounding box (null to hide), can be used for debug and font drawing
+ },
+
+ debug: false,
+ _bufferLexemes: {},
+
+ extend: function(dest, src) {
+ for (var property in src) {
+ if (property in dest) continue;
+ dest[property] = src[property];
+ }
+ return dest;
+ },
+
+ /** Get the letter data corresponding to a char
+ * @param {String} ch - The char
+ */
+ letter: function(ch) {
+ return CanvasText.letters[ch];
+ },
+
+ parseLexemes: function(str) {
+ if (CanvasText._bufferLexemes[str])
+ return CanvasText._bufferLexemes[str];
+
+ var i, c, matches = str.match(/&[A-Za-z]{2,5};|\s|./g),
+ result = [], chars = [];
+
+ for (i = 0; i < matches.length; i++) {
+ c = matches[i];
+ if (c.length == 1)
+ chars.push(c);
+ else {
+ var entity = c.substring(1, c.length-1);
+ if (CanvasText.specialchars[entity])
+ chars.push(entity);
+ else
+ chars = chars.concat(c.toArray());
+ }
+ }
+ for (i = 0; i < chars.length; i++) {
+ c = chars[i];
+ if (c = CanvasText.letters[c] || CanvasText.specialchars[c]) result.push(c);
+ }
+ for (i = 0; i < result.length; i++) {
+ if (result === null || typeof result === 'undefined')
+ delete result[i];
+ }
+ return CanvasText._bufferLexemes[str] = result;
+ },
+
+ /** Get the font ascent for a given style
+ * @param {Object} style - The reference style
+ */
+ ascent: function(style) {
+ style = style || CanvasText.style;
+ return (style.size || CanvasText.style.size);
+ },
+
+ /** Get the font descent for a given style
+ * @param {Object} style - The reference style
+ * */
+ descent: function(style) {
+ style = style || CanvasText.style;
+ return 7.0*(style.size || CanvasText.style.size)/25.0;
+ },
+
+ /** Measure the text horizontal size
+ * @param {String} str - The text
+ * @param {Object} style - Text style
+ * */
+ measure: function(str, style) {
+ if (!str) return;
+ style = style || CanvasText.style;
+
+ var i, width, lexemes = CanvasText.parseLexemes(str),
+ total = 0;
+
+ for (i = lexemes.length-1; i > -1; --i) {
+ c = lexemes[i];
+ width = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width;
+ total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0;
+ }
+ return total;
+ },
+
+ getDimensions: function(str, style) {
+ style = style || CanvasText.style;
+
+ var width = CanvasText.measure(str, style),
+ height = style.size || CanvasText.style.size,
+ angle = style.angle || CanvasText.style.angle;
+
+ if (style.angle == 0) return {width: width, height: height};
+ return {
+ width: Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height),
+ height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height)
+ }
+ },
+
+ /** Draws serie of points at given coordinates
+ * @param {Canvas context} ctx - The canvas context
+ * @param {Array} points - The points to draw
+ * @param {Number} x - The X coordinate
+ * @param {Number} y - The Y coordinate
+ * @param {Number} mag - The scale
+ */
+ drawPoints: function (ctx, points, x, y, mag, offset) {
+ var i, a, penUp = true, needStroke = 0;
+ offset = offset || {x:0, y:0};
+
+ ctx.beginPath();
+ for (i = 0; i < points.length; i++) {
+ a = points[i];
+ if (!a) {
+ penUp = true;
+ continue;
+ }
+ if (penUp) {
+ ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
+ penUp = false;
+ }
+ else {
+ ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
+ }
+ }
+ ctx.stroke();
+ ctx.closePath();
+ },
+
+ /** Draws a text at given coordinates and with a given style
+ * @param {String} str - The text to draw
+ * @param {Number} xOrig - The X coordinate
+ * @param {Number} yOrig - The Y coordinate
+ * @param {Object} style - The font style
+ */
+ draw: function(str, xOrig, yOrig, style) {
+ if (!str) return;
+ CanvasText.extend(style, CanvasText.style);
+
+ var i, c, total = 0,
+ mag = style.size / 25.0,
+ x = 0, y = 0,
+ lexemes = CanvasText.parseLexemes(str),
+ offset = {x: 0, y: 0},
+ measure = CanvasText.measure(str, style),
+ align;
+
+ if (style.adjustAlign) {
+ align = CanvasText.getBestAlign(style.angle, style);
+ CanvasText.extend(style, align);
+ }
+
+ switch (style.textAlign) {
+ case 'left': break;
+ case 'center': offset.x = -measure / 2; break;
+ case 'right': offset.x = -measure; break;
+ }
+
+ switch (style.textBaseline) {
+ case 'bottom': break;
+ case 'middle': offset.y = style.size / 2; break;
+ case 'top': offset.y = style.size; break;
+ }
+
+ this.save();
+ this.translate(xOrig, yOrig);
+ this.rotate(style.angle);
+ this.lineCap = "round";
+ this.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight);
+ this.strokeStyle = style.color || CanvasText.style.color;
+
+ for (i = 0; i < lexemes.length; i++) {
+ c = lexemes[i];
+ if (c.width == -1) {
+ x = 0;
+ y = style.size * 1.4;
+ continue;
+ }
+
+ var points = c.points,
+ width = c.width;
+
+ if (c.diacritic) {
+ var dia = CanvasText.diacritics[c.diacritic],
+ character = CanvasText.letter(c.letter);
+
+ CanvasText.drawPoints(this, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset);
+ points = character.points;
+ width = character.width;
+ }
+
+ CanvasText.drawPoints(this, points, x, y, mag, offset);
+
+ if (CanvasText.debug) {
+ this.save();
+ this.lineJoin = "miter";
+ this.lineWidth = 0.5;
+ this.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor);
+ this.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size);
+
+ this.fillStyle = (style.originPointColor || CanvasText.style.originPointColor);
+ this.beginPath();
+ this.arc(0, 0, 1.5, 0, Math.PI*2, true);
+ this.fill();
+ this.closePath();
+ this.restore();
+ }
+
+ x += width*mag*(style.tracking || CanvasText.style.tracking);
+ }
+ this.restore();
+ return total;
+ }
+};
+
+/** The text functions are bound to the CanvasRenderingContext2D prototype */
+CanvasText.proto = window.CanvasRenderingContext2D ? window.CanvasRenderingContext2D.prototype : document.createElement('canvas').getContext('2d').__proto__;
+
+if (CanvasText.proto) {
+ CanvasText.proto.drawText = CanvasText.draw;
+ CanvasText.proto.measure = CanvasText.measure;
+ CanvasText.proto.getTextBounds = CanvasText.getDimensions;
+ CanvasText.proto.fontAscent = CanvasText.ascent;
+ CanvasText.proto.fontDescent = CanvasText.descent;
+}
1,425 flotr/lib/excanvas.js
@@ -0,0 +1,1425 @@
+// Copyright 2006 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// Known Issues:
+//
+// * Patterns only support repeat.
+// * Radial gradient are not implemented. The VML version of these look very
+// different from the canvas one.
+// * Clipping paths are not implemented.
+// * Coordsize. The width and height attribute have higher priority than the
+// width and height style values which isn't correct.
+// * Painting mode isn't implemented.
+// * Canvas width/height should is using content-box by default. IE in
+// Quirks mode will draw the canvas using border-box. Either change your
+// doctype to HTML5
+// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
+// or use Box Sizing Behavior from WebFX
+// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
+// * Non uniform scaling does not correctly scale strokes.
+// * Optimize. There is always room for speed improvements.
+
+// Only add this code if we do not already have a canvas implementation
+if (!document.createElement('canvas').getContext) {
+
+(function() {
+
+ // alias some functions to make (compiled) code shorter
+ var m = Math;
+ var mr = m.round;
+ var ms = m.sin;
+ var mc = m.cos;
+ var abs = m.abs;
+ var sqrt = m.sqrt;
+
+ // this is used for sub pixel precision
+ var Z = 10;
+ var Z2 = Z / 2;
+
+ var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
+
+ /**
+ * This funtion is assigned to the <canvas> elements as element.getContext().
+ * @this {HTMLElement}
+ * @return {CanvasRenderingContext2D_}
+ */
+ function getContext() {
+ return this.context_ ||
+ (this.context_ = new CanvasRenderingContext2D_(this));
+ }
+
+ var slice = Array.prototype.slice;
+
+ /**
+ * Binds a function to an object. The returned function will always use the
+ * passed in {@code obj} as {@code this}.
+ *
+ * Example:
+ *
+ * g = bind(f, obj, a, b)
+ * g(c, d) // will do f.call(obj, a, b, c, d)
+ *
+ * @param {Function} f The function to bind the object to
+ * @param {Object} obj The object that should act as this when the function
+ * is called
+ * @param {*} var_args Rest arguments that will be used as the initial
+ * arguments when the function is called
+ * @return {Function} A new function that has bound this
+ */
+ function bind(f, obj, var_args) {
+ var a = slice.call(arguments, 2);
+ return function() {
+ return f.apply(obj, a.concat(slice.call(arguments)));
+ };
+ }
+
+ function encodeHtmlAttribute(s) {
+ return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+ }
+
+ function addNamespace(doc, prefix, urn) {
+ if (!doc.namespaces[prefix]) {
+ doc.namespaces.add(prefix, urn, '#default#VML');
+ }
+ }
+
+ function addNamespacesAndStylesheet(doc) {
+ addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
+ addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
+
+ // Setup default CSS. Only add one style sheet per document
+ if (!doc.styleSheets['ex_canvas_']) {
+ var ss = doc.createStyleSheet();
+ ss.owningElement.id = 'ex_canvas_';
+ ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
+ // default size is 300x150 in Gecko and Opera
+ 'text-align:left;width:300px;height:150px}';
+ }
+ }
+
+ // Add namespaces and stylesheet at startup.
+ addNamespacesAndStylesheet(document);
+
+ var G_vmlCanvasManager_ = {
+ init: function(opt_doc) {
+ var doc = opt_doc || document;
+ // Create a dummy element so that IE will allow canvas elements to be
+ // recognized.
+ doc.createElement('canvas');
+ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
+ },
+
+ init_: function(doc) {
+ // find all canvas elements
+ var els = doc.getElementsByTagName('canvas');
+ for (var i = 0; i < els.length; i++) {
+ this.initElement(els[i]);
+ }
+ },
+
+ /**
+ * Public initializes a canvas element so that it can be used as canvas
+ * element from now on. This is called automatically before the page is
+ * loaded but if you are creating elements using createElement you need to
+ * make sure this is called on the element.
+ * @param {HTMLElement} el The canvas element to initialize.
+ * @return {HTMLElement} the element that was created.
+ */
+ initElement: function(el) {
+ if (!el.getContext) {
+ el.getContext = getContext;
+
+ // Add namespaces and stylesheet to document of the element.
+ addNamespacesAndStylesheet(el.ownerDocument);
+
+ // Remove fallback content. There is no way to hide text nodes so we
+ // just remove all childNodes. We could hide all elements and remove
+ // text nodes but who really cares about the fallback content.
+ el.innerHTML = '';
+
+ // do not use inline function because that will leak memory
+ el.attachEvent('onpropertychange', onPropertyChange);
+ el.attachEvent('onresize', onResize);
+
+ var attrs = el.attributes;
+ if (attrs.width && attrs.width.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setWidth_(attrs.width.nodeValue);
+ el.style.width = attrs.width.nodeValue + 'px';
+ } else {
+ el.width = el.clientWidth;
+ }
+ if (attrs.height && attrs.height.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setHeight_(attrs.height.nodeValue);
+ el.style.height = attrs.height.nodeValue + 'px';
+ } else {
+ el.height = el.clientHeight;
+ }
+ //el.getContext().setCoordsize_()
+ }
+ return el;
+ }
+ };
+
+ function onPropertyChange(e) {
+ var el = e.srcElement;
+
+ switch (e.propertyName) {
+ case 'width':
+ el.getContext().clearRect();
+ el.style.width = el.attributes.width.nodeValue + 'px';
+ // In IE8 this does not trigger onresize.
+ if (el.firstChild) {
+ el.firstChild.style.width = el.clientWidth + 'px';
+ }
+ break;
+ case 'height':
+ el.getContext().clearRect();
+ el.style.height = el.attributes.height.nodeValue + 'px';
+ if (el.firstChild) {
+ el.firstChild.style.height = el.clientHeight + 'px';
+ }
+ break;
+ }
+ }
+
+ function onResize(e) {
+ var el = e.srcElement;
+ if (el.firstChild) {
+ el.firstChild.style.width = el.clientWidth + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ }
+ }
+
+ G_vmlCanvasManager_.init();
+
+ // precompute "00" to "FF"
+ var decToHex = [];
+ for (var i = 0; i < 16; i++) {
+ for (var j = 0; j < 16; j++) {
+ decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
+ }
+ }
+
+ function createMatrixIdentity() {
+ return [
+ [1, 0, 0],
+ [0, 1, 0],
+ [0, 0, 1]
+ ];
+ }
+
+ function matrixMultiply(m1, m2) {
+ var result = createMatrixIdentity();
+
+ for (var x = 0; x < 3; x++) {
+ for (var y = 0; y < 3; y++) {
+ var sum = 0;
+
+ for (var z = 0; z < 3; z++) {
+ sum += m1[x][z] * m2[z][y];
+ }
+
+ result[x][y] = sum;
+ }
+ }
+ return result;
+ }
+
+ function copyState(o1, o2) {
+ o2.fillStyle = o1.fillStyle;
+ o2.lineCap = o1.lineCap;
+ o2.lineJoin = o1.lineJoin;
+ o2.lineWidth = o1.lineWidth;
+ o2.miterLimit = o1.miterLimit;
+ o2.shadowBlur = o1.shadowBlur;
+ o2.shadowColor = o1.shadowColor;
+ o2.shadowOffsetX = o1.shadowOffsetX;
+ o2.shadowOffsetY = o1.shadowOffsetY;
+ o2.strokeStyle = o1.strokeStyle;
+ o2.globalAlpha = o1.globalAlpha;
+ o2.font = o1.font;
+ o2.textAlign = o1.textAlign;
+ o2.textBaseline = o1.textBaseline;
+ o2.arcScaleX_ = o1.arcScaleX_;
+ o2.arcScaleY_ = o1.arcScaleY_;
+ o2.lineScale_ = o1.lineScale_;
+ }
+
+ var colorData = {
+ 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 getRgbHslContent(styleString) {
+ var start = styleString.indexOf('(', 3);
+ var end = styleString.indexOf(')', start + 1);
+ var parts = styleString.substring(start + 1, end).split(',');
+ // add alpha if needed
+ if (parts.length != 4 || styleString.charAt(3) != 'a') {
+ parts[3] = 1;
+ }
+ return parts;
+ }
+
+ function percent(s) {
+ return parseFloat(s) / 100;
+ }
+
+ function clamp(v, min, max) {
+ return Math.min(max, Math.max(min, v));
+ }
+
+ function hslToRgb(parts){
+ var r, g, b, h, s, l;
+ h = parseFloat(parts[0]) / 360 % 360;
+ if (h < 0)
+ h++;
+ s = clamp(percent(parts[1]), 0, 1);
+ l = clamp(percent(parts[2]), 0, 1);
+ if (s == 0) {
+ r = g = b = l; // achromatic
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hueToRgb(p, q, h + 1 / 3);
+ g = hueToRgb(p, q, h);
+ b = hueToRgb(p, q, h - 1 / 3);
+ }
+
+ return '#' + decToHex[Math.floor(r * 255)] +
+ decToHex[Math.floor(g * 255)] +
+ decToHex[Math.floor(b * 255)];
+ }
+
+ function hueToRgb(m1, m2, h) {
+ if (h < 0)
+ h++;
+ if (h > 1)
+ h--;
+
+ if (6 * h < 1)
+ return m1 + (m2 - m1) * 6 * h;
+ else if (2 * h < 1)
+ return m2;
+ else if (3 * h < 2)
+ return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+ else
+ return m1;
+ }
+
+ var processStyleCache = {};
+
+ function processStyle(styleString) {
+ if (styleString in processStyleCache) {
+ return processStyleCache[styleString];
+ }
+
+ var str, alpha = 1;
+
+ styleString = String(styleString);
+ if (styleString.charAt(0) == '#') {
+ str = styleString;
+ } else if (/^rgb/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ var str = '#', n;
+ for (var i = 0; i < 3; i++) {
+ if (parts[i].indexOf('%') != -1) {
+ n = Math.floor(percent(parts[i]) * 255);
+ } else {
+ n = +parts[i];
+ }
+ str += decToHex[clamp(n, 0, 255)];
+ }
+ alpha = +parts[3];
+ } else if (/^hsl/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ str = hslToRgb(parts);
+ alpha = parts[3];
+ } else {
+ str = colorData[styleString] || styleString;
+ }
+ return processStyleCache[styleString] = {color: str, alpha: alpha};
+ }
+
+ var DEFAULT_STYLE = {
+ style: 'normal',
+ variant: 'normal',
+ weight: 'normal',
+ size: 10,
+ family: 'sans-serif'
+ };
+
+ // Internal text style cache
+ var fontStyleCache = {};
+
+ function processFontStyle(styleString) {
+ if (fontStyleCache[styleString]) {
+ return fontStyleCache[styleString];
+ }
+
+ var el = document.createElement('div');
+ var style = el.style;
+ try {
+ style.font = styleString;
+ } catch (ex) {
+ // Ignore failures to set to invalid font.
+ }
+
+ return fontStyleCache[styleString] = {
+ style: style.fontStyle || DEFAULT_STYLE.style,
+ variant: style.fontVariant || DEFAULT_STYLE.variant,
+ weight: style.fontWeight || DEFAULT_STYLE.weight,
+ size: style.fontSize || DEFAULT_STYLE.size,
+ family: style.fontFamily || DEFAULT_STYLE.family
+ };
+ }
+
+ function getComputedStyle(style, element) {
+ var computedStyle = {};
+
+ for (var p in style) {
+ computedStyle[p] = style[p];
+ }
+
+ // Compute the size
+ var canvasFontSize = parseFloat(element.currentStyle.fontSize),
+ fontSize = parseFloat(style.size);
+
+ if (typeof style.size == 'number') {
+ computedStyle.size = style.size;
+ } else if (style.size.indexOf('px') != -1) {
+ computedStyle.size = fontSize;
+ } else if (style.size.indexOf('em') != -1) {
+ computedStyle.size = canvasFontSize * fontSize;
+ } else if(style.size.indexOf('%') != -1) {
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
+ } else if (style.size.indexOf('pt') != -1) {
+ computedStyle.size = fontSize / .75;
+ } else {
+ computedStyle.size = canvasFontSize;
+ }
+
+ // Different scaling between normal text and VML text. This was found using
+ // trial and error to get the same size as non VML text.
+ //computedStyle.size *= 0.981;
+
+ return computedStyle;
+ }
+
+ function buildStyle(style) {
+ return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
+ style.size + 'px ' + style.family;
+ }
+
+ var lineCapMap = {
+ 'butt': 'flat',
+ 'round': 'round'
+ };
+
+ function processLineCap(lineCap) {
+ return lineCapMap[lineCap] || 'square';
+ }
+
+ /**
+ * This class implements CanvasRenderingContext2D interface as described by
+ * the WHATWG.
+ * @param {HTMLElement} canvasElement The element that the 2D context should
+ * be associated with
+ */
+ function CanvasRenderingContext2D_(canvasElement) {
+ this.m_ = createMatrixIdentity();
+
+ this.mStack_ = [];
+ this.aStack_ = [];
+ this.currentPath_ = [];
+
+ // Canvas context properties
+ this.strokeStyle = '#000';
+ this.fillStyle = '#000';
+
+ this.lineWidth = 1;
+ this.lineJoin = 'miter';
+ this.lineCap = 'butt';
+ this.miterLimit = Z * 1;
+ this.globalAlpha = 1;
+ this.font = '10px sans-serif';
+ this.textAlign = 'left';
+ this.textBaseline = 'alphabetic';
+ this.canvas = canvasElement;
+
+ var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
+ canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
+ var el = canvasElement.ownerDocument.createElement('div');
+ el.style.cssText = cssText;
+ canvasElement.appendChild(el);
+
+ var overlayEl = el.cloneNode(false);
+ // Use a non transparent background.
+ overlayEl.style.backgroundColor = 'red';
+ overlayEl.style.filter = 'alpha(opacity=0)';
+ canvasElement.appendChild(overlayEl);
+
+ this.element_ = el;
+ this.arcScaleX_ = 1;
+ this.arcScaleY_ = 1;
+ this.lineScale_ = 1;
+ }
+
+ var contextPrototype = CanvasRenderingContext2D_.prototype;
+ contextPrototype.clearRect = function() {
+ if (this.textMeasureEl_) {
+ this.textMeasureEl_.removeNode(true);
+ this.textMeasureEl_ = null;
+ }
+ this.element_.innerHTML = '';
+ };
+
+ contextPrototype.beginPath = function() {
+ // TODO: Branch current matrix so that save/restore has no effect
+ // as per safari docs.
+ this.currentPath_ = [];
+ };
+
+ contextPrototype.moveTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.lineTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
+
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+ aCP2x, aCP2y,
+ aX, aY) {
+ var p = getCoords(this, aX, aY);
+ var cp1 = getCoords(this, aCP1x, aCP1y);
+ var cp2 = getCoords(this, aCP2x, aCP2y);
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ // Helper function that takes the already fixed cordinates.
+ function bezierCurveTo(self, cp1, cp2, p) {
+ self.currentPath_.push({
+ type: 'bezierCurveTo',
+ cp1x: cp1.x,
+ cp1y: cp1.y,
+ cp2x: cp2.x,
+ cp2y: cp2.y,
+ x: p.x,
+ y: p.y
+ });
+ self.currentX_ = p.x;
+ self.currentY_ = p.y;
+ }
+
+ contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
+ // the following is lifted almost directly from
+ // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
+
+ var cp = getCoords(this, aCPx, aCPy);
+ var p = getCoords(this, aX, aY);
+
+ var cp1 = {
+ x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
+ y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
+ };
+ var cp2 = {
+ x: cp1.x + (p.x - this.currentX_) / 3.0,
+ y: cp1.y + (p.y - this.currentY_) / 3.0
+ };
+
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ contextPrototype.arc = function(aX, aY, aRadius,
+ aStartAngle, aEndAngle, aClockwise) {
+ aRadius *= Z;
+ var arcType = aClockwise ? 'at' : 'wa';
+
+ var xStart = aX + mc(aStartAngle) * aRadius - Z2;
+ var yStart = aY + ms(aStartAngle) * aRadius - Z2;
+
+ var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
+ var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
+
+ // IE won't render arches drawn counter clockwise if xStart == xEnd.
+ if ((abs(xStart - xEnd) < 10e-8) && !aClockwise) {
+ xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
+ // that can be represented in binary
+ }
+ // IE won't render arches drawn clockwise if yStart is very close to yEnd.
+ if ((abs(yStart - yEnd) < 10e-8) && aClockwise) {
+ yStart -= 0.125; // Offset yStart by 1/80 of a pixel. Use something
+ // that can be represented in binary
+ }
+
+ var p = getCoords(this, aX, aY);
+ var pStart = getCoords(this, xStart, yStart);
+ var pEnd = getCoords(this, xEnd, yEnd);
+
+ this.currentPath_.push({type: arcType,
+ x: p.x,
+ y: p.y,
+ radius: aRadius,
+ xStart: pStart.x,
+ yStart: pStart.y,
+ xEnd: pEnd.x,
+ yEnd: pEnd.y});
+
+ };
+
+ contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ };
+
+ contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.stroke();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ this.beginPath();
+
+ this.moveTo(aX, aY);
+ this.lineTo(aX + aWidth, aY);
+ this.lineTo(aX + aWidth, aY + aHeight);
+ this.lineTo(aX, aY + aHeight);
+ this.closePath();
+ this.fill();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+ var gradient = new CanvasGradient_('gradient');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ return gradient;
+ };
+
+ contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
+ aX1, aY1, aR1) {
+ var gradient = new CanvasGradient_('gradientradial');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.r0_ = aR0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ gradient.r1_ = aR1;
+ return gradient;
+ };
+
+ contextPrototype.drawImage = function(image, var_args) {
+ var dx, dy, dw, dh, sx, sy, sw, sh;
+
+ // to find the original width we overide the width and height
+ var oldRuntimeWidth = image.runtimeStyle.width;
+ var oldRuntimeHeight = image.runtimeStyle.height;
+ image.runtimeStyle.width = 'auto';
+ image.runtimeStyle.height = 'auto';
+
+ // get the original size
+ var w = image.width;
+ var h = image.height;
+
+ // and remove overides
+ image.runtimeStyle.width = oldRuntimeWidth;
+ image.runtimeStyle.height = oldRuntimeHeight;
+
+ if (arguments.length == 3) {
+ dx = arguments[1];
+ dy = arguments[2];
+ sx = sy = 0;
+ sw = dw = w;
+ sh = dh = h;
+ } else if (arguments.length == 5) {
+ dx = arguments[1];
+ dy = arguments[2];
+ dw = arguments[3];
+ dh = arguments[4];
+ sx = sy = 0;
+ sw = w;
+ sh = h;
+ } else if (arguments.length == 9) {
+ sx = arguments[1];
+ sy = arguments[2];
+ sw = arguments[3];
+ sh = arguments[4];
+ dx = arguments[5];
+ dy = arguments[6];
+ dw = arguments[7];
+ dh = arguments[8];
+ } else {
+ throw Error('Invalid number of arguments');
+ }
+
+ var d = getCoords(this, dx, dy);
+
+ var w2 = sw / 2;
+ var h2 = sh / 2;
+
+ var vmlStr = [];
+
+ var W = 10;
+ var H = 10;
+
+ // For some reason that I've now forgotten, using divs didn't work
+ vmlStr.push(' <g_vml_:group',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' coordorigin="0,0"' ,
+ ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
+
+ // If filters are necessary (rotation exists), create them
+ // filters are bog-slow, so only create them if abbsolutely necessary
+ // The following check doesn't account for skews (which don't exist
+ // in the canvas spec (yet) anyway.
+
+ if (this.m_[0][0] != 1 || this.m_[0][1] ||
+ this.m_[1][1] != 1 || this.m_[1][0]) {
+ var filter = [];
+
+ // Note the 12/21 reversal
+ filter.push('M11=', this.m_[0][0], ',',
+ 'M12=', this.m_[1][0], ',',
+ 'M21=', this.m_[0][1], ',',
+ 'M22=', this.m_[1][1], ',',
+ 'Dx=', mr(d.x / Z), ',',
+ 'Dy=', mr(d.y / Z), '');
+
+ // Bounding box calculation (need to minimize displayed area so that
+ // filters don't waste time on unused pixels.
+ var max = d;
+ var c2 = getCoords(this, dx + dw, dy);
+ var c3 = getCoords(this, dx, dy + dh);
+ var c4 = getCoords(this, dx + dw, dy + dh);
+
+ max.x = m.max(max.x, c2.x, c3.x, c4.x);
+ max.y = m.max(max.y, c2.y, c3.y, c4.y);
+
+ vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
+ 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
+ filter.join(''), ", sizingmethod='clip');");
+
+ } else {
+ vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
+ }
+
+ vmlStr.push(' ">' ,
+ '<g_vml_:image src="', image.src, '"',
+ ' style="width:', Z * dw, 'px;',
+ ' height:', Z * dh, 'px"',
+ ' cropleft="', sx / w, '"',
+ ' croptop="', sy / h, '"',
+ ' cropright="', (w - sx - sw) / w, '"',
+ ' cropbottom="', (h - sy - sh) / h, '"',
+ ' />',
+ '</g_vml_:group>');
+
+ this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
+ };
+
+ contextPrototype.stroke = function(aFill) {
+ var lineStr = [];
+ var lineOpen = false;
+
+ var W = 10;
+ var H = 10;
+
+ lineStr.push('<g_vml_:shape',
+ ' filled="', !!aFill, '"',
+ ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
+ ' coordorigin="0,0"',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' stroked="', !aFill, '"',
+ ' path="');
+
+ var newSeq = false;
+ var min = {x: null, y: null};
+ var max = {x: null, y: null};
+
+ for (var i = 0; i < this.currentPath_.length; i++) {
+ var p = this.currentPath_[i];
+ var c;
+
+ switch (p.type) {
+ case 'moveTo':
+ c = p;
+ lineStr.push(' m ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'lineTo':
+ lineStr.push(' l ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'close':
+ lineStr.push(' x ');
+ p = null;
+ break;
+ case 'bezierCurveTo':
+ lineStr.push(' c ',
+ mr(p.cp1x), ',', mr(p.cp1y), ',',
+ mr(p.cp2x), ',', mr(p.cp2y), ',',
+ mr(p.x), ',', mr(p.y));
+ break;
+ case 'at':
+ case 'wa':
+ lineStr.push(' ', p.type, ' ',
+ mr(p.x - this.arcScaleX_ * p.radius), ',',
+ mr(p.y - this.arcScaleY_ * p.radius), ' ',
+ mr(p.x + this.arcScaleX_ * p.radius), ',',
+ mr(p.y + this.arcScaleY_ * p.radius), ' ',
+ mr(p.xStart), ',', mr(p.yStart), ' ',
+ mr(p.xEnd), ',', mr(p.yEnd));
+ break;
+ }
+
+
+ // TODO: Following is broken for curves due to
+ // move to proper paths.
+
+ // Figure out dimensions so we can do gradient fills
+ // properly
+ if (p) {
+ if (min.x == null || p.x < min.x) {
+ min.x = p.x;
+ }
+ if (max.x == null || p.x > max.x) {
+ max.x = p.x;
+ }
+ if (min.y == null || p.y < min.y) {
+ min.y = p.y;
+ }
+ if (max.y == null || p.y > max.y) {
+ max.y = p.y;
+ }
+ }
+ }
+ lineStr.push(' ">');
+
+ if (!aFill) {
+ appendStroke(this, lineStr);
+ } else {
+ appendFill(this, lineStr, min, max);
+ }
+
+ lineStr.push('</g_vml_:shape>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ function appendStroke(ctx, lineStr) {
+ var a = processStyle(ctx.strokeStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ var lineWidth = ctx.lineScale_ * ctx.lineWidth;
+
+ // VML cannot correctly render a line if the width is less than 1px.
+ // In that case, we dilute the color to make the line look thinner.
+ if (lineWidth < 1) {
+ opacity *= lineWidth;
+ }
+
+ lineStr.push(
+ '<g_vml_:stroke',
+ ' opacity="', opacity, '"',
+ ' joinstyle="', ctx.lineJoin, '"',
+ ' miterlimit="', ctx.miterLimit, '"',
+ ' endcap="', processLineCap(ctx.lineCap), '"',
+ ' weight="', lineWidth, 'px"',
+ ' color="', color, '" />'
+ );
+ }
+
+ function appendFill(ctx, lineStr, min, max) {
+ var fillStyle = ctx.fillStyle;
+ var arcScaleX = ctx.arcScaleX_;
+ var arcScaleY = ctx.arcScaleY_;
+ var width = max.x - min.x;
+ var height = max.y - min.y;
+ if (fillStyle instanceof CanvasGradient_) {
+ // TODO: Gradients transformed with the transformation matrix.
+ var angle = 0;
+ var focus = {x: 0, y: 0};
+
+ // additional offset
+ var shift = 0;
+ // scale factor for offset
+ var expansion = 1;
+
+ if (fillStyle.type_ == 'gradient') {
+ var x0 = fillStyle.x0_ / arcScaleX;
+ var y0 = fillStyle.y0_ / arcScaleY;
+ var x1 = fillStyle.x1_ / arcScaleX;
+ var y1 = fillStyle.y1_ / arcScaleY;
+ var p0 = getCoords(ctx, x0, y0);
+ var p1 = getCoords(ctx, x1, y1);
+ var dx = p1.x - p0.x;
+ var dy = p1.y - p0.y;
+ angle = Math.atan2(dx, dy) * 180 / Math.PI;
+
+ // The angle should be a non-negative number.
+ if (angle < 0) {
+ angle += 360;
+ }
+
+ // Very small angles produce an unexpected result because they are
+ // converted to a scientific notation string.
+ if (angle < 1e-6) {
+ angle = 0;
+ }
+ } else {
+ var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
+ focus = {
+ x: (p0.x - min.x) / width,
+ y: (p0.y - min.y) / height
+ };
+
+ width /= arcScaleX * Z;
+ height /= arcScaleY * Z;
+ var dimension = m.max(width, height);
+ shift = 2 * fillStyle.r0_ / dimension;
+ expansion = 2 * fillStyle.r1_ / dimension - shift;
+ }
+
+ // We need to sort the color stops in ascending order by offset,
+ // otherwise IE won't interpret it correctly.
+ var stops = fillStyle.colors_;
+ stops.sort(function(cs1, cs2) {
+ return cs1.offset - cs2.offset;
+ });
+
+ var length = stops.length;
+ var color1 = stops[0].color;
+ var color2 = stops[length - 1].color;
+ var opacity1 = stops[0].alpha * ctx.globalAlpha;
+ var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
+
+ var colors = [];
+ for (var i = 0; i < length; i++) {
+ var stop = stops[i];
+ colors.push(stop.offset * expansion + shift + ' ' + stop.color);
+ }
+
+ // When colors attribute is used, the meanings of opacity and o:opacity2
+ // are reversed.
+ lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
+ ' method="none" focus="100%"',
+ ' color="', color1, '"',
+ ' color2="', color2, '"',
+ ' colors="', colors.join(','), '"',
+ ' opacity="', opacity2, '"',
+ ' g_o_:opacity2="', opacity1, '"',
+ ' angle="', angle, '"',