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

如何实现固定点静止、SVG路径移动经过该点的动画效果

问题:如何实现固定点不动、SVG路径反向移动经过该点的动画

这看起来可能有些奇怪,但我想要让SVG路径移动经过一个固定点。我清楚可以使用<animateMotion>实现点沿路径运动的动画,现在我想要得到相同的运动逻辑,只是点保持固定,由路径移动经过该点。

到目前为止,我想到可以用path.getTotalLength()来实现,我写了循环在路径上生成采样点,想要让路径在动画中逐次居中到每个采样点的位置,但我对SVG和JavaScript的了解比较有限,现在卡住了不知道该怎么推进。

我目前的代码如下:

现有JS代码

const path = document.getElementById('chemin')
let svg = document.getElementById("mySVG");
let totalLength = path.getTotalLength();
let intersections = 30;

for (var i = 0; i <= intersections; i++) {
    let distance = i * 1 / intersections * totalLength;
    let point = path.getPointAtLength(distance);
    addCircleToSVG(point.x, point.y);
}

function addCircleToSVG(x, y) {
    let circle = document.createElementNS("http://www.w3.org/2000/svg", 'circle');
    circle.setAttribute("cx", x);
    circle.setAttribute("cy", y);
    circle.setAttribute("r", "5");
    circle.setAttribute("fill", "#8888ff");
    svg.appendChild(circle);
}

现有HTML代码

<div class="svgDiv">
    <svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
        x="0px" y="0px" viewBox="0 0 1306 989" style="enable-background:new 0 0 1306 989;" xml:space="preserve">
        <style type="text/css">
            .st1 {
                fill: #fff;
                stroke: #000000;
                stroke-width: 3;
                stroke-miterlimit: 10;
            }

            .st2 {
                fill: none;
                stroke: #ff0000;
                stroke-width: 8;
                stroke-miterlimit: 10;
                stroke-linecap: round;
            }
        </style>
        <g>
            <path id="chemin" class="st2" d="M315,443l13-11h13l13-2h9l7.5,1.5h10l8-4l4-5l15,5l10,4h12h16l16-2l4-1h11h9l8-6h6l8-2l5-3l4-2l5-4l3-3v-4l4-3
                    l5-1h11c0,0,0,0,2,0s12,0,12,0l6,3l3,4l4,4l6,2c0,0,1,0,3-1s6-3,6-3l3-2l5,1h6l8,3l8,1c0,0,4,1,5,1s9,0,9,0l7,1h9h5l6-2l4-1l4-3
                    l5-2l6-4l4-5l4-4l2-5c0,0,1-2,1-4s0-5,0-5v-4c0,0,4,3,4,3l7,2l5,3l6,1l11,2l8,2l7,5l10,2c3-3,6-5,6-5l4-3l4-2l4,2l4-1l-2-6l5-5
                    c0,0,8,3,8,0s4-6,4-6l6-4l3-4l6-6c0,0,0-3-2-7s-5-8-5-8s-2-5-3-9s-4-9,4-11s2-6,1-8s-5-7-5-7v-8l-1-7v-5l-8-11">
            </path>
        </g>
    </svg>

</div>

一开始我觉得这个思路可行,但现在我觉得这个方法走不通,完全卡住了。

编辑补充:我想要实现的分步效果如下图:
需求分步效果图


解决方案

这个需求本质是相对运动的逆向实现,不需要修改原有路径的坐标,只需要通过transform属性动态平移路径即可实现效果,具体逻辑如下:

  1. 先确定目标固定点坐标,这里直接取SVG viewBox的中心(653, 494.5)作为固定点
  2. 动画运行时,根据当前进度取路径上对应的采样点
  3. 计算偏移量:用固定点坐标减去采样点坐标,把这个偏移量作为路径的translate值,就能让当前采样点刚好对齐到固定点,视觉上就是路径移动经过固定点
  4. 用requestAnimationFrame实现平滑动画

可运行完整代码

<!DOCTYPE html>
<html>
<body>
<div class="svgDiv">
    <svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
        x="0px" y="0px" viewBox="0 0 1306 989" style="enable-background:new 0 0 1306 989; width: 800px;" xml:space="preserve">
        <style type="text/css">
            .st2 {
                fill: none;
                stroke: #ff0000;
                stroke-width: 8;
                stroke-miterlimit: 10;
                stroke-linecap: round;
            }
            /* 固定点样式 */
            .fixed-point {
                fill: #8888ff;
                r: 8;
            }
        </style>
        <!-- 固定点,位置居中 -->
        <circle class="fixed-point" cx="653" cy="494.5" />
        <g id="pathGroup">
            <path id="chemin" class="st2" d="M315,443l13-11h13l13-2h9l7.5,1.5h10l8-4l4-5l15,5l10,4h12h16l16-2l4-1h11h9l8-6h6l8-2l5-3l4-2l5-4l3-3v-4l4-3
                    l5-1h11c0,0,0,0,2,0s12,0,12,0l6,3l3,4l4,4l6,2c0,0,1,0,3-1s6-3,6-3l3-2l5,1h6l8,3l8,1c0,0,4,1,5,1s9,0,9,0l7,1h9h5l6-2l4-1l4-3
                    l5-2l6-4l4-5l4-4l2-5c0,0,1-2,1-4s0-5,0-5v-4c0,0,4,3,4,3l7,2l5,3l6,1l11,2l8,2l7,5l10,2c3-3,6-5,6-5l4-3l4-2l4,2l4-1l-2-6l5-5
                    c0,0,8,3,8,0s4-6,4-6l6-4l3-4l6-6c0,0,0-3-2-7s-5-8-5-8s-2-5-3-9s-4-9,4-11s2-6,1-8s-5-7-5-7v-8l-1-7v-5l-8-11">
            </path>
        </g>
    </svg>
</div>
<script>
const path = document.getElementById('chemin');
const pathGroup = document.getElementById('pathGroup');
const totalLength = path.getTotalLength();
// 固定点坐标,可自行修改
const fixedX = 653;
const fixedY = 494.5;
// 动画总时长 单位毫秒
const duration = 5000;
let startTime = null;

function animate(timestamp) {
    if (!startTime) startTime = timestamp;
    const progress = Math.min((timestamp - startTime) / duration, 1);
    const currentDistance = progress * totalLength;
    const point = path.getPointAtLength(currentDistance);
    // 计算偏移量 让采样点对齐固定点
    const offsetX = fixedX - point.x;
    const offsetY = fixedY - point.y;
    pathGroup.setAttribute('transform', `translate(${offsetX}, ${offsetY})`);
    // 动画循环
    if (progress < 1) {
        requestAnimationFrame(animate);
    } else {
        // 如需循环播放,可取消下方两行注释
        // startTime = null;
        // requestAnimationFrame(animate);
    }
}
requestAnimationFrame(animate);
</script>
</body>
</html>

实现说明

  • 没有修改路径本身的d属性,而是给路径套了父级g标签,通过修改父级的transform实现整体平移,渲染性能更高
  • 偏移量逻辑很简单:要让路径上的点(x,y)移动到(fixedX, fixedY),只需要把整个路径往右移fixedX - x、往下移fixedY - y即可,刚好和点沿路径移动的偏移方向相反
  • 如需调整固定点位置,直接修改fixedX和fixedY的值即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:06:01