效果:
![圆弧进度条最终效果](https://i-blog.csdnimg.cn/blog_migrate/cc54d77cf081848e6a287ef1d5207490.png)
代码:
import React, { useEffect, useRef } from 'react';
interface Props {
progress: number;
sid: number;
}
const radius = 110;
const width = radius * 2;
export default function ArcProgressBar({ progress, sid }: Props) {
const ref = useRef<{
ctx?: CanvasRenderingContext2D | null;
center: number;
}>({
center: 0,
});
useEffect(() => {
init();
}, [progress]);
function init() {
let el: HTMLElement | null = document.getElementById('aceProgress' + sid);
if (!el) return;
draw(el);
}
function draw(el: HTMLElement) {
el.replaceChildren();
let canvas = document.createElement('canvas');
el.appendChild(canvas);
ref.current.ctx = canvas.getContext('2d');
el.style.width = `${rpx(width)}px`;
el.style.height = `${rpx(radius)}px`;
canvas.style.width = `${rpx(width)}px`;
canvas.style.height = `${rpx(radius)}px`;
canvas.width = rpx(width);
canvas.height = rpx(radius);
ref.current.center = rpx(radius);
ref.current.ctx!.scale(1, -1);
ref.current.ctx!.translate(0, -width);
drawBg();
drawProgress();
}
function drawBg() {
let ctx = ref.current.ctx!;
ctx.beginPath();
ctx.lineWidth = rpx(8);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(255,255,255,0.3)';
const _start = 0;
const _end = (Math.PI / 180) * 180;
ctx.arc(
ref.current.center,
ref.current.center + rpx(10) * 2,
ref.current.center - rpx(10) * 2,
_start,
_end,
false
);
ctx.stroke();
ctx.closePath();
}
function drawProgress() {
if (!progress) return;
let ctx = ref.current.ctx!;
ctx.beginPath();
ctx.lineWidth = rpx(15);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(255,255,255)';
const _start = 0;
const _end = (Math.PI / 180) * (180 * progress);
ctx.arc(
ref.current.center,
ref.current.center + rpx(10) * 2,
ref.current.center - rpx(10) * 2,
_start,
_end,
false
);
ctx.stroke();
ctx.closePath();
}
return <div id={'aceProgress' + sid} className="cricle-progress"></div>;
}
function rpx(t: number) {
return (t / 375) * window.innerWidth;
}