# 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 旋转处理 ```css .progress-wrapper { transform: rotate(-90deg); /* 向左旋转90度 */ } .progress-info { transform: rotate(90deg); /* 文字反向旋转保持正常 */ } ``` **原理**:整个容器旋转 -90°,使 Canvas 的 0° 基准位于 12 点钟方向,文字区域反向旋转保持可读性。 ### 4. 颜色渐变实现 #### 颜色节点配置 ```javascript 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. 分段绘制渐变 **核心思路**:将圆弧分成多段,每段使用不同颜色,实现平滑渐变效果。 ```javascript // 计算分段数量(根据进度动态调整) 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. 动画实现 #### 缓动函数 ```javascript 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 实现流畅动画