You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas定时环形绘制异常:多段同时绘制,求平滑单环方案

Canvas环形动画问题排查与解决方案

问题原因

  • 循环逻辑失效:遍历data数组时,仅保留了最后一项的myVal和myName,导致动画帧反复处理最后一个数据段,drawArc不断累加startAngle,重复绘制多段弧。
  • 进度控制混乱:newX的计算与环形实际绘制进度无关,错误用单个数据项数值作为判断条件,无法形成平滑的整体进度推进。
  • 未清除画布:每帧绘制前未清除画布,导致所有绘制的弧叠加显示,视觉上出现多段混乱效果。

解决方案

  1. 全局进度控制:计算从0到1的动画进度值,对应环形从起始角度到完整一圈的绘制过程。
  2. 分段顺序绘制:按数据项顺序累计占比,根据当前进度计算每个分段的绘制范围,逐步推进环形动画。
  3. 每帧清屏:绘制前清除画布,确保每次只显示当前进度的环形状态。
  4. 修正角度计算:统一基于总占比计算每个分段的起始和结束角度,避免角度累加错误。

修正后的代码

HTML部分

<canvas id="myCanvas" width="800" height="900"></canvas>

JavaScript部分

window.requestAnimFrame = (function(callback) {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame || window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback) {
            window.setTimeout(callback, 1000 / 60);
        };
})();

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var data = ['Red,250', 'Blue,530', 'Orange,390', 'Green,190', 'Purple,450', 'Brown,600'];

// 转换数据为对象数组,方便处理
var segments = data.map(item => {
    const [color, value] = item.split(',');
    return { color, value: parseInt(value) };
});

var myTotal = segments.reduce((sum, seg) => sum + seg.value, 0);
const centerX = 100;
const centerY = 100;
const radius = canvas.height / 8;
const lineWidth = 2.5;
const startAngle = -Math.PI / 2; // 从顶部开始

// 动画参数
const duration = 3000; // 动画总时长(毫秒)
let startTime;

function drawCurrentProgress(progress) {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
    
    let currentAngle = startAngle;
    const totalProgress = Math.min(progress, 1); // 限制进度不超过1
    let accumulatedValue = 0;

    for (let seg of segments) {
        const segRatio = seg.value / myTotal;
        const segProgress = Math.min(totalProgress - accumulatedValue / myTotal, segRatio);
        
        if (segProgress > 0) {
            const endAngle = currentAngle + 2 * Math.PI * segProgress;
            
            ctx.beginPath();
            ctx.arc(centerX, centerY, radius, currentAngle, endAngle, false);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = seg.color;
            ctx.stroke();
            
            currentAngle = endAngle;
        }
        
        accumulatedValue += seg.value;
        if (accumulatedValue / myTotal >= totalProgress) break;
    }
}

function animate() {
    const elapsed = Date.now() - startTime;
    const progress = elapsed / duration;
    
    drawCurrentProgress(progress);
    
    if (progress < 1) {
        requestAnimFrame(animate);
    }
}

// 启动动画
setTimeout(() => {
    startTime = Date.now();
    animate();
}, 100);

内容的提问来源于stack exchange,提问作者Hannington Mambo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:12:18