Canvas学习,canvas绘制饼状图
效果图如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>画圆</title>
<style>
canvas {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
// 饼状图每一份的占比
let arr = [1,3,8,7,5]
// 计算总的份数
let sum = arr.reduce(function(pro, cur){
return pro + cur
})
console.log(sum);
let canvas = document.querySelector('#canvas')
canvas.width = 500
canvas.height = 500
let ctx = canvas.getContext('2d');
console.log(Math.PI);
let colorArr = ['red', 'blue', 'black', 'green', 'yellow']
// 绘制饼状图函数
function draw(coor) {
let start = 0
let end = 0
for(let i = 0;i < arr.length;i++) {
end = end + Math.PI*2*arr[i]/sum
ctx.beginPath()
// 起点位置
ctx.moveTo(200,200)
// 绘制圆的对应部分图形
// arc参数:(中心点x坐标,中心点y坐标,半径大小,起始角度,结束角度,角度是否逆时针计算)
ctx.arc(200,200,100,start,end,false)
// 设置填充颜色
ctx.fillStyle = colorArr[i]
// 圆弧回到中心点位置
ctx.lineTo(200,200)
// 填充颜色
ctx.fill()
// isPointInPath() 是判断所指定的点是否在所绘制的弧线上,是则返回true,不是则返回false
// 用于判断鼠标是否移入第 i 块图内
if (coor && ctx.isPointInPath(coor.x, coor.y)) {
if (coor.x!==200&&coor.y!==200) {
ctx.beginPath()
ctx.moveTo(200,200)
ctx.arc(200,200,110,start,end,false)
ctx.fill()
let startCoor = activeMethod(start);
console.log(startCoor,'1111');
let endCoor = activeMethod(end)
console.log(endCoor,'2222');
// 绘制鼠标所指土块对应数据和指示折线
drawActiveLine(200,200,startCoor.x,startCoor.y,endCoor.x,endCoor.y,i)
}
}
start = end
}
}
draw()
// 鼠标移动触发事件
canvas.addEventListener('mousemove', function() {
// 获取鼠标所在位置的坐标
let x = event.offsetX;
let y = event.offsetY;
// console.log(event);
ctx.clearRect(0, 0, 500, 500);
// 重绘饼状图,将鼠标坐标进行传参
draw({x: x,y: y});
})
// 计算对应区块起始和结束对应的点
function activeMethod(angle) {
let x = 0
let y = 0
console.log('angle---',angle);
console.log(Math.PI);
if (angle<Math.PI/2 || angle===Math.PI/2) {
x = 200 + 100 * Math.cos(angle)
y = 200 + 100 * Math.sin(angle)
return {x:x,y:y}
} else if (angle>Math.PI/2 && angle < Math.PI || angle===Math.PI) {
angle = Math.PI - angle
x = 200 - 100 * Math.cos(angle)
y = 200 + 100 * Math.sin(angle)
return {x:x,y:y}
} else if (angle>Math.PI && angle < Math.PI*3/2 || angle===Math.PI*3/2) {
angle = angle - Math.PI
x = 200 - 100 * Math.cos(angle)
y = 200 - 100 * Math.sin(angle)
return {x:x,y:y}
} else if (angle>Math.PI*3/2 && angle < Math.PI*2) {
angle = (Math.PI*2 - angle)
x = 200 + 100 * Math.cos(angle)
y = 200 - 100 * Math.sin(angle)
return {x:x,y:y}
} else if (angle == 0 || angle== Math.PI*2) {
x = 200 + 100
y = 200
return {x:x,y:y}
}
}
// 绘制指向对应区块的折线和数据
function drawActiveLine(x1,y1,x2,y2,x3,y3,i) {
console.log(x1+'--'+y1+'--'+x2+'--'+y2+'--'+x3+'--'+y3);
let startX = (x1 + x2 + x3) / 3
let startY = (y1 + y2 + y3) / 3
console.log(startX+'------'+startY);
ctx.beginPath()
ctx.fillStyle = 'red'
ctx.strokeStyle = "red"
ctx.moveTo(startX,startY)
if (startX>200 && startY<200) {
ctx.lineTo(startX+100,startY)
ctx.lineTo(startX+120,startY-20)
ctx.lineTo(startX+140,startY-20)
ctx.textAlign = 'left'
ctx.fillText(`${arr[i]}/${sum}`,startX+145,startY-20)
ctx.stroke()
} else if (startX>200 && startY>200) {
ctx.lineTo(startX+100,startY)
ctx.lineTo(startX+120,startY+20)
ctx.lineTo(startX+140,startY+20)
ctx.textAlign = 'left'
ctx.fillText(`${arr[i]}/${sum}`,startX+145,startY+20)
ctx.stroke()
} else if (startX<200 && startY>200) {
ctx.lineTo(startX-100,startY)
ctx.lineTo(startX-120,startY+20)
ctx.lineTo(startX-140,startY+20)
ctx.textAlign = 'right'
ctx.fillText(`${arr[i]}/${sum}`,startX-145,startY+20)
ctx.stroke()
} else if (startX<200 && startY<200) {
ctx.lineTo(startX-100,startY)
ctx.lineTo(startX-120,startY-20)
ctx.lineTo(startX-140,startY-20)
ctx.textAlign = 'right'
ctx.fillText(`${arr[i]}/${sum}`,startX-145,startY-20)
ctx.stroke()
}
ctx.closePath()
}
</script>
</body>
</html>
文章代码存在错误和可以改进的地方,欢迎大家指正!!!