您的位置:首页 > Web前端 > HTML5

使用H5的canvas绘制饼状图

2020-06-04 05:52 148 查看

前言:在我们写网站,我们往往都想要向用户展示一些数据,比如访问数,文章的点击数等等。如果我们只是用数字来向用户展示的,用户很可能会感觉到枯燥,因为数据的显示实在使太单一的。所以今天我来教大家来用H5的画布api来绘制饼状图,让你的网站更加高大上。

直接进入正题,先展示成果和源码。

最终结果:

代码:

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>

<body>
<canvas width="600" height="600"></canvas>
</body>
<script>
let data = [
{
size: 2,
title: '0-5岁'
},
{
size: 3,
title: '5-10岁'
},
{
size: 4,
title: '10-15岁'
},
{
size: 1,
title: '15-20岁'
},
{
size: 6,
title: '20-25岁'
},
{
size: 4,
title: '25-30岁'
},
{
size: 1,
title: '20-35岁'
}
]
class Chart {
constructor(data) {
this.myCanvas = document.querySelector('canvas')
this.ctx = this.myCanvas.getContext('2d')
// 绘制饼状图所需的数据
this.data = data
// 取画布的中心作为饼状图的圆心
this.x0 = this.myCanvas.width / 2
this.y0 = this.myCanvas.height / 2
// 用来存储每一个数据对应的弧度
this.angles = []
// 半径
this.radius = 150
// 延申线的长度
this.outline = 15
// 初始化功能
this.init()
}
init() {
// 获取对应的角度
this.getAngles()
// 画饼状图
this.drawCircle()
}
// 获取每个数据对应的角度
getAngles() {
let sum = 0
this.data.forEach(item => {
sum += item.size
})
this.data.forEach((item) => {
this.angles.push((item.size / sum) * Math.PI * 2)
})
}
drawCircle() {
let startAngle = 0
let endAngle = 0
// 循环绘制扇形,最后组成圆
for (let i = 0; i < this.data.length; i++) {
endAngle = startAngle + this.angles[i]
this.ctx.beginPath()
// 每次都要把起点移回圆心,不然就会就弄不成扇形
this.ctx.moveTo(this.x0, this.y0)
this.ctx.fillStyle = this.getRandomColor()
this.ctx.arc(this.x0, this.y0, this.radius, startAngle, endAngle)
this.ctx.closePath()
this.ctx.fill()
// 绘制延迟线
this.drawDetails(startAngle, this.angles[i], this.ctx.fillStyle, i)
startAngle = endAngle
}
}
// 获取随机颜色
getRandomColor() {
let r = Math.floor(Math.random() * 255)
let g = Math.floor(Math.random() * 255)
let b = Math.floor(Math.random() * 255)
return `rgb(${r},${g},${b})`
}
drawDetails(startAngle, angle, color, i) {
// 绘制延申线
let edge = this.radius + this.outline
let edgeX = Math.cos(startAngle + angle / 2) * edge
let edgeY = Math.sin(startAngle + angle / 2) * edge
this.ctx.moveTo(this.x0, this.y0)
this.ctx.lineTo(edgeX + this.x0, edgeY + this.y0)
this.ctx.strokeStyle = color
this.ctx.stroke()
// 绘制文字下划线
this.drawTextDecoration(edgeX + this.x0, edgeY + this.y0, i, color)
// 画布左上方的描述
this.drawDataDecoration(this.data[i].title, color, i)
}
drawTextDecoration(x, y, i, color) {
this.ctx.font = '20px 宋体'
this.ctx.beginPath()
this.ctx.moveTo(x, y)
this.ctx.strokeStyle = color
let textWidth = this.ctx.measureText(this.data[i].title).width
if (x > this.x0) { // x坐标大于原点,下划线向右延申不会与圆重叠
this.ctx.lineTo(x + textWidth, y)
// 添加文字,y-3使文字和下划线不用紧贴
this.ctx.fillText(this.data[i].title, x, y - 3)
} else { // x坐标小于原点,下划线向左延申不会与圆重叠
this.ctx.lineTo(x - textWidth, y)
// 添加文字
this.ctx.fillText(this.data[i].title, x - textWidth, y - 3)
}
this.ctx.stroke()
}
// 在画布的左上方添加描述
drawDataDecoration(title, color, i) {
this.ctx.font = '15px 宋体'
this.ctx.fillStyle = color
this.ctx.beginPath()
this.ctx.fillRect(10, (18 * i) + 10, 30, 10)
this.ctx.fillStyle = 'black'
this.ctx.fillText(title, 50, (18 * i) + 20)
}
}
const chart = new Chart(data)
</script>

</html>

难点:

1.绘制圆形:

计算每个数据占总数的百分比,拿去乘以整个圆的弧度2π,就可以得到每个数据对应的弧度了。利用这个弧度去绘制扇形,这个扇形组合起来就是一个圆了。如果不想设置颜色,可以像我一样写一个获取随机颜色的函数。

2.绘制延长线


由于将延长线的颜色和对应的区域的颜色是一样的,我们就只看到饼状图区域外的线。
先说一下延长线的特点:会平分对应扇形的角,经过中点。
.
我们要已知延长线的长度,角度。我们就可以根据三角函数来求延长线的坐标。
我们假设原点是x0和y0,半径的radius,对应扇形的角度是30°。那么我们可以做一个辅助线。如下图:

斜边就是代码中的半径+outline
a边的长度:斜边×cos(当前扇形的一半)
b边的长度:斜边×sin(当前扇形的一半)
因为垂直嘛,所以:
x坐标就是:圆心的x坐标+a
y坐标就是:圆心的y坐标+b

有些人可能会疑问如果角度大于180度的话,会不会异常,假如扇形的角度是大于180°的,获取到的三角函数值是负数的,就会自动的往那个方向延申了。

3.绘制下滑线

根据对应的延长线的终点坐标,和计算文字所需要的宽度来画线。如果延长线的终点x坐标是在右边的话,就x+文字所需要的宽度,y不变。在左边就x-文字所需要的宽度,y不变
其他的都是基本操作了。

结语

最近学的h5的画布功能,发现画布能实现的功能还是挺多的,实现的功能的可以增添自己网站的丰富度。让网站感觉没那么单调。加油!!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: