当前位置: 移动技术网 > IT编程>开发语言>JavaScript > js封装成插件_Canvas统计图插件编写实例

js封装成插件_Canvas统计图插件编写实例

2017年12月12日  | 移动技术网IT编程  | 我要评论

之前就说过,我想写一个canvas画统计图的插件,现在写好了

先说下实现的功能吧:

  1.可以通过自定义x轴坐标属性和y轴坐标属性按比例画出统计图

  2.可以选择画折现图还是柱形统计图,或者两者都实现

  3.可以自由定义折现颜色,坐标颜色,柱形图颜色 和canvas边框颜色,当然边框你也可以选择要或者不要

  4.可以选择是否实现柱形图和折现图的动画实现

实现过程

画坐标——画箭头——做x轴和y轴的标注——画柱形图——画折现图

话不多说,上代码

(function(window,document){
 var chartdraws = function(options){
  if(!(this instanceof chartdraws))return new chartdraws(options);
  this.options = $.extend({
   //报表所需的参数
   "containerid" : "",  //canvas所在容器id
   "canvaswidth" : 400,
   "canvasheight" : 300,
   "paddingleft" : 20,
   "paddingtop" : 20,
   "columnchartdata" :[], //柱形图的数量和对应得名称以及百分比
   "ychartdata" :[],   //y轴的数量及名称
   "axiscolor" : "white",  //坐标轴颜色
   "columnchartcolor" : "#eee685", //柱形图颜色
   "isneedanimation" : true, //是否需要动画
   "isneedlinechart" : true, //是否需要折线图
   "isneedcolumnchart" : true, //是否需要柱形图
   "linechartcolor" : "#90ee90", //折线图颜色,当isneedlinechart=true时有效
   "isneedborder" : false,  //canvas是否需要外边框
   "bordercolor" : "white"  //外边框颜色
  },options);
  if(this.options.canvaswidth<=500)
  {
   this.axisborderwidth = 3;
   this.fontsize = 8;
  }
  else if(this.options.canvaswidth<=800){
   this.axisborderwidth = 4;
   this.fontsize = 12;
  }
  else{
   this.axisborderwidth = 5;
   this.fontsize = 16;
  }
  var self = this;
  _init();
  function _init(){
   var canvasdom = document.createelement("canvas");
   canvasdom.id = self.options.containerid+"_"+"canvas";
   canvasdom.width = self.options.canvaswidth;
   canvasdom.height = self.options.canvasheight;
   if(self.options.isneedborder){
    canvasdom.style.borderwidth = 1;
    canvasdom.style.borderstyle = "solid";
    canvasdom.style.bordercolor = self.options.bordercolor;
   }
   document.getelementbyid(self.options.containerid).appendchild(canvasdom);
   self.context = document.getelementbyid(self.options.containerid+"_"+"canvas");
   self.ctx = self.context.getcontext("2d");
   _drawaxis();
  }

  function _drawaxis(){
   var xydata =transformaxis( [{x:self.options.paddingleft,y:self.options.canvasheight-self.options.paddingtop},{x:self.options.paddingleft,y:self.options.paddingtop},{x:self.options.canvaswidth-self.options.paddingleft,y:self.options.paddingtop}]);
   self.ctx.strokestyle=self.options.axiscolor;
   drawline(self.ctx,xydata,self.axisborderwidth);
   //画三角箭头
   //画y轴三角箭头
   drawline(self.ctx,transformaxis([{x:self.options.paddingleft-self.axisborderwidth,y:self.options.canvasheight-self.options.paddingtop-self.axisborderwidth*2},{x:self.options.paddingleft,y:self.options.canvasheight-self.options.paddingtop},{x:self.options.paddingleft+self.axisborderwidth,y:self.options.canvasheight-self.options.paddingtop-self.axisborderwidth*2}]),self.axisborderwidth);
   //画x轴三角箭头
   drawline(self.ctx,transformaxis([{x:self.options.canvaswidth-self.options.paddingleft-self.axisborderwidth*2,y:self.options.paddingtop+self.axisborderwidth},{x:self.options.canvaswidth-self.options.paddingleft,y:self.options.paddingtop},{x:self.options.canvaswidth-self.options.paddingleft-self.axisborderwidth*2,y:self.options.paddingtop-self.axisborderwidth}]),self.axisborderwidth);
   _drawcoordinatepoints();
  }

  function _drawcoordinatepoints(){
   self.reactanglewidth = (1-2*0.04)*(self.options.canvaswidth-(2*self.options.paddingleft))/(self.options.columnchartdata.length*2-1);
   self.linedatalist = [];
   for(var i = 0;i<self.options.columnchartdata.length;i++)
   {
    drawxtext(self.ctx,2*self.options.columnchartdata[i].no*self.reactanglewidth+self.options.paddingleft+0.04*(self.options.canvaswidth-(2*self.options.paddingleft))+self.reactanglewidth/2,self.options.paddingtop/2,self.options.columnchartdata[i].name);
    self.linedatalist.push({
     x:2*self.options.columnchartdata[i].no*self.reactanglewidth+self.options.paddingleft+0.04*(self.options.canvaswidth-(2*self.options.paddingleft))+self.reactanglewidth/2,
     y:self.options.canvasheight-(self.options.paddingtop+(self.options.canvasheight-2*self.options.paddingtop)*self.options.columnchartdata[i].pt)
    })
   }

   //画y轴title 画y轴虚线
   self.reactangleheight = (self.options.canvasheight-2*self.options.paddingtop)/(self.options.ychartdata.length+1);
   for(var j = 0;j<self.options.ychartdata.length;j++)
   {
    drawytext(self.ctx,3*self.options.paddingleft/4,self.options.paddingtop+self.reactangleheight*(j+1),self.options.ychartdata[j].name);
    //画虚线
    drawdottedline(self.ctx,self.options.paddingleft,self.options.paddingtop+self.reactangleheight*(j+1),self.options.canvaswidth-self.options.paddingleft,self.options.paddingtop+self.reactangleheight*(j+1),self.options.canvaswidth-2*self.options.paddingleft,10,self.axisborderwidth/2);
   }
   _drawcolumnchart();
  }

  function _drawcolumnchart(){
   //柱形图循环
   var reactangletimer = 1;
   function loopcolumnchart()
   {
    var columnchartlooped = window.requestanimationframe(loopcolumnchart);
    if(reactangletimer<=100)
    {
     for(var k=0;k<self.options.columnchartdata.length;k++)
     {
      self.ctx.fillstyle =self.options.columnchartcolor;
      drawrectangle(self.ctx,self.linedatalist[k].x-self.reactanglewidth/2,self.options.canvasheight-((self.options.canvasheight-2*self.options.paddingtop)*self.options.columnchartdata[k].pt*reactangletimer/100+self.options.paddingtop),self.reactanglewidth,(self.options.canvasheight-2*self.options.paddingtop)*self.options.columnchartdata[k].pt*reactangletimer/100);
     }
     reactangletimer++;
    }
    else
    {
     window.cancelanimationframe(columnchartlooped);
     columnchartlooped = null;
     reactangletimer = 1;
     if(self.options.isneedlinechart)
     {
      looplinechart();
     }
    }
   }
   //折线图循环
   var linetimer = 0;
   function looplinechart()
   {
    var linechartlooped = window.requestanimationframe(looplinechart);
    if(linetimer<self.linedatalist.length-1)
    {
     self.ctx.linewidth = 2*self.axisborderwidth/3;
     if(linetimer == 0)
     {
      drawcircle(self.ctx,self.linedatalist[linetimer].x,self.linedatalist[linetimer].y);
     }
     drawcircle(self.ctx,self.linedatalist[linetimer+1].x,self.linedatalist[linetimer+1].y);
     self.ctx.beginpath();
     self.ctx.moveto(self.linedatalist[linetimer].x,self.linedatalist[linetimer].y);
     self.ctx.lineto(self.linedatalist[linetimer+1].x,self.linedatalist[linetimer+1].y);
     self.ctx.strokestyle = self.options.linechartcolor;
     self.ctx.linewidth = 2*self.axisborderwidth/3;
     self.ctx.stroke();
     linetimer++;
    }
    else
    {
     window.cancelanimationframe(linechartlooped);
     linechartlooped = null;
     linetimer = 0;
    }
   }
   //画柱形图
   function drawrectangle(context,x,y,width,height){
    context.beginpath();
    context.fillrect(x,y,width,height);
   }
   //画圆
   function drawcircle(context,x,y){
    context.beginpath();
    context.arc(x,y,self.axisborderwidth/2,0,2*math.pi,true);
    context.strokestyle=self.options.linechartcolor;
    context.stroke();
    context.closepath();
   }
   if(self.options.isneedanimation)
   {
    if(self.options.isneedcolumnchart)
    {
     loopcolumnchart();
    }
    else
    {
     if(self.options.isneedlinechart) {
      looplinechart();
     }
    }
   }
   else
   {
    if(self.options.isneedcolumnchart)
    {
     for(var k=0;k<self.options.columnchartdata.length;k++)
     {
      self.ctx.fillstyle =self.options.columnchartcolor;
      drawrectangle(self.ctx,self.linedatalist[k].x-self.reactanglewidth/2,self.options.canvasheight-((self.options.canvasheight-2*self.options.paddingtop)*self.options.columnchartdata[k].pt+self.options.paddingtop),self.reactanglewidth,(self.options.canvasheight-2*self.options.paddingtop)*self.options.columnchartdata[k].pt);
     }
    }
    if(self.options.isneedlinechart) {
     for (var l = 0; l < self.linedatalist.length - 1; l++) {
      self.ctx.linewidth = 4;
      if (l == 0) {
       drawcircle(self.ctx, self.linedatalist[l].x, self.linedatalist[l].y);
      }
      drawcircle(self.ctx, self.linedatalist[l + 1].x, self.linedatalist[l + 1].y);
      self.ctx.beginpath();
      self.ctx.moveto(self.linedatalist[l].x, self.linedatalist[l].y);
      self.ctx.lineto(self.linedatalist[l + 1].x, self.linedatalist[l + 1].y);
      self.ctx.strokestyle = self.options.linechartcolor;
      self.ctx.linewidth = 2*self.axisborderwidth/3;
      self.ctx.stroke();
     }
    }
   }
  }


  function transformaxis(data)
  {
   var newdata=[];
   for(var i=0;i<data.length;i++){
    newdata.push({
     x:data[i].x,
     y:self.options.canvasheight-data[i].y
    })
   }
   return newdata;
  }

  function drawline(context,point,width){
   context.beginpath();
   context.moveto(point[0].x,point[0].y);
   if(point.length>2)
   {
    for(var i=1;i<point.length;i++)
    {
     context.lineto(point[i].x,point[i].y);
    }
   }
   context.linewidth = width;
   context.linejoin='round';
   context.stroke();
   context.closepath();
  }

  //画y轴title
  function drawytext(context,x,y,str) {
   context.beginpath();
   context.font = '{fontsize} microsoft yahei'.replace("{fontsize}",self.fontsize+"px");
   context.fillstyle = 'white';
   context.textalign = 'right';
   context.filltext(str,x,self.options.canvasheight-y);
   context.closepath();
  }
  //画x轴title
  function drawxtext(context,x,y,str) {
   context.beginpath();
   context.font = '{fontsize} microsoft yahei'.replace("{fontsize}",self.fontsize+"px");
   context.fillstyle = 'white';
   context.textalign = 'center';
   context.filltext(str,x,self.options.canvasheight-y);
   context.closepath();
  }
  function drawdottedline(context,x1,y1,x2,y2,totallength,length,linewidth){
   y1 = self.options.canvasheight-y1;
   y2 = self.options.canvasheight-y2;
   var dashlen = length === undefined ? 5 : length;
   //计算有多少个线段
   context.beginpath();
   var num = math.floor(totallength/dashlen);
   context.linewidth = linewidth;
   for(var i = 0 ; i < num; i++)
   {
    context[i%2==0 ? 'moveto' : 'lineto'](x1+(x2-x1)/num*i,y1+(y2-y1)/num*i);
   }
   context.stroke();
  }
 };
 window.chartdraws = chartdraws;
}(window,document));

