下面小编就为大家带来一篇js封装成插件_canvas统计图插件编写实例。小编觉得挺不错的,现在就分享js源码给大家,也给大家做个参考。对js感兴趣的一起跟随小编过来看看吧
之前就说过,我想写一个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代码
<p class="section">
<p id="chart1"></p>
<p id="chart2"></p>
<p id="chart3"></p>
</p>
下面是一个实现后的效果图
在整个编码的过程中我把代码改过一次,为什么改呢,因为在第一次的时候我在js里面使用了大量的 chartdraws.prototype.xxxx = function(){};
后来我一想不对啊,我为什么要把这么多的方法暴露给外部呢......这不是没事找事么.......
所以现在就改成这样了,如果有不对的地方和可以改进的地方,希望路过的指点下,谢谢!还有那个白条代码背景怎么删不掉...........
相关推荐:
javascript构造器模式实例分析
javascript如何计算对象长度
javascript中的typeof和类型判断详解
以上就是js封装成插件_canvas统计图插件编写实例_javascript技巧的详细内容。