js封装成插件_Canvas统计图插件编写实例
程序员文章站
2022-11-25 08:09:13
之前就说过,我想写一个canvas画统计图的插件,现在写好了
先说下实现的功能吧:
1.可以通过自定义x轴坐标属性和y轴坐标属性按比例画出统计图
2.可以选择...
之前就说过,我想写一个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统计图插件编写实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
下一篇: Vuejs 页面的区域化与组件封装的实现