微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

先说下实现的功能吧:

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

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

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

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

实现过程

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

话不多说,上代码

rush:xhtml;"> (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.axisBorderWidth2},{x:self.options.paddingLeft+self.axisBorderWidth,y:self.options.canvasHeight-self.options.paddingTop-self.axisBorderWidth2}]),self.axisBorderWidth);
//画x轴三角箭头
drawLine(self.ctx,transformAxis([{x:self.options.canvasWidth-self.options.paddingLeft-self.axisBorderWidth2,y:self.options.paddingTop+self.axisBorderWidth},{x:self.options.canvasWidth-self.options.paddingLeft-self.axisBorderWidth2,y:self.options.paddingTop-self.axisBorderWidth}]),self.axisBorderWidth);
_drawCoordinatePoints();
}

function _drawCoordinatePoints(){
self.reactAngleWidth = (1-20.04)(self.options.canvasWidth-(2self.options.paddingLeft))/(self.options.columnChartData.length2-1);
self.lineDataList = [];
for(var i = 0;i<self.options.columnChartData.length;i++)
{
drawXText(self.ctx,2self.options.columnChartData[i].NOself.reactAngleWidth+self.options.paddingLeft+0.04(self.options.canvasWidth-(2self.options.paddingLeft))+self.reactAngleWidth/2,self.options.paddingTop/2,self.options.columnChartData[i].Name);
self.lineDataList.push({
x:2self.options.columnChartData[i].NOself.reactAngleWidth+self.options.paddingLeft+0.04(self.options.canvasWidth-(2self.options.paddingLeft))+self.reactAngleWidth/2,y:self.options.canvasHeight-(self.options.paddingTop+(self.options.canvasHeight-2self.options.paddingTop)self.options.columnChartData[i].PT)
})
}

//画Y轴title 画y轴虚线
self.reactAngleHeight = (self.options.canvasHeight-2self.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.canvasWidth-self.options.paddingLeft,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-2self.options.paddingTop)self.options.columnChartData[k].PTreactAngleTimer/100+self.options.paddingTop),self.reactAngleWidth,(self.options.canvasHeight-2self.options.paddingTop)self.options.columnChartData[k].PTreactAngleTimer/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 = 2self.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,height);
}
//画圆
function drawCircle(context,y){
context.beginPath();
context.arc(x,self.axisBorderWidth/2,2Math.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.options.canvasHeight-((self.options.canvasHeight-2
self.options.paddingTop)self.options.columnChartData[k].PT+self.options.paddingTop),(self.options.canvasHeight-2self.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,str) {
context.beginPath();
context.font = '{fontSize} Microsoft Yahei'.replace("{fontSize}",self.fontSize+"px");
context.fillStyle = 'white';
context.textAlign = 'right';
context.fillText(str,self.options.canvasHeight-y);
context.closePath();
}
//画x轴title
function drawXText(context,self.fontSize+"px");
context.fillStyle = 'white';
context.textAlign = 'center';
context.fillText(str,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++)
{
contexti%2==0 ? 'moveto' : 'lineto';
}
context.stroke();
}
};
window.ChartDraws = ChartDraws;
}(window,document));

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

rush:xhtml;"> (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;
}());

附上

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