视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
js封装成插件_Canvas统计图插件编写实例
2020-11-27 22:30:26 责编:小采
文档

之前就说过,我想写一个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统计图插件编写实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

下载本文
显示全文
专题