js封裝成插件_Canvas統(tǒng)計(jì)圖插件編寫(xiě)實(shí)例
之前就說(shuō)過(guò),我想寫(xiě)一個(gè)canvas畫(huà)統(tǒng)計(jì)圖的插件,現(xiàn)在寫(xiě)好了
先說(shuō)下實(shí)現(xiàn)的功能吧:
1.可以通過(guò)自定義X軸坐標(biāo)屬性和Y軸坐標(biāo)屬性按比例畫(huà)出統(tǒng)計(jì)圖
2.可以選擇畫(huà)折現(xiàn)圖還是柱形統(tǒng)計(jì)圖,或者兩者都實(shí)現(xiàn)
3.可以自由定義折現(xiàn)顏色,坐標(biāo)顏色,柱形圖顏色 和canvas邊框顏色,當(dāng)然邊框你也可以選擇要或者不要
4.可以選擇是否實(shí)現(xiàn)柱形圖和折現(xiàn)圖的動(dòng)畫(huà)實(shí)現(xiàn)
實(shí)現(xiàn)過(guò)程
畫(huà)坐標(biāo)——畫(huà)箭頭——做X軸和Y軸的標(biāo)注——畫(huà)柱形圖——畫(huà)折現(xiàn)圖
話不多說(shuō),上代碼
(function(window,document){
var ChartDraws = function(options){
if(!(this instanceof ChartDraws))return new ChartDraws(options);
this.options = $.extend({
//報(bào)表所需的參數(shù)
"containerId" : "", //canvas所在容器id
"canvasWidth" : 400,
"canvasHeight" : 300,
"paddingLeft" : 20,
"paddingTop" : 20,
"columnChartData" :[], //柱形圖的數(shù)量和對(duì)應(yīng)得名稱(chēng)以及百分比
"yChartData" :[], //y軸的數(shù)量及名稱(chēng)
"axisColor" : "white", //坐標(biāo)軸顏色
"columnChartColor" : "#EEE685", //柱形圖顏色
"isNeedAnimation" : true, //是否需要?jiǎng)赢?huà)
"isNeedLineChart" : true, //是否需要折線圖
"isNeedColumnChart" : true, //是否需要柱形圖
"lineChartColor" : "#90EE90", //折線圖顏色,當(dāng)isNeedLineChart=true時(shí)有效
"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);
//畫(huà)三角箭頭
//畫(huà)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);
//畫(huà)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)
})
}
//畫(huà)Y軸title 畫(huà)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);
//畫(huà)虛線
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(){
//柱形圖循環(huán)
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();
}
}
}
//折線圖循環(huán)
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;
}
}
//畫(huà)柱形圖
function drawRectangle(context,x,y,width,height){
context.beginPath();
context.fillRect(x,y,width,height);
}
//畫(huà)圓
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();
}
//畫(huà)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();
}
//畫(huà)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;
//計(jì)算有多少個(gè)線段
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));
下面還有一個(gè)是實(shí)現(xiàn)requestAnimationFrame瀏覽器兼容的
(function(){
var lastTime = 0;
var prefixes = ['ms','webkit','o','moz']; //各瀏覽器前綴
var requestAnimationFrame = window.requestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame;
var prefix;
//通過(guò)遍歷各瀏覽器前綴,來(lái)得到requestAnimationFrame和cancelAnimationFrame在當(dāng)前瀏覽器的實(shí)現(xiàn)形式
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' ];
}
//如果當(dāng)前瀏覽器不支持requestAnimationFrame和cancelAnimationFrame,則會(huì)退到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>調(diào)用
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>
下面是一個(gè)實(shí)現(xiàn)后的效果圖

在整個(gè)編碼的過(guò)程中我把代碼改過(guò)一次,為什么改呢,因?yàn)樵诘谝淮蔚臅r(shí)候我在js里面使用了大量的 ChartDraws.prototype.XXXX = function(){};
后來(lái)我一想不對(duì)啊,我為什么要把這么多的方法暴露給外部呢......這不是沒(méi)事找事么.......
所以現(xiàn)在就改成這樣了,如果有不對(duì)的地方和可以改進(jìn)的地方,希望路過(guò)的指點(diǎn)下,謝謝!還有那個(gè)白條代碼背景怎么刪不掉...........
以上這篇js封裝成插件_Canvas統(tǒng)計(jì)圖插件編寫(xiě)實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Echarts圖表如何利用formatter自定義tooltip的內(nèi)容和樣式
這篇文章主要給大家介紹了關(guān)于Echarts圖表如何利用formatter自定義tooltip的內(nèi)容和樣式的相關(guān)資料,echarts的圖表配置非常的靈活自由,但是不熟悉的時(shí)候容易不知道怎么配置,需要的朋友可以參考下2023-06-06
JavaScript錯(cuò)誤處理之分析 Uncaught(in promise) error的
在開(kāi)發(fā)過(guò)程中,JavaScript的錯(cuò)誤處理是一個(gè)老生常談的話題,當(dāng)應(yīng)用程序發(fā)生未捕獲的異常時(shí),Uncaught(in promise) error是其中最常見(jiàn)的錯(cuò)誤類(lèi)型,這篇文章將從多個(gè)方面詳細(xì)闡述這種錯(cuò)誤類(lèi)型的原因與解決方案,感興趣的朋友一起看看吧2023-12-12
JavaScript通過(guò)HTML的class來(lái)獲取HTML元素的方法總結(jié)
除了getElementsByClassName()函數(shù),我們可以自己動(dòng)手編寫(xiě)程式來(lái)通過(guò)class獲取元素,接下來(lái)我們整理了一下JavaScript通過(guò)HTML的class來(lái)獲取HTML元素的方法總結(jié),需要的朋友可以參考下2016-05-05
JavaScript與Div對(duì)層定位和移動(dòng)獲得坐標(biāo)的實(shí)現(xiàn)代碼
JavaScript與Div對(duì)層定位和移動(dòng)獲得坐標(biāo)的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-09-09
防止Layui form表單重復(fù)提交的實(shí)現(xiàn)方法
今天小編就為大家分享一篇防止Layui form表單重復(fù)提交的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
chrome瀏覽器不支持onmouseleave事件的解決技巧
發(fā)現(xiàn)給div加的 onmouseleave事件在chrome 中不起效果,下面與大家分享下具體的解決方法,不會(huì)的朋友可以了解下哈,希望對(duì)大家有所幫助2013-05-05
微信小程序?qū)Ш綑诟S滑動(dòng)效果的實(shí)現(xiàn)代碼
這篇文章主要介紹了小程序?qū)Ш綑诟S滑動(dòng)效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-05-05
JavaScript基于自定義函數(shù)判斷變量類(lèi)型的實(shí)現(xiàn)方法
這篇文章主要介紹了JavaScript基于自定義函數(shù)判斷變量類(lèi)型的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了javascript判斷變量類(lèi)型的自定義函數(shù)定義與使用方法,并針對(duì)不同瀏覽器給出了相關(guān)的分析與說(shuō)明,需要的朋友可以參考下2016-11-11

