<template>
<div class="circle-progress">
<canvas id="canvas" width="150" height="150"></canvas>
<div class="btns">
<button @click="toCanvas('canvas', '#ffbf00', 0)">0</button>
<button @click="toCanvas('canvas', '#ffbf00', 10)">10</button>
<button @click="toCanvas('canvas', '#ffbf00', 20)">20</button>
<button @click="toCanvas('canvas', '#ffbf00', 30)">30</button>
<button @click="toCanvas('canvas', '#ffbf00', 40)">40</button>
<button @click="toCanvas('canvas', '#ffbf00', 50)">50</button>
</div>
<div class="btns">
<button @click="toCanvas('canvas', '#ffbf00', 60)">60</button>
<button @click="toCanvas('canvas', '#ffbf00', 70)">70</button>
<button @click="toCanvas('canvas', '#ffbf00', 80)">80</button>
<button @click="toCanvas('canvas', '#ffbf00', 90)">90</button>
<button @click="toCanvas('canvas', '#ffbf00', 100)">100</button>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
const obj = reactive({
canvas: '',
percent: '',
ctx: '',
circleX: '',
circleY: '',
radius: '',
cradius: '',
lineWidth: '',
fontSize: '',
color: '',
process: '',
circleLoading: null,
})
const circle = (cx, cy, r) => {
obj.ctx.beginPath();
//ctx.moveTo(cx + r, cy);
obj.ctx.lineWidth = obj.lineWidth;
obj.ctx.strokeStyle = "#000";
obj.ctx.arc(cx, cy, r, 0, Math.PI, true);
obj.ctx.stroke();
}
const sector = (cx, cy, r, startAngle, endAngle, anti) => {
obj.ctx.beginPath();
//ctx.moveTo(cx, cy + r); // 从圆形底部开始画
obj.ctx.lineWidth = obj.lineWidth;
// 进度条颜色
obj.ctx.strokeStyle = obj.color;
//圆弧两端的样式
obj.ctx.lineCap = "round";
//圆弧
obj.ctx.arc(cx, cy, r, Math.PI, Math.PI + (endAngle / 100) * Math.PI, false);
obj.ctx.stroke();
}
const smallcircle2 = (cx, cy, r, fillStyle) => {
obj.ctx.beginPath();
//ctx.moveTo(cx + r, cy);
obj.ctx.lineWidth = 1;
obj.ctx.fillStyle = fillStyle;
obj.ctx.arc(cx, cy, r, 0, Math.PI * 2);
obj.ctx.fill();
}
const loading = (progress) => {
if (obj.process >= obj.percent) {
clearInterval(obj.circleLoading);
}
//清除canvas内容
obj.ctx.clearRect(0, 0, obj.circleX * 2, obj.circleY * 2);
//中间的字
obj.ctx.font = "normal bold 40px April";
obj.ctx.textAlign = "center";
obj.ctx.textBaseline = "middle";
obj.ctx.fillStyle = "#ffbf00";
obj.ctx.fillText(parseFloat(obj.process).toFixed(0), obj.circleX, obj.circleY - 5);
obj.ctx.font = "normal bold " + obj.fontSize + "px April";
obj.ctx.fillStyle = "#ffbf00";
//圆形
circle(obj.circleX, obj.circleY, obj.radius);
//圆弧
sector(obj.circleX, obj.circleY, obj.radius, (Math.PI * 2) / 3, obj.process);
smallcircle2(
obj.cradius +
Math.cos(Math.PI + (obj.process / 100) * Math.PI) * obj.radius,
obj.cradius +
Math.sin(Math.PI + (obj.process / 100) * Math.PI) * obj.radius,
8,
"green"
);
smallcircle2(
obj.cradius +
Math.cos(Math.PI + (obj.process / 100) * Math.PI) * obj.radius,
obj.cradius +
Math.sin(Math.PI + (obj.process / 100) * Math.PI) * obj.radius,
5,
"red"
);
//控制结束时动画的速度
if (obj.process / obj.percent > 0.9) {
obj.process += 0.3;
} else if (obj.process / obj.percent > 0.8) {
obj.process += 0.55;
} else if (obj.process / obj.percent > 0.7) {
obj.process += 0.75;
} else {
obj.process += 1.0;
}
}
const toCanvas = (id, color, progress) => {
clearInterval(obj.circleLoading);
//canvas进度条
obj.canvas = document.getElementById(id);
obj.percent = progress //最终百分比
obj.ctx = canvas.getContext("2d");
obj.circleX = canvas.width / 2; //中心x坐标
obj.circleY = canvas.height / 2; //中心y坐标
obj.radius = 60; //圆环半径
obj.cradius = 75; // canvas半径
obj.lineWidth = 6; //圆形线条的宽度
obj.fontSize = 16; //字体大小
obj.process = 0.0; //进度
obj.color = color;
if (progress < 50) {
obj.circleLoading = window.setInterval(() => {
loading(progress);
}, 20);
}
if (progress >= 50 && progress < 70) {
obj.circleLoading = window.setInterval(() => {
loading(progress);
}, 10);
}
if (progress >= 70) {
obj.circleLoading = window.setInterval(() => {
loading(progress);
}, 6);
}
}
onMounted(() => {
toCanvas("canvas", "#ffbf00", 40);
})
</script>
<style lang="less">
.circle-progress {
h2 {
color: #ffbf00;
margin: 160px 0 60px 0;
}
.btns {
margin: 20px 0;
.van-button--default {
background-color: #ffbf00;
color: #fff;
}
}
}
</style>