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

如何实现SVG弯曲传送带的运行动画效果?

实现SVG弯曲传送带运行动画的可行方法

原生成代码

JavaScript

const cx = 50;
const cy = 50;
const width = 40;
const radius = 100; // CV size
const TwoPi = Math.PI * 0.5;

const circ = TwoPi * radius;
const height = circ / 4; // Roller counts
const parent = document.getElementById("bend");

for (let i = 0; i < circ; i += height) {
    let seg = document.createElementNS("http://www.w3.org/2000/svg", "path");
    
    let rs = (i / circ) * TwoPi;
    let re = ((i + height) / circ) * TwoPi;
    
    let ss = Math.sin(rs);
    let cs = Math.cos(rs);
    let se = Math.sin(re);
    let ce = Math.cos(re);
    
    seg.setAttribute("d",
        `M${(cs * radius) + cx},${(ss * radius) + cy}` +
        `A${radius},${radius} ${((re - rs) / Math.PI) * 180},0,1 ${(ce * radius) + cx},${(se * radius) + cy}` +
        `L${(ce * (radius - width)) + cx},${(se * (radius - width)) + cy}` +
        `A${radius - width},${radius - width} ${((re - rs) / Math.PI) * -180},0,0 ${(cs * (radius - width)) + cx},${(ss * (radius - width)) + cy}z`
    );
    
    seg.setAttribute("fill", "url(#grad2)");
    seg.setAttribute("stroke", "#008000");
    
    parent.appendChild(seg);
}

HTML

<svg width="200" height="200" viewBox="0 0 200 200" style="transform: rotate(-90deg)">
  <defs>
    <linearGradient id="grad2" x1="0%" y1="0%" x2="40%" y2="100%">
      <stop offset="0%" style="stop-color:#008000;stop-opacity:1"/>
      <stop offset="100%" style="stop-color:#c7fdc7;stop-opacity:1"/>
    </linearGradient>
  </defs>
    <g id="bend"></g>
</svg>

可行实现方法

方法1:整体旋转动画(快速实现循环滚动)

利用SVG原生动画标签,让整个传送带组围绕圆心旋转,是最简便的方案。

修改HTML中的<g id="bend">标签,添加动画:

<g id="bend">
  <animateTransform
    attributeName="transform"
    type="rotate"
    origin="50 50" <!-- 对应代码里的cx、cy圆心坐标 -->
    from="0"
    to="90" <!-- 对应TwoPi的90度,刚好覆盖四分之一圆范围 -->
    dur="3s"
    repeatCount="indefinite"
    ease="linear"
  />
</g>

原理:传送带是四分之一圆弧,整体旋转90度后刚好回到初始视觉状态,循环后即可模拟持续滚动效果。

方法2:分段位移动画(更细腻的滚动感)

如果需要每个传送带分段独立移动,而非整体旋转,可通过JS实时更新分段的路径位置。

在原JS代码末尾添加以下逻辑:

// 记录每个分段的初始偏移量
const segments = Array.from(parent.children);
const offsets = segments.map((_, idx) => idx * height);
let animationId;

function animate() {
  offsets.forEach((offset, idx) => {
    // 每帧移动1单位,超出圆弧周长后重置
    let newOffset = (offset + 1) % circ;
    offsets[idx] = newOffset;
    
    let rs = (newOffset / circ) * TwoPi;
    let re = ((newOffset + height) / circ) * TwoPi;
    
    let ss = Math.sin(rs);
    let cs = Math.cos(rs);
    let se = Math.sin(re);
    let ce = Math.cos(re);
    
    // 更新当前分段的路径
    segments[idx].setAttribute("d",
      `M${(cs * radius) + cx},${(ss * radius) + cy}` +
      `A${radius},${radius} ${((re - rs) / Math.PI) * 180},0,1 ${(ce * radius) + cx},${(se * radius) + cy}` +
      `L${(ce * (radius - width)) + cx},${(se * (radius - width)) + cy}` +
      `A${radius - width},${radius - width} ${((re - rs) / Math.PI) * -180},0,0 ${(cs * (radius - width)) + cx},${(ss * (radius - width)) + cy}z`
    );
  });
  animationId = requestAnimationFrame(animate);
}

// 启动动画
animate();

// 如需停止动画:cancelAnimationFrame(animationId);

原理:每个分段沿着圆弧路径逐步移动,偏移量超出范围后重置,实现循环滚动,视觉上每个分段都在独立前进。

方法3:配合渐变动画增强真实感

在上述两种动画的基础上,给传送带的渐变添加动画,模拟滚动时的纹理移动,提升视觉真实度。

修改<linearGradient>部分:

<linearGradient id="grad2" x1="0%" y1="0%" x2="40%" y2="100%">
  <stop offset="0%" style="stop-color:#008000;stop-opacity:1">
    <animate
      attributeName="offset"
      from="0%" to="100%"
      dur="1.5s"
      repeatCount="indefinite"
      ease="linear"
    />
  </stop>
  <stop offset="100%" style="stop-color:#c7fdc7;stop-opacity:1">
    <animate
      attributeName="offset"
      from="100%" to="200%"
      dur="1.5s"
      repeatCount="indefinite"
      ease="linear"
    />
  </stop>
</linearGradient>

原理:渐变的颜色偏移跟随传送带滚动方向移动,让表面呈现出持续流动的质感,和旋转/分段动画配合效果更逼真。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:52:00