圆环进度条实现原理.md 4.5 KB

288度对称圆环进度条实现原理

概述

使用 HTML5 Canvas API 实现的对称 288° 圆环进度条,支持颜色渐变和平滑动画。

核心技术点

1. Canvas 绘制基础

技术 说明
绘制方法 ctx.arc() 绘制圆弧
样式设置 strokeStyle、lineWidth、lineCap
坐标系统 以画布中心为原点,使用极坐标计算

2. 角度配置

参数 值 说明
起始角度 -144° 7点钟方向(相对于12点)
结束角度 144° 5点钟方向(相对于12点)
总角度 288° 占完整圆的 80%
空白区域 72° 144° 到 216° 之间

角度计算公式:

角度 = -144° + 进度百分比 × 288° / 100

3. CSS 旋转处理

.progress-wrapper {
    transform: rotate(-90deg);  /* 向左旋转90度 */
}

.progress-info {
    transform: rotate(90deg);   /* 文字反向旋转保持正常 */
}

原理:整个容器旋转 -90°,使 Canvas 的 0° 基准位于 12 点钟方向,文字区域反向旋转保持可读性。

4. 颜色渐变实现

颜色节点配置

const colorStops = [
    {percent: 0, color: '#FFC900'},   // 黄色
    {percent: 11, color: '#FFC900'},
    {percent: 32, color: '#13A6FF'},  // 蓝色
    {percent: 50, color: '#806EFF'},  // 紫色
    {percent: 66, color: '#FF8EEC'},  // 粉色
    {percent: 89, color: '#FE4F51'},  // 红色
    {percent: 100, color: '#FE4F51'}
];

颜色插值算法

  1. 根据进度百分比找到对应的两个颜色节点
  2. 计算节点间的比例 t = (percent - startPercent) / (endPercent - startPercent)
  3. RGB 线性插值:R = R1 + (R2 - R1) × t

5. 分段绘制渐变

核心思路:将圆弧分成多段,每段使用不同颜色,实现平滑渐变效果。

// 计算分段数量(根据进度动态调整)
const segmentCount = Math.max(20, Math.floor(progress * 0.5));

// 分段绘制
for (let i = 0; i < segmentCount; i++) {
    const segmentStart = startAngleRad + (angleRange * i / segmentCount);
    const segmentEnd = startAngleRad + (angleRange * (i + 1) / segmentCount);
    const segmentCenterPercent = (i + 0.5) / segmentCount * progress;
    const segmentColor = getColorForPercent(segmentCenterPercent);
    
    ctx.strokeStyle = segmentColor;
    ctx.arc(centerX, centerY, radius, segmentStart, segmentEnd);
    ctx.stroke();
}

6. 动画实现

缓动函数

const easing = 0.1;
currentProgress += (targetProgress - currentProgress) * easing;

动画循环

  • 使用 requestAnimationFrame 实现平滑动画
  • 当差值小于 0.1 时停止动画
  • 每帧调用 drawProgress() 重绘画布

7. 绘制流程

drawProgress(progress)
    ├── clearRect()              // 清空画布
    ├── drawBackgroundRing()     // 绘制背景圆环和空白区域指示
    ├── 计算结束角度
    ├── 分段绘制进度条(渐变)
    ├── 绘制起点/终点标记(100%时)
    ├── drawProgressText()       // 绘制中心文字
    └── updateUIDisplay()        // 更新UI元素

关键函数说明

函数 功能
drawProgress(progress) 主绘制函数,绘制完整进度条
getColorForPercent(percent) 根据百分比获取插值颜色
interpolateColor(c1, c2, t) RGB 颜色线性插值
calculateAngle(progress) 将进度百分比转换为角度
animateProgress() 动画循环函数
updateProgress(newProgress) 更新目标进度并启动动画

性能优化

  1. 分段数量控制:根据进度动态调整分段数,避免过度绘制
  2. 动画帧控制:使用 requestAnimationFrame 优化渲染性能
  3. 差值判断:当接近目标值时直接设置,避免无限循环

交互功能

功能 实现方式
滑块控制 input[type="range"] 监听 input 事件
测试按钮 预设百分比值快速测试
动画演示 从 0% 到 100% 自动播放
随机进度 生成 0-100 随机值

技术要点总结

  1. Canvas 坐标系:默认 0° 在 3 点钟方向,通过 CSS 旋转调整到 12 点钟
  2. 角度计算:使用弧度制,角度 × Math.PI / 180
  3. 渐变实现:分段绘制 + 颜色插值,而非 Canvas 原生渐变
  4. 文字旋转:容器旋转后,文字元素需要反向旋转保持可读
  5. 动画平滑度:缓动函数 + requestAnimationFrame 实现流畅动画