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

基于Framer Motion的SVG动画开发求助:实现曲线灰线与蓝色小球流动

解决方案

一、创建SVG弯曲线条

替换原代码中的<line>为<path>,通过SVG路径指令绘制弧形:

  • M x,y:定义路径起点
  • Q cx,cy x,y:二次贝塞尔曲线(适配简单弧形)
  • C cx1,cy1 cx2,cy2 x,y:三次贝塞尔曲线(适配复杂曲线)
    根据目标布局,用二次贝塞尔拟合上下两组弧形路径即可匹配需求。

二、实现蓝色小球沿路径无限流动

利用Framer Motion的路径动画能力,为每个路径绑定蓝色小球,通过pathOffset属性控制小球沿路径移动,设置统一的无限循环线性动画保证所有小球同步流动。


完整代码示例

import { motion } from "framer-motion";

const Comp = () => {
  // 统一动画配置:所有小球同步匀速循环
  const ballVariants = {
    flow: {
      pathOffset: 0,
      transition: {
        repeat: Infinity,
        duration: 2,
        ease: "linear",
      },
    },
  };

  return (
    <svg width="800" height="800" viewBox="0 0 200 200" className="rotate-90">
      {/* 中心U形区域 */}
      <path d="M 80 100 L 120 100 L 120 110 L 80 110 Z" fill="#3D414899" />

      {/* 下方弧形路径组(灰色静态)+ 蓝色小球 */}
      <path d="M 100 100 Q 70 140 52 175" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 70 140 52 175')" }}
      />

      <path d="M 100 100 Q 85 145 76 174" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 85 145 76 174')" }}
      />

      <path d="M 100 100 L 100 174" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 L 100 174')" }}
      />

      <path d="M 100 100 Q 115 145 126 180" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 115 145 126 180')" }}
      />

      <path d="M 100 100 Q 130 140 147 168" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 130 140 147 168')" }}
      />

      {/* 上方弧形路径组(灰色静态)+ 蓝色小球 */}
      <path d="M 100 100 Q 130 60 148 25" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 130 60 148 25')" }}
      />

      <path d="M 100 100 Q 115 60 124 26" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 115 60 124 26')" }}
      />

      <path d="M 100 100 L 100 26" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 L 100 26')" }}
      />

      <path d="M 100 100 Q 85 60 74 20" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 85 60 74 20')" }}
      />

      <path d="M 100 100 Q 70 60 55 27" stroke="#3D414899" strokeWidth="1" fill="none" />
      <motion.circle
        variants={ballVariants}
        initial={{ pathOffset: 1 }}
        animate="flow"
        cx={0}
        cy={0}
        r="3"
        fill="#00A3FF"
        style={{ pathLength: "path('M 100 100 Q 70 60 55 27')" }}
      />
    </svg>
  );
};

export default Comp;

关键说明

  1. 弯曲线条调整:可修改<path>中Q后的中间控制点坐标,微调弧形弧度以完全匹配目标图。
  2. 动画同步性:所有小球共用同一动画配置,确保流动节奏完全一致;linear缓动保证匀速运动。
  3. 循环逻辑:pathOffset从1(路径终点)过渡到0(路径起点),配合无限循环实现往返流动效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:49:51