下面还有一个是实现requestanimationframe浏览器兼容的

(function(){
 var lasttime = 0;
 var prefixes = ['ms','webkit','o','moz']; //各浏览器前缀

 var requestanimationframe = window.requestanimationframe;
 var cancelanimationframe = window.cancelanimationframe;

 var prefix;
 //通过遍历各浏览器前缀,来得到requestanimationframe和cancelanimationframe在当前浏览器的实现形式
 for( var i = 0; i < prefixes.length; i++ ) {
  if ( requestanimationframe && cancelanimationframe ) {
   break;
  }
  prefix = prefixes[i];
  requestanimationframe = requestanimationframe || window[ prefix + 'requestanimationframe' ];
  cancelanimationframe = cancelanimationframe || window[ prefix + 'cancelanimationframe' ] || window[ prefix + 'cancelrequestanimationframe' ];
 }

 //如果当前浏览器不支持requestanimationframe和cancelanimationframe,则会退到settimeout
 if ( !requestanimationframe || !cancelanimationframe ) {
  requestanimationframe = function( callback, element ) {
   var currtime = new date().gettime();
   //为了使settimteout的尽可能的接近每秒60帧的效果
   var timetocall = math.max( 0, 16 - ( currtime - lasttime ) );
   var id = window.settimeout( function() {
    callback( currtime + timetocall );
   }, timetocall );
   lasttime = currtime + timetocall;
   return id;
  };
  cancelanimationframe = function( id ) {
   window.cleartimeout( id );
  };
 }

 window.requestanimationframe = requestanimationframe;
 window.cancelanimationframe = cancelanimationframe;
}());

