function handleExecute(ctx, keyPoints) {
// 设置线条样式
ctx.lineWidth = 1;
ctx.strokeStyle = '#24B7B3';
// 顺序定义折线上各个转折点的坐标
let prevX = keyPoints[0].x;
let prevY = keyPoints[0].y;
let nextX;
let nextY;
// 第一帧执行的时间
let startTime;
// 期望动画持续的时间
const duration = 900;
// 动画被切分成若干段,每一段所占总进度的比例
const partProportion = 1 / (keyPoints.length - 1);
// 缓存绘制第n段线段的n值,为了在进行下一段绘制前把这一段线段的末尾补齐
let lineIndexCache = 1;
/*
* 动画帧绘制方法.
* currentTime是requestAnimation执行回调方法step时会传入的一个执行时的时间(由performance.now()获得).
* */
const step = currentTime => {
// 第一帧绘制时记录下开始的时间
!startTime && (startTime = currentTime);
// 已经过去的时间(ms)
const timeElapsed = currentTime - startTime;
// 动画执行的进度 {0,1}
let progress = Math.min(timeElapsed / duration, 1);
// 描述当前所绘制的是第几段线段
const lineIndex = Math.min(
Math.floor(progress / partProportion) + 1,
keyPoints.length - 1,
);
// 当前线段的进度 {0,1}
const partProgress =
(progress - (lineIndex - 1) * partProportion) / partProportion;
// 绘制方法
const draw = () => {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
// 当绘制下一段线段前,把上一段末尾缺失的部分补齐
if (lineIndex !== lineIndexCache) {
ctx.lineTo(keyPoints[lineIndex - 1].x, keyPoints[lineIndex - 1].y);
lineIndexCache = lineIndex;
}
prevX = nextX = ~~(
keyPoints[lineIndex - 1].x +
(keyPoints[lineIndex].x - keyPoints[lineIndex - 1].x) * partProgress
);
prevY = nextY = ~~(
keyPoints[lineIndex - 1].y +
(keyPoints[lineIndex].y - keyPoints[lineIndex - 1].y) * partProgress
);
ctx.lineTo(nextX, nextY);
ctx.stroke();
};
draw();
if (progress < 1) {
requestAnimationFrame(step);
} else {
console.log('动画执行完毕');
}
};
requestAnimationFrame(step);
}
useEffect(() => {
const canvas = canvasRef.current;
if (canvas) {
const ctx = canvas.getContext('2d');
// 先清除画布(一次性清除画布)
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 获取每个 catalog 元素的位置
catalogRefs.current.forEach((catalogRef, index) => {
if (catalogRef) {
const rect = catalogRef.getBoundingClientRect();
console.log(
`坐标${index}:`,
rect.left,
rect.top,
rect.width,
rect.height,
);
}
});
// 线
drawLine(160, 113, 160, 267, 113, 2, ctx); // 开始绘制动画
// 圆
drawCircle(ctx, 277, 113, 10);
// 线
drawLine(391, 113, 391, 347, 113, 2, ctx); // 开始绘制动画
// 圆
drawCircle(ctx, 342, 113, 10);
const Three = [
{x: 160, y: 377.5},
{x: 195, y: 377.5},
{x: 195, y: 284},
{x: 270, y: 284},
];
handleExecute(ctx, Three);
drawCircle(ctx, 280, 284, 10);
}, [canvasRef.current]);