如何使用SVG SMIL动画<mpath> (运动路径)移动多个圆圈。
问题:关于前3、4圈,一切都很好。
一些圆圈“出了轨道”--所以它们与运动路径不正确地对齐。。

.planePath {
stroke: red;
stroke-width: .1%;
stroke-width: .5%;
stroke-dasharray: 1% 2%;
stroke-linecap: round;
fill: none;
z-index: 99;
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="index.css">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
<title>Document</title>
</head>
<body>
<div class="container-fluid center" style="z-index: 99">
<svg viewBox="-300 -150 3387 1270" align="center" class="svg-animation">
<path id="planePath" class="planePath"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z"/>
/>
<path style="position:absolute" id="circle2" class="planePath "
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z"/>
/>
<defs>
<filter id="filter0_d_0_1" x="0" y="17" width="897" height="847" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_1" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_1" result="shape" />
</filter>
<filter id="filter1_d_0_1" x="926" y="33" width="897" height="847" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_1" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_1" result="shape" />
</filter>
<filter id="filter2_d_0_1" x="1884" y="33" width="897" height="847" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_1" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_1" result="shape" />
</filter>
</defs>
<g id="plane">
<circle cx="80" cy="0" r="20" fill="black" />
</g>
<g id="point">
<circle cx="-50" cy="0" r="20" fill="black"/>
</g>
<g id="point-2">
<circle cx="20" cy="0" r="20" fill="black" />
</g>
<g id="point-3">
<circle cx="-120" cy="0" r="20" fill="black" />
</g>
<g id="point-4">
<circle cx="140" cy="0" r="20" fill="black" />
</g>
<g id="point-5">
<circle cx="180" cy="20" r="20" fill="orange" />
</g>
<g id="point-6">
<circle cx="-180" cy="0" r="20" fill="black" />
</g>
<g id="point-7">
<circle cx="-200" cy="0" r="20" fill="black" />
</g>
<g id="point-8">
<circle cx="-220" cy="0" r="20" fill="black" />
</g>
<g id="point-9">
<circle cx="-240" cy="0" r="20" fill="black" />
</g>
<g id="point-10">
<circle cx="-260" cy="0" r="20" fill="black" />
</g>
<g id="point-11">
<circle cx="-280" cy="0" r="20" fill="black" />
</g>
<g id="point-12">
<circle cx="-300" cy="0" r="20" fill="black"/>
</g>
<g id="point-13">
<circle cx="320" cy="0" r="20" fill="black" />
</g>
<g id="point-14">
<circle cx="-340" cy="0" r="20" fill="black" />
</g>
<g id="point-15">
<circle cx="-360" cy="0" r="20" fill="black" />
</g>
<g id="point-16">
<circle cx="-380" cy="0" r="20" fill="black" />
</g>
<g id="point-17">
<circle cx="-400" cy="0" r="20" fill="black" />
</g>
<g id="point-18">
<circle cx="-420" cy="0" r="20" fill="black" />
</g>
<g id="point-19">
<circle cx="-430" cy="0" r="20" fill="black" />
</g>
<g id="point-20">
<circle cx="-440" cy="0" r="20" fill="black" />
</g>
<g id="point-21">
<circle cx="-460" cy="0" r="20" fill="black" />
</g>
<g id="point-22">
<circle cx="-480" cy="0" r="20" fill="black" />
</g>
<!-- Define the motion path animation -->
<animateMotion xlink:href="#plane" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-2" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-3" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-4" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-5" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<!-- <animateMotion xlink:href="#point-6" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-7" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-8" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-9" dur="20s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion> -->
</svg>
</div>
<!-- <div class="box">
<div class="circle">
</div>
<div class="circle">
</div>
<div class="circle">
</div>
</div> -->
<script src="index.js"></script>
</body>
</html>
<!-- begin snippet: js hide: false console: true babel: false -->
发布于 2022-07-27 18:19:08
你的动画圆圈(沿着运动路径移动)
应该放在cx/cy =0。
这里由@Paul LeBeau:跟踪svg运动路径时的偏移量解释
否则,它们的初始位置将被添加到当前的运动路径位置。
这就是为什么你的圆圈在沿着小径直线移动的原因。
基于动画延迟的路径偏移
实际上,所有的圆圈都有相同的cx="0" cy="0"的中心位置,因此它们在没有动画的情况下是重叠的。
通过添加增量begin值,我们模拟了如下所示的路径偏移:
<animateMotion xlink:href="#plane" dur="10s" begin="0s"repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-1" dur="10s" begin="0.1s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion> begin="0.1s"值越高,圆之间的距离越大。
简化示例
<svg viewBox="-300 -150 3387 1270" align="center" class="svg-animation">
<path id="planePath" fill="none" stroke="red" stroke-width="0.5%" stroke-dasharray="1% 2%"
stroke-linecap="round" class="planePath"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z" />
/>
<g id="circles">
<circle id="plane" class="plane" fill="green" cx="0" cy="0" r="20" fill="black" />
<circle id="point-1" class="point-1" fill="magenta" cx="0" cy="0" r="20" fill="black" />
<circle id="point-2" class="point-2" fill="purple" cx="0" cy="0" r="20" fill="black" />
<circle id="point-3" class="point-3" fill="orange" cx="0" cy="0" r="20" fill="black" />
</g>
<animateMotion xlink:href="#plane" dur="10s" begin="0s"repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-1" dur="10s" begin="0.1s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-2" dur="10s" begin="0.2s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-3" dur="10s" begin="0.3s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
</svg>
缺点:由于延迟,在开始时可以看到x/y=0位置的圆圈,因为它们还没有对齐到运动路径。
作为一种解决办法,我们可以隐藏所有的圆圈,直到它们都是动画/对齐:
.planePath {
stroke: red;
stroke-width: .1%;
stroke-width: .5%;
stroke-dasharray: 1% 2%;
stroke-linecap: round;
fill: none;
}<svg viewBox="-300 -150 3387 1270" align="center" class="svg-animation">
<path id="planePath" class="planePath"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z" />
/>
<g id="circles" opacity="0">
<circle id="plane" class="plane" fill="green" cx="0" cy="0" r="20" fill="black" />
<circle id="point-1" class="point-1" fill="magenta" cx="0" cy="0" r="20" fill="black" />
<circle id="point-2" class="point-2" fill="purple" cx="0" cy="0" r="20" fill="black" />
<circle id="point-3" class="point-3" fill="orange" cx="0" cy="0" r="20" fill="black" />
</g>
<animateMotion xlink:href="#plane" dur="10s" begin="0s"repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-1" dur="10s" begin="0.1s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-2" dur="10s" begin="0.2s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<animateMotion xlink:href="#point-3" dur="10s" begin="0.3s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#planePath" />
</animateMotion>
<!-- hide circles on start: otherwise circles show up at x/y=0 due to animation delay-->
<animate attributeName="opacity"
xlink:href="#circles"
values="0; 1;" dur="0.1s" begin="0.4"
data-id="circles"
repeatCount="1"
fill="freeze"
/>
</svg>
动画中的淡入
<animate attributeName="opacity"
xlink:href="#circles"
values="0; 1;" dur="0.1s" begin="0.4"
data-id="circles"
repeatCount="1"
fill="freeze"
/>begin值的计算如下:
延迟-增量: 0.1 *圆圈总数
初始运动路径偏移- css offset-path到救援
免责声明:浏览器支持可能仍然不稳定。
另见MDN文档。
offset-path属性的主要优点是它能够实际定义一个起始偏移量--对于静态元素呈现来说也相当整洁。
(非常类似于svg的textPath相关startOffset属性)
const svg = document.querySelector('svg');
let dotsCount = 15;
let steps = 100 / dotsCount;
let duration = 10;
let circleRadius = 20;
let startOffset = 50;
//create css rules for animations
let circleMarkup = '';
let css =
`.css-animate circle {
offset-path: path('M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z');
offset-rotate: auto;
}`;
for (let i = 0; i < dotsCount; i++) {
circleMarkup +=
`<circle id="point${i}" class="point point${i}" fill="green" cx="0" cy="0" r="${circleRadius}" />`;
css +=
`.point${i} {
offset-distance: ${steps*i+startOffset}%;
animation: followpath${i} ${duration}s linear infinite;
}
@keyframes followpath${i} {
to {
offset-distance: ${100+steps*i+startOffset}%;
}
}`;
}
svg.insertAdjacentHTML('afterbegin', '<style>'+css+'</style>');
svg.insertAdjacentHTML('beforeend', circleMarkup); <svg viewBox="-300 -150 3387 1270" class="css-animate">
<path id="planePath" stroke="#ccc" stroke-width="1%" stroke-dasharray="1% 2%"
stroke-linecap="round" fill="none" class="planePath"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z" />
</svg>
在上面的示例中,初始运动路径偏移量由以下方法设置:
.point-1 {
offset-distance: 25%;
animation: followpath1 10s linear infinite;
}还引用了@keyframe动画规则:
@keyframes followpath1 {
to {
offset-distance: 125%;
}
}当然,您需要根据所需的偏移量/时间来调整值。
备选方案:动画stroke-dashoffset
可能是最简单的方法--有点紧张。我使用pathLength将破折号数组的计算长度更改为100。
stroke-dasharray: 0 6.666;
stroke-linecap: round;将第一个破折号数组值设置为0时,当与stroke-linecap: round组合时,将产生一条虚线(因此每个点都是完全圆形的)。
第二个值定义了差距或点的总数:
100 (路径长度)/ 15 (3圈-5点)= 0.666。
.planePath {
stroke: red;
stroke-width: 5%;
stroke-dasharray: 0 6.666;
stroke-linecap: round;
fill: none;
animation: animStroke 10s linear infinite;
stroke-dashoffset: 0;
}
.planePath2 {
stroke: red;
stroke-width: 5%;
stroke-dasharray: 0 3.333;
stroke-linecap: round;
fill: none;
animation: animStroke 10s linear infinite;
}
@keyframes animStroke {
to {
stroke-dashoffset: -100;
}
}<div class="container-fluid center" style="z-index: 99">
<svg viewBox="-300 -150 3387 1270" align="center" class="svg-animation">
<path id="planePath" pathLength="100" class="planePath"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z" />
/>
</svg>
</div>
<div class="container-fluid center" style="z-index: 99">
<svg viewBox="-300 -150 3387 1270" align="center" class="svg-animation">
<path id="planePath2" pathLength="100" class="planePath planePath2"
d="M1.50024 430C58.2002 -111.6 853.699 -156.741 889.5 430C925.5 1020 1754 1007.5 1785 430C1816 -147.5 2665.5 -132 2665.5 430C2665.5 1010.27 1847 948 1785 453C1841.5 -83.5 930.282 -187.244 889.5 389C851 933 35 1017.5 1.50024 430Z" />
/>
</svg>
</div>
https://stackoverflow.com/questions/73135195
复制相似问题