moChart.js 12.19 KiB
;(function(){if(window.moChart && window.moChart.getPainter) return;
window.moChart={};(function(mc) {
Function.prototype.__setModel=function(){
var fn=this;var defaultValue=arguments[0];
return function(){for(var i in arguments){
custom=arguments[i];checkProperty(custom,defaultValue);}
return fn.apply(this,arguments);};};
function checkProperty(cus,def){
for(var i in def){
if(cus[i]==undefined) cus[i]=def[i];
else if(def[i] instanceof Object) {
if(cus[i] instanceof Array) checkArrayProperty(cus[i],def[i]);
else checkProperty(cus[i],def[i]);}}}
function checkArrayProperty(cusArr,def){
if(cusArr instanceof Array) for(var i in cusArr) checkArrayProperty(cusArr[i],def);
else checkProperty(cusArr,def);}
Function.prototype.__setDefault=function(){
var fn=this;var args=Array.prototype.slice.apply(arguments);
return function(){var arg=0; for(var i=0;i<args.length && arg<arguments.length;i++)
if(arguments[i]!=undefined) args[i]=arguments[i];
return fn.apply(this,args);};};
var accMath={accAdd:function(arg1,arg2){var r1=0;var r2=0;
try{r1=arg1.toString().split('.')[1].length;}catch(e){}
try{r2=arg2.toString().split('.')[1].length;}catch(e){}
var m=Math.pow(10,Math.max(r1,r2));
return (Math.round(arg1*m)+Math.round(arg2*m))/m;},
accSub:function(arg1,arg2){return accAdd(arg1,-arg2);},
accMul:function(arg1,arg2){var s1=arg1.toString();
var s2=arg2.toString();var m=0;
try{m+=s1.split('.')[1].length;}catch(e) {}
try{m+=s2.split('.')[1].length;}catch(e) {}
return (s1.replace('.','')-0)*(s2.replace('.','')-0)/Math.pow(10,m);},
accDiv:function(arg1,arg2){
var s1=arg1.toString();var s2=arg2.toString();var m=0;
try{m=s2.split('.')[1].length;}catch(e) {}
try{m-=s1.split('.')[1].length;}catch(e) {}
return (s1.replace('.','')-0)/(s2.replace('.','')-0)*Math.pow(10,m);}};
var centerTimer={tickTime:25,timerID:0,timerFn:[],isAnimate:false,
add:function(aFn,cFn){aFn.cancelFn=cFn;this.timerFn.push(aFn);},
start:function(){if(this.timerID) return; this.isAnimate=true;
(function runNext(){ if(centerTimer.timerFn.length>0){
for(var i=0;i<centerTimer.timerFn.length;i++)
if(centerTimer.timerFn[i](centerTimer.tickTime)===false){
centerTimer.timerFn.splice(i,1);i--;}
centerTimer.timerID=setTimeout(runNext,centerTimer.tickTime);
} else centerTimer.timerID=0;})();},
stop:function(){this.isAnimate=false;
clearTimeout(this.timerID);this.timerID=0;
for(var i in this.timerFn) if(this.timerFn[i].cancelFn) this.timerFn[i].cancelFn();
this.timerFn=[];}};
var AOP={before:function(){if(centerTimer.isAnimate) centerTimer.stop();},after:function(){}};
function Painter(container,requestClass){var canvas=container.canvas||document.createElement("canvas"),
context,painter=this; var __fontSize=24,__defaultColor="#888",__totalTime=1000;
function initCanvas(){ canvas.width=container.clientWidth*2;
canvas.height=container.clientHeight*2;canvas.style.width=container.clientWidth+"px";
canvas.style.height=container.clientHeight+"px";context=canvas.getContext("2d");}
initCanvas();if(!container.canvas){container.canvas=canvas;
container.appendChild(canvas);}else{container.removeChild(canvas);container.appendChild(canvas);}
function reset(isResize){if(isResize){clearTimeout(reset.id);reset.id=setTimeout(function(){
initCanvas();for(var i in requestClass){var tempClass=requestClass[i]+"Control";
eval("painter."+tempClass+".reDraw();");}},50);}else{context.clearRect(0,0,canvas.width,canvas.height);
for(var i in requestClass){var tempClass=requestClass[i]+"Control";
eval("painter."+tempClass+".reDraw();");}}}
try{for(var i in requestClass){var tempClass=requestClass[i]+"Control";
eval("this."+tempClass+"=new "+tempClass+";");}}catch(error){console.log(error);
throw new Error("mobileChart:Request class not exists:"+requestClass[i]);}
this.getContext=function(){return context;};this.reSize=reset.__setDefault(true);
var Grid=(function(ctx){var layout,width,height,yl,ma,mi,grid;
var leftX,rightX,bottomY,range,amount,axis,stepY,axisY;
function drawYLabel(){var x,stepValue,flag= 0,fullLength;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
ctx.beginPath();ctx.fillStyle=yl.fontColor; ctx.font=yl.fontSize+"px Sans";ctx.textBaseline="middle"; switch(yl.float){case "left": x=leftX-ctx.measureText(" ").width; fullLength=width*layout.d;ctx.textAlign="right";break; case "right": x=rightX+ctx.measureText(" ").width; fullLength=width*layout.b;ctx.textAlign="left";break;} if(mi>=0) {flag=4;}else if(ma<=0){flag=5;}else{stepValue=Math.max(ma,-mi)/2; if(ma>stepValue) flag+=1;if(-1*mi>stepValue) flag+=2;}amount=yl.split+1; switch(flag){case 1: amount=4;axis=1;break; case 2: amount=4;axis=2;break; case 3: if(amount%2!=1) amount++;axis=Math.floor(amount/2);break; case 4: axis=0;break; case 5: axis=amount-1;break;} stepValue=calcYValue(yl,flag);stepY=height/(amount-1);axisY=bottomY-axis*stepY;drawGrid(); for(var i=0;i<amount;i++) ctx.fillText(accMath.accAdd(mi,accMath.accMul(i,stepValue))+yl.mark,x,bottomY-i*stepY,fullLength);} function calcYValue(yl,flag){var step,temp;if(!yl.fitValue){ma=(Math.ceil(ma*100)/100).toFixed(2); mi=(Math.floor(mi*100)/100).toFixed(2);return ((ma-mi)/yl.split).toFixed(2);} switch(flag){case 1: temp=calcYHelper(ma,2);ma=temp[0],step=temp[1];mi=-1*step;break; case 2: temp=calcYHelper(-1*mi,2);mi=-1*temp[0];step=temp[1];ma=step;break; case 3: temp=Math.max(ma,-1*mi);step=Math.floor(amount/2);temp=calcYHelper(temp,step);ma=temp[0],step=temp[1];mi=-1*ma;break; case 4: temp=calcYHelper(ma,yl.split);ma=temp[0],step=temp[1];mi=0;break; case 5: temp=calcYHelper(-1*mi,yl.split);ma=0;mi=-1*temp[0],step=temp[1];break;}range=ma-mi;return step;} function calcYHelper(tmp,spl){var mul=1;if(tmp==0) tmp=1; while(Math.floor(tmp*mul)/mul==0) mul*=10; tmp=Math.ceil(tmp*mul);while(tmp%spl!=0) tmp++; var step=tmp/spl;return [tmp/mul,step/mul];} function drawGrid(){var gap=2,length=6,gridX,gridY;ctx.beginPath();ctx.strokeStyle="#ccc";ctx.lineWidth=1; switch(grid){case "dotted":for(var i=0;i<amount;i++){if(i==axis) continue; gridX=leftX;gridY=Math.round(bottomY-i*stepY); gridY=gridY%2==0 ? gridY:gridY+1; for(;gridX+length<rightX;gridX+=length+gap){ctx.moveTo(gridX,gridY);ctx.lineTo(gridX+length,gridY);} ctx.moveTo(gridX,gridY);ctx.lineTo(rightX,gridY);} break; case "solid":for(var i=0;i<amount;i++){if(i==axis) continue; gridY=Math.round(bottomY-i*stepY);gridY=gridY%2==0 ? gridY:gridY+1; ctx.moveTo(leftX,gridY);ctx.lineTo(rightX,gridY);} break; default: throw new Error("moChart:no such grid type supported:"+grid);break;} ctx.stroke();ctx.beginPath();ctx.strokeStyle="#444"; gridY=Math.round(bottomY-axis*stepY);gridY=gridY%2==0 ? gridY:gridY+1; ctx.moveTo(leftX,gridY);ctx.lineTo(rightX,gridY);ctx.stroke();} return {draw:function(la,wi,he,le,ri,bo,gr,yLabel,max,min){ layout=la;width=wi;height=he;leftX=le;rightX=ri;bottomY=bo; grid=gr;yl=yLabel;ma=max;mi=min;drawYLabel(); return [ma,mi,range,axisY];}};})(context); function lineControl(){var layout,animate,xLabel,yLabel,grid,items,customFn; var max,min,range; var width,height,topY,bottomY,leftX,rightX,axisY,amount; var x,y,stepX,totalTime,animateTimes,positionStep,position,previousX; function init(option){layout=option.layout;animate=option.animate; xLabel=option.xLabel;yLabel=option.yLabel;grid=option.grid; items=option.items;totalTime=option.totalTime;customFn=option.customFn;initValue();} function initValue(){width=canvas.width*(1-layout.b-layout.d); height=canvas.height*(1-layout.a-layout.c); topY=canvas.height*layout.a;bottomY=canvas.height*(1-layout.c); leftX=canvas.width*layout.d;rightX=canvas.width*(1-layout.b); max=min=items[0].value[0];var maxLength=1,tempMax,tempMin; for(var i in items){tempMax=yLabel.calcMax.apply(this,items[i].value); tempMin=yLabel.calcMin.apply(this,items[i].value); tempMax>max ? max=tempMax:"";tempMin<min ? min=tempMin:""; items[i].value.length>maxLength ? maxLength=items[i].value.length:"";} range=max-min;stepX=width/(maxLength-1);amount=maxLength;animateTimes=totalTime/centerTimer.tickTime; positionStep=Math.round(maxLength/animateTimes);positionStep=positionStep==0 ? 1:positionStep;position=0;drawReady();} function drawReady(){switch(animate){case "none": centerTimer.add(staticDraw);break; case "flow": centerTimer.add(animateFlowDraw,resetDraw);break; default:throw new Error("mobileChart:No such animate support:"+animate);}} function drawXLabel(ctx,xl){ctx.beginPath();ctx.fillStyle=xl.fontColor; ctx.font=xl.fontSize+"px Sans";ctx.textBaseline="top";ctx.textAlign="left";ctx.fillText(xl.start,leftX,bottomY+height/15);ctx.textAlign="right"; ctx.fillText(xl.end,rightX,bottomY+height/15);} function staticDraw(){drawXLabel(context,xLabel); var newValue=Grid.draw(layout,width,height,leftX,rightX,bottomY,grid,yLabel,max,min); max=newValue[0];min=newValue[1];range=newValue[2];axisY=newValue[3];
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
for(var i in items) (function(item){context.beginPath(); var data=item.value; context.strokeStyle=item.color;context.lineWidth=item.lineWidth || __lineWidth; x=leftX;y=(max-data[0])/range*height+topY;context.moveTo(x,y); for(var i=1;i<data.length;i++){x+=stepX;y=(max-data[i])/range*height+topY; context.lineTo(x,y);context.moveTo(x,y);}context.stroke(); if(item.gradient)(function(gra){context.beginPath();context.globalAlpha=gra.alpha; var tempMax=Math.max.apply(this,data.slice(gra.start,gra.end)); var gradient=context.createLinearGradient(leftX,(max-tempMax)/range*height+topY,leftX,bottomY); for(var i in gra.colorStop) gradient.addColorStop(i,gra.colorStop[i]); context.fillStyle=gradient;x=leftX+gra.start*stepX;y=bottomY; context.moveTo(x,y);for(i=gra.start;i<gra.end;i++){y=(max-data[i])/range*height+topY; context.lineTo(x,y);x+=stepX;} context.lineTo(x-stepX,bottomY);context.closePath();context.fill(); })(item.gradient);})(items[i]);return false;} function animateFlowDraw(){if(position==0){positionStep=1;drawXLabel(context,xLabel); var newValue=Grid.draw(layout,width,height,leftX,rightX,bottomY,grid,yLabel,max,min); max=newValue[0];min=newValue[1];range=newValue[2]; axisY=newValue[3];previousX=leftX;position++;} if(position<amount+1){for(var j in items)(function(item,tempPosition){ if(tempPosition<item.value.length)(function(data){x=leftX+tempPosition*stepX;y=(max-data[tempPosition-1])/range*height+topY; x=Math.round(x);if(item.gradient && tempPosition>item.gradient.start && tempPosition<item.gradient.end)(function(gra){ context.beginPath();context.globalAlpha=gra.alpha; var tempMax=Math.max.apply(this,data.slice(gra.start,gra.end)); var gradient=context.createLinearGradient(leftX,(max-tempMax)/range*height+topY,leftX,bottomY); for(var i in gra.colorStop) gradient.addColorStop(i,gra.colorStop[i]); context.fillStyle=gradient;context.moveTo(previousX,bottomY); context.lineTo(previousX,y);if((tempPosition+positionStep)<gra.end){ for(var i=0;i<positionStep;i++){context.lineTo(x,(max-data[tempPosition++])/range*height+topY);x+=stepX;} x-=stepX;context.lineTo(x,y);tempPosition-=positionStep;}else{ var left=gra.end-tempPosition; for(var i=0;i<left;i++){context.lineTo(x,(max-data[tempPosition++])/range*height+topY); x+=stepX;}x-=stepX;tempPosition-=left;}context.lineTo(x,bottomY);context.closePath();context.fill();})(item.gradient); context.beginPath();context.globalAlpha=1;context.strokeStyle=item.color; context.lineWidth=item.lineWidth || __lineWidth;context.moveTo(previousX,y); if((tempPosition+positionStep)<=data.length){for(var i=0;i<positionStep;i++){y=(max-data[tempPosition++])/range*height+topY; context.lineTo(x,y);x+=stepX;}x-=stepX;}else{for(var i=tempPosition;i<data.length;i++){ y=(max-data[tempPosition++])/range*height+topY;context.lineTo(x,y);x+=stepX;}} context.stroke();})(item.value);})(items[j],position);position+=positionStep;previousX=x;return true;}else return false;} function resetDraw(){initValue();staticDraw();} var defaultOption={layout:{a:0,b:0,c:0,d:0},animate:"none", xLabel:{fontColor:__defaultColor,fontSize:__fontSize,start:"",end:""}, yLabel:{fontColor:__defaultColor,fontSize:__fontSize,float:"left", calcMax:Math.max,calcMin:Math.min,mark:"",split:3,fitValue:true,}, grid:"dotted",items:{color:__defaultColor,lineWidth:2},totalTime:__totalTime,customFn:"function(){}"}; return {setOption:init.__setModel(defaultOption),reDraw:resetDraw};};} mc.getPainter=function(container,requestClass){return new Painter(container,requestClass);}; mc.draw=function(){centerTimer.start();}; mc.addTimerFn=function(animateFn,cancelFn){centerTimer.add(animateFn,cancelFn);}; mc.wrapEvent=function(fn){var bound=function(){AOP.before.apply(this); fn.apply(this,arguments);};return bound;};})(window.moChart);})();