附上<script>调用

chartdraws({
  "containerid" : "chart1",  //canvas所在容器id
  "canvaswidth" : 1000,
  "canvasheight" : 250,
  "paddingleft" : 50,
  "paddingtop" : 50,
  "columnchartdata": [
   {no:0,pt:0.2,name:"html/css"},
   {no:1,pt:0.4,name:"html5/css3"},
   {no:2,pt:0.4,name:"javascript"},
   {no:3,pt:0.5,name:"jquery"},
   {no:4,pt:0.2,name:"angular.js"},
   {no:5,pt:0.8,name:"bootstrap"},
   {no:6,pt:0.6,name:"react.js"},
   {no:7,pt:0.5,name:"java"}
  ],
  "ychartdata" : [
   {no:0,name:"熟悉"},
   {no:1,name:"掌握"},
   {no:2,name:"精通"}
  ],
  "isneedanimation" : false,
  "isneedborder" : false,
  "isneedlinechart":true,
  "axiscolor" : "#8deeee"
 });
 chartdraws({
  "containerid" : "chart2",  //canvas所在容器id
  "canvaswidth" : 1000,
  "canvasheight" : 250,
  "paddingleft" : 50,
  "paddingtop" : 50,
  "columnchartdata": [
   {no:0,pt:0.4,name:"html/css"},
   {no:1,pt:0.5,name:"html5/css3"},
   {no:2,pt:0.2,name:"javascript"},
   {no:3,pt:0.7,name:"jquery"},
   {no:4,pt:0.2,name:"angular.js"},
   {no:5,pt:0.3,name:"bootstrap"},
   {no:6,pt:0.8,name:"react.js"},
   {no:7,pt:0.2,name:"java"}
  ],
  "ychartdata" : [
   {no:0,name:"熟悉"},
   {no:1,name:"掌握"},
   {no:2,name:"精通"}
  ],
  "isneedanimation" : false,
  "isneedborder" : false,
  "isneedlinechart":false,
  "isneedcolumnchart" : true,
  "columnchartcolor":"#9370db"
 });

 chartdraws({
  "containerid" : "chart3",  //canvas所在容器id
  "canvaswidth" : 1000,
  "canvasheight" : 250,
  "paddingleft" : 50,
  "paddingtop" : 50,
  "columnchartdata": [
   {no:0,pt:0.4,name:"html/css"},
   {no:1,pt:0.5,name:"html5/css3"},
   {no:2,pt:0.2,name:"javascript"},
   {no:3,pt:0.7,name:"jquery"},
   {no:4,pt:0.2,name:"angular.js"},
   {no:5,pt:0.3,name:"bootstrap"},
   {no:6,pt:0.8,name:"react.js"},
   {no:7,pt:0.2,name:"java"}
  ],
  "ychartdata" : [
   {no:0,name:"熟悉"},
   {no:1,name:"掌握"},
   {no:2,name:"精通"}
  ],
  "isneedanimation" : false,
  "isneedborder" : true,
  "isneedlinechart":true,
  "isneedcolumnchart" : false,
  "linechartcolor" : "#8db6cd",
  "bordercolor" : "#87cefa"
 })

html代码

<div class="section">
 <div id="chart1"></div>
 <div id="chart2"></div>
 <div id="chart3"></div>
 </div>

下面是一个实现后的效果图

在整个编码的过程中我把代码改过一次,为什么改呢,因为在第一次的时候我在js里面使用了大量的 chartdraws.prototype.xxxx = function(){};

后来我一想不对啊,我为什么要把这么多的方法暴露给外部呢......这不是没事找事么.......

所以现在就改成这样了,如果有不对的地方和可以改进的地方,希望路过的指点下,谢谢!还有那个白条代码背景怎么删不掉...........

以上这篇js封装成插件_canvas统计图插件编写实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网