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

如何基于事件进度实现自定义闭合抛物线贝塞尔曲线动画

基于HTML5 Canvas的抛物线形态进度条实现方案

核心实现逻辑

你可以通过二次贝塞尔曲线拟合抛物线,再按进度截断路径的方式完成需求,整体步骤如下:

  • 预定义100%进度下的曲线参数
    单条抛物线可以用二次贝塞尔曲线完美拟合,只需要2个端点+1个控制点即可:
    • 两条抛物线共享左右两个端点P0(x1,y1)和P2(x2,y2)
    • 上抛物线的控制点设为controlTop(cx, cyTop),下抛物线的控制点设为controlBottom(cx, cyBottom),cx取两个端点的中点即可得到对称的抛物线,也可根据视觉需求自定义位置
      100%进度下的闭合路径就是从P0出发用上控制点画曲线到P2,再从P2出发用下控制点画曲线回到P0后填充。
  • 按进度截断贝塞尔曲线
    使用德卡斯特里奥算法(De Casteljau's Algorithm)计算指定进度t(0≤t≤1,10%进度对应t=0.1)下的截断点和截断后曲线的控制点:
    对任意二次贝塞尔曲线,给定端点P0、P2,控制点P1,进度t对应的截断后前半段曲线参数为:
    新控制点P01 = {x: P0.x + t*(P1.x - P0.x), y: P0.y + t*(P1.y - P0.y)}
    截断点Pt = {x: P01.x + t*( (P1.x + t*(P2.x - P1.x)) - P01.x ), y: P01.y + t*( (P1.y + t*(P2.y - P1.y)) - P01.y )}
    
  • 拼接对应进度的闭合路径
    用进度t分别计算上、下两条抛物线的截断参数,按如下规则拼接路径即可:
    1. 从P0出发,用截断后的上抛物线参数画到截断点Pt
    2. 从Pt出发,用截断后的下抛物线参数反向画回P0
    3. 填充/描边路径即可得到对应进度的闭合抛物线效果

可运行核心代码示例

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// 自定义完整抛物线的坐标参数
const leftPoint = {x: 100, y: 200}; // 左共享端点
const rightPoint = {x: 500, y: 200}; // 右共享端点
const topControl = {x: 300, y: 60}; // 上抛物线控制点
const bottomControl = {x: 300, y: 340}; // 下抛物线控制点

// 计算指定进度下截断后的二次贝塞尔曲线参数
function getTruncatedQuadratic(p0, p1, p2, t) {
  const p01 = {x: p0.x + t * (p1.x - p0.x), y: p0.y + t * (p1.y - p0.y)};
  const p12 = {x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y)};
  const cutPoint = {x: p01.x + t * (p12.x - p01.x), y: p01.y + t * (p12.y - p01.y)};
  return {start: p0, control: p01, end: cutPoint};
}

// 绘制指定进度的闭合抛物线进度条
function drawParabolaProgress(progress) {
  const t = Math.max(0, Math.min(1, progress / 100)); // 把0-100的进度转为0-1的参数
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 分别获取上下两条抛物线的截断参数
  const topTruncated = getTruncatedQuadratic(leftPoint, topControl, rightPoint, t);
  const bottomTruncated = getTruncatedQuadratic(leftPoint, bottomControl, rightPoint, t);
  
  ctx.beginPath();
  // 画上半段曲线
  ctx.moveTo(topTruncated.start.x, topTruncated.start.y);
  ctx.quadraticCurveTo(topTruncated.control.x, topTruncated.control.y, topTruncated.end.x, topTruncated.end.y);
  // 画下半段曲线闭合
  ctx.quadraticCurveTo(bottomTruncated.control.x, bottomTruncated.control.y, bottomTruncated.start.x, bottomTruncated.start.y);
  
  // 自定义样式
  ctx.fillStyle = '#409eff';
  ctx.fill();
  ctx.strokeStyle = '#1d64c7';
  ctx.lineWidth = 2;
  ctx.stroke();
}

// 测试绘制10%进度
drawParabolaProgress(10);
// 动画效果直接用requestAnimationFrame动态修改传入的progress参数即可

内容的提问来源于stack exchange,提问作者Rishabh.IO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 08:18:00