最近在项目中用到canvas绘图,有点心得,在此小记。
原本打算用百度echarts
,百度echarts有饼状图,但后来没有用。主要有两方面原因。
1.小菜的技术有限,不能直接拿来用。
2.如果要用echarts那就得熟读echarts的api文档,小菜时间有限。
按照小菜的尿性,先把demo放出来
备用演示地址http://walidream.com/example/canvas/pieChart/
1.绘实线圆
方法:drawSolidRound(ctx,x,y,round)
参数:ctx
x
y
round
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 圆心x坐标 |
y | Number | 是 | 圆心y坐标 |
round | Object | 是 | 圆的基本参数 |
参数:round
参数 | 类型 | 必填 | 说明 |
---|
starAngle | Number | 是 | 起始角度 |
endAngle | Number | 是 | 结束角度 |
anticlockwise | Boolean | 是 | true(顺时针),false(逆时针) |
radius | Number | 是 | 圆半径 |
border | Array | 是 | [0]:是线条宽度值,[1]:线条颜色值 |
bgColor | String | 是 | 背景色 |
drawSolidRound(ctx,x,y,round){
ctx.beginPath()
ctx.lineWidth = round.border[0];
ctx.strokeStyle = round.border[1];
ctx.closePath();
ctx.arc(x, y, round.radius, this.getRads(round.starAngle),this.getRads(round.endAngle),round.anticlockwise);
ctx.fillStyle = round.bgColor;
ctx.fill();
ctx.stroke();
}
2.绘虚线圆
方法:drawDashRound (ctx, x, y, dashround)
参数:ctx
x
y
dashround
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 圆心x坐标 |
y | Number | 是 | 圆心y坐标 |
dashround | Object | 是 | 基本参数 |
参数:dashround
参数 | 类型 | 必填 | 说明 |
---|
step | Number | 是 | 虚线间距(值越大,间距越大) |
starAngle | Number | 是 | 起始角度 |
endAngle | Number | 是 | 结束角度 |
anticlockwise | Boolean | 是 | true(顺时针),false(逆时针) |
radius | Number | 是 | 圆半径 |
border | Array | 是 | [0]:线条宽度,[1]:线条颜色值 |
bgColor | String | 是 | 背景色 |
innerBorder | Array | [0]:内环线条宽度,[1]:内环线条颜色值 | |
innerBgColor | String | 是 | 内环背景色 |
drawDashRound (ctx, x, y, dashround){
let step = dashround.step / 180 * 2 * Math.PI;
for (let b = 0, e = step / 2; e <= dashround.endAngle; b += step, e += step) {
ctx.beginPath()
ctx.lineWidth = dashround.border[0];
ctx.strokeStyle = dashround.border[1];
ctx.closePath();
ctx.arc(x, y, dashround.radius, b, e);
ctx.stroke();
}
//填充内圈
ctx.beginPath()
ctx.lineWidth = dashround.innerBorder[0];
ctx.strokeStyle= dashround.innerBorder[1];
ctx.closePath();
ctx.arc(x, y, dashround.radius - dashround.border[0], this.getRads(dashround.starAngle), this.getRads(dashround.endAngle));
ctx.fillStyle= dashround.innerBgColor;
ctx.fill();
ctx.stroke();
}
3.画等份线
方法:drawAngleSolid(ctx,x,y,line)
参数:ctx
x
y
line
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 圆心x坐标 |
y | Number | 是 | 圆心y坐标 |
line | Object | 是 | 基本参数 |
参数:line
参数 | 类型 | 必填 | 说明 |
---|
width | Number | 是 | 线条长度 |
border | Array | 是 | [0]:是线条宽度值,[1]:线条颜色值 |
drawAngleSolid(ctx,x,y,line){
let s = {
x:x,
y:y,
r:line.width
}
let num = this.data.allTagValues.length; //获取等份
let sang = this.getsolidPointAngle(num); //获取等份角度
let spoint = this.getCircle(s,sang); //获取等份角度点坐标
ctx.lineWidth = line.border[0];
ctx.strokeStyle = line.border[1];
let nleng = spoint.length/2;
for(let i=0;i<spoint.length/2;i++){
ctx.beginPath();
ctx.moveTo(spoint[i].x,spoint[i].y);
ctx.lineTo(spoint[i+nleng].x,spoint[i+nleng].y);
ctx.stroke();
ctx.closePath();
}
}
4.画多弧
方法:drawMoreScreen(ctx)
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
drawMoreScreen(ctx){
let self = this;
let screenArr = this.data.tagValueUUIDs;
let allScreenArr = this.data.allTagValusUUIDs;
let angle = 360 / allScreenArr.length;
let angleArr = this.getsolidPointAngle(allScreenArr.length);
let tmpArr = [];
screenArr.forEach( val => {
let tmpobj = this.isArrayValue(val,allScreenArr);
if(tmpobj.flag){
let ang = angleArr[tmpobj.ind];
tmpArr.push(ang);
}
});
tmpArr.forEach( val =>{
self.drawScreen(ctx,canvas.width,canvas.height,this.activeStyle.screen,this.getRads(val),this.getRads(val+angle));
});
}
5.画单弧
方法:drawScreen (ctx,canvasWidth,canvasHeight,screen,sDeg,eDeg)
参数:ctx
canvasWidth
canvasHeight
screen
sDeg
eDeg
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
canvasWidth | Number | 是 | 画布宽度 |
canvasHeight | Number | 是 | 画布高度 |
screen | Object | 是 | 基本参数 |
sDeg | Number | 是 | 起始弧度 |
eDeg | Number | 是 | 结束弧度 |
参数:screen
参数 | 类型 | 必填 | 说明 |
---|
radius | Number | 是 | 圆半径 |
border | Array | 是 | [0]:弧宽度,[1]:弧颜色值 |
bgColor | String | 是 | 背景色 |
drawScreen (ctx,canvasWidth,canvasHeight,screen,sDeg,eDeg) {
let arc = {
x: canvasWidth / 2,
y: canvasHeight / 2,
r: screen.radius
},
w = canvasWidth,
h = canvasHeight;
ctx.save();
ctx.lineWidth = screen.border[0];
ctx.strokeStyle = screen.border[1];
ctx.fillStyle = screen.bgColor;
ctx.beginPath(); // 起始点设置在圆心处
ctx.moveTo(arc.x, arc.y);
ctx.arc(arc.x, arc.y, arc.r,sDeg,eDeg); // 闭合路径
ctx.closePath();
ctx.fill();
ctx.stroke();
}
6.画小圈圈
方法:drawSmallCircle(ctx,x,y,smallRound)
参数:ctx
x
y
smallRound
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 圆心x坐标 |
y | Number | 是 | 圆心y坐标 |
smallRound | Object | 是 | 基本参数 |
参数:smallRound
参数 | 类型 | 必填 | 说明 |
---|
starAngle | Number | 是 | 起始角度 |
endAngle | Number | 是 | 结束角度 |
radius | Number | 是 | 圆半径 |
fatherRadius | Number | 是 | 位于父圆上的半径 |
border | Arrray | 是 | [0]:线条宽度,[1]:线条颜色值 |
noBorder | Array | 是 | [0]:未被选中线条宽度,[1]:未被选中线条颜色值 |
bgColor | String | 是 | 背景色 |
drawSmallCircle(ctx,x,y,smallRound){
let self = this;
let c ={
x:x,
y:y,
r:smallRound.fatherRadius
}
let num = this.data.allTagValues.length; //获取等分
let angles = this.getAngles(num);
let quan = this.getCircle(c,angles); //画小圈圈
quan.forEach(function(val){
self.drawSolidRound(ctx,val.x,val.y,smallRound);
});
}
7.绘制矩形
方法:drawRect(cxt,x,y,width,height,BW,BC,fillColor)
参数:cxt
x
y
width
height
BW
BC
fillColor
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 起始坐标x |
y | Number | 是 | 起始坐标y |
width | Number | 是 | 矩形宽度 |
height | Number | 是 | 矩形高度 |
BW | Number | 是 | 边框线条宽度值 |
BW | String | 是 | 边框线条颜色值 |
fillColor | String | 是 | 矩形填充色 |
drawRect(cxt,x,y,width,height,BW,BC,fillColor){
cxt.beginPath();
cxt.moveTo(x,y);
cxt.lineTo(x+width,y);
cxt.lineTo(x+width,y+height);
cxt.lineTo(x,y+height);
cxt.closePath();
cxt.lineWidth=BW;
cxt.fillStyle=fillColor;
cxt.strokeStyle=BC;
cxt.fill();
cxt.stroke();
}
8.绘文字
方法:drwaText(ctx,x,y,text)
参数:ctx
x
y
text
参数 | 类型 | 必填 | 说明 |
---|
ctx | Object | 是 | canvas 2d绘图环境 |
x | Number | 是 | 圆心x坐标 |
y | Number | 是 | 圆心y坐标 |
text | Object | 是 | 基本参数 |
参数:text
参数 | 类型 | 必填 | 说明 |
---|
radius | Number | 是 | 在外圆文字 |
font | String | 是 | 字体 |
color | String | 是 | 字体颜色 |
noColor | String | 是 | 未被选中字体颜色 |
offsetPosition | Object | 是 | x:向’x’轴偏移x,y:向’y’轴偏移y |
drwaText(ctx,x,y,text){
let t = {
x:x,
y:y,
r:text.radius
}
let divide = this.data.allTagValues.length; //等分
let angles = this.bbbb(divide);
let points = this.getCircle(t,angles);
//this.drawSmallCircle(ctx,2,points)
//this.drawSolidRound(ctx,circle.x,circle.y,circle.r,0,360,{width:1,bgColor:'#000'});
let tmpArr = this.dealTextData(ctx,points,this.data.allTagValues,text.offsetPosition); //获取处理好的数据
ctx.font = text.font;
ctx.fillStyle = text.color;
tmpArr.forEach(function(val){
ctx.fillText(val.text, val.point.x, val.point.y);
});
}
9.工具方法
//1.角度转弧度
getRads (degrees) { return (Math.PI * degrees) / 180; }
//2.弧度转角度
getDegrees (rads) { return (rads * 180) / Math.PI; }
//3.获取角度等分
getAngles(num){
let angle = 360 / num;
let tmpArr = [];
for(let i=1;i<=num;i++){
tmpArr.push(angle * i);
}
return tmpArr;
}
//4.获取圆上任意一点坐标
getCircle(circle,circleArr){
let tmpArr = [];
tmpArr = circleArr.map(function(val){
let obj = {};
obj.x = circle.x + circle.r * Math.cos(val * Math.PI / 180);
obj.y = circle.y + circle.r * Math.sin(val * Math.PI / 180);
return obj;
});
return tmpArr;
}
//5.获取等分线角度
getsolidPointAngle(num){
let angle = 360 / num;
let tmpArr = [];
for(let i=0;i<num;i++){
tmpArr.push(i * angle - 90);
}
return tmpArr;
}
//6.随便起的名字
bbbb(num){
let angle = 360 / num;
let tmpArr = [];
for(let i=0;i<num;i++){
tmpArr.push(angle * i - 90 + angle/2 );
}
return tmpArr;
}
//7.判读数组是否存在某个值
isArrayValue(val,arr){
let obj = {
flag:false,
ind:null
}
arr.forEach((v,i) =>{
if(val == v) {
obj.flag = true;
obj.ind = i;
}
});
return obj;
}
//8.处理文字数据,返回文字起始坐标
dealTextData(ctx,points,textArr,offsetPosition){
let tmpArr = [];
textArr.forEach(function(val,ind){
let obj = {};
let textWidth = ctx.measureText(val).width; //获取文本长度
if(ind < textArr.length / 2){
let point = {
x: points[ind].x + offsetPosition.x,
y: points[ind].y + offsetPosition.y
};
obj.text = val;
obj.point = point;
}else{
let point = {
x: points[ind].x + offsetPosition.x - textWidth -20,
y: points[ind].y + offsetPosition.y
};
obj.text = val;
obj.point = point;
}
tmpArr.push(obj);
});
return tmpArr;
}