canvas实现圆饼图
- 前言
- 作法
- canvas
- 圆饼制作
前言
最近,跟人讨论怎么在前端页面画圆饼图,想来想去,这难度不高,毕竟网上挺多的,像用伪元素伪装然后旋转出来部分等等,今天就来试试用canvas来话,试着弄了一下,效果图
作法
首先是有这么一组模拟数据,我根据数据来弄成一个饼图
var can = [{
id: 'can-file-other',
color: 'red',
},
{
id: 'can-file-img',
color: 'blue',
},
{
id: 'can-file-tar',
color: 'orange',
},
{
id: 'can-file-vi',
color: 'green',
},
{
id: 'can-file-au',
color: 'pink',
}
]
var File = {
total: 100,
data: [
{type:'other',size: 5},
{type:'img',size: 10},
{type:'tar',size: 10},
{type:'vi',size: 10},
{type:'au',size: 20}
]
}
咋一看,数据格式还挺好懂,
废话不多说,首先来定义框架,
<div id="bu">
<canvas id="can-file" width="300" height="300">
</canvas>
<div id="cir-dir">
<label v-for="(val , index) in file" v-if="val.size > 0">
{{val.type}}
<span :style="{background:can[index].color}"></span>
</label>
</div>
</div>
后面的lable用到了vue来进行构造,当然是用js来构造也是简单的,这里就不详细解析了,
然后稍微解析一下,canvas标签
canvas
canvas标签用于绘制图像,但是本身没用绘制功能,绘制能力都是有js脚本来操作,也就是图像并不能用纯css来构造,要借助js来实现,由于属性挺多的,就不一一列举,这里说一下我这次用到的属性
名 | 描述 |
getcontxt | 配置当前绘制环境,目前了解来看似乎只有个‘2d’这个属性,也就是2d空间,也就是说在未来可能会有3d的绘画环境 |
beginPath | 重置路径,canvas配置有路径记录,也就说,可以用其中的某些方法,比如arcTo等,连续绘画 ,这个方法就是来重置当前路径的 |
arc | 画弧线或者曲线,共有6个属性,下面再行介绍 |
createLinearGradient | 设置渐变样式 |
addColorStop | 设置渐变颜色,和 位置 |
fillStyle | 设置填充图形样式,也就是选颜色,可以单颜色也可以是渐变颜色 |
strokeStyle | 设置填充边线样式,也就是选颜色,可以单颜色也可以是渐变颜色 |
fill | 应用样式填充图形 |
stroke | 也是填充,但是不同的是填充的是边线 |
lineWidth | 设置边线厚度 |
一般来说,在canvas配置环境后再进行绘画,才能用其他方法.
arc属性如下
名 | 描述 |
x | 中心x坐标 |
y | 中心y坐标 |
sAngle | 起始角度 |
eAngle | 结束角度 |
counterclockwise | 选择反向,false为顺时针,true为逆时针,默认是顺时针 |
圆饼制作
首先,饼图是根据上面的数据做的,所以上面数据,也是对图的操作,要取得他的颜色,起始和结束位置,角度就可以用size来计算,但是要注意的一点就是每一次的起始角设置上上一次的起始角,并且角的单位是弧度制,所以得出
所以定义个方法
draw: function(index, val) {
var color = val.color
var c = document.getElementById('can-file')
var ctx = c.getContext('2d')
ctx.beginPath()
var x = 150
var y = 150
var radius = 50;
var startAngle = this.start
var endAngle =startAngle+2*Math.PI * this.file[index].size / 100
this.start = endAngle
ctx.arc(x, y, radius, startAngle, endAngle)
ctx.strokeStyle = color
ctx.lineWidth = 50
ctx.stroke()
}
最后定义循环来进行绘画
this.can.forEach(function(val,index){
this.draw(index,val)
})
//进行最后的填充补充
var c = document.getElementById('can-file')
var ctx = c.getContext('2d')
ctx.beginPath()
var startAngle = this.start
ctx.arc(150, 150, 50, startAngle, 2*Math.PI);
ctx.strokeStyle = 'black'
ctx.lineWidth = 50
ctx.stroke()
设置css和高宽后,得出图形
然后设置一下div的伪类装饰,
#bu:after,#bu:before{
position: absolute;
content: "";
width: 90px;
height: 90px;
border-radius: 50%;
top: calc(50% - 45px);
left: calc(50% - 45px);
background: white;
z-index: 2;
border: 1px solid black;
}
#bu:before{
width: 160px;
height: 160px;
border-radius: 50%;
top: calc(50% - 80px);
left: calc(50% - 80px);
background: transparent;
border: 1px solid black;
z-index: -1;
}
并循环添加lable标签,这里用的是vue来进行添加,也很简单
<label v-for="(val , index) in file" v-if="val.size > 0">
{{val.type}}
<span :style="{background:can[index].color}"></span>
最后得出效果图