如何实现圆点沿双交织椭圆路径平滑动画及路径优化
圆点沿交织椭圆平滑移动的SVG动画问题与解决方案
我想要实现一个圆点沿两个交织椭圆平滑移动的动画,效果如图所示。我通过在线工具将图形转换为单一路径,制作了一个接近可用的SVG动画:
.wrapper { margin-top: 25dvh; height: 50dvh; width: 50dvh; background-color: black; margin: auto; }
<div class="wrapper"> <svg viewBox="0 0 130 130" xmlns="http://www.w3.org/2000/svg"> <path fill="none" stroke="lightgrey" d="M 115.9656 66.951 A 52.9167 26.4583 0 0 1 63.049 93.4094 A 52.9167 26.4583 0 0 1 10.1323 66.951 A 52.9167 26.4583 0 0 1 63.049 40.4927 A 52.9167 26.4583 0 0 1 115.9656 66.951 Z M 62.9167 14.2985 A 26.3265 52.7849 0 0 1 89.2432 67.0833 A 26.3265 52.7849 0 0 1 62.9167 119.8682 A 26.3265 52.7849 0 0 1 36.5901 67.0833 A 26.3265 52.7849 0 0 1 62.9167 14.2985 Z" /> <circle r="5" fill="red"> <animateMotion dur="10s" repeatCount="indefinite" path="M 115.9656 66.951 A 52.9167 26.4583 0 0 1 63.049 93.4094 A 52.9167 26.4583 0 0 1 10.1323 66.951 A 52.9167 26.4583 0 0 1 63.049 40.4927 A 52.9167 26.4583 0 0 1 115.9656 66.951 Z M 62.9167 14.2985 A 26.3265 52.7849 0 0 1 89.2432 67.0833 A 26.3265 52.7849 0 0 1 62.9167 119.8682 A 26.3265 52.7849 0 0 1 36.5901 67.0833 A 26.3265 52.7849 0 0 1 62.9167 14.2985 Z" /> </circle> </svg> </div>
但目前两个椭圆的起点不重合,我希望它们的起点叠加(如图中A点),现提出以下问题:
- 实现该动画的最优/最简单方法是什么?
- 是否可以移动椭圆的起点?
- 我尝试用连续圆弧绘制路径,但无法完成椭圆的数学计算,请问如何计算关键点坐标、rx、ry等参数?
问题解答
1. 实现该动画的最优/最简单方法
最优且最简单的方案是将两个椭圆的路径起点调整至同一交点,合并为一条连续路径后使用SVG原生的animateMotion。纯SVG实现无需额外JS,既能保证移动的平滑性,也便于后续调整参数。
2. 是否可以移动椭圆的起点
当然可以。SVG的椭圆路径由A(圆弧)命令构成,你可以:
- 直接选取椭圆上任意一点作为新起点,重新编写路径命令;
- 通过调整
A命令中的large-arc-flag(大弧标志)和sweep-flag(扫掠标志),改变圆弧的绘制方向,从而将起点切换到椭圆的任意位置,同时保持椭圆形状不变。
3. 椭圆路径的参数计算方法
要手动计算椭圆路径的关键点和参数,可按以下步骤操作:
- 确定基础参数:先明确两个椭圆的中心(这里是SVG viewBox的中心
(65,65))、长半轴rx、短半轴ry、旋转角(水平椭圆旋转0°,垂直椭圆旋转90°)。 - 计算重合起点:选择两个椭圆的交点作为共同起点,比如右侧交点:
- 水平椭圆的右侧端点坐标为
(中心x + rx, 中心y),即(65+52.9167, 65) = (117.9167,65); - 垂直椭圆旋转90°后,该交点同样是其路径上的点,代入椭圆标准方程可验证坐标正确性。
- 水平椭圆的右侧端点坐标为
- 编写圆弧命令:SVG的
A命令格式为A rx ry x-axis-rotation large-arc-flag sweep-flag x y,通过调整large-arc-flag和sweep-flag,保证从起点出发绕椭圆一周后回到起点。
调整后的完整代码
.wrapper { margin-top: 25dvh; height: 50dvh; width: 50dvh; background-color: black; margin: auto; }
<div class="wrapper"> <svg viewBox="0 0 130 130" xmlns="http://www.w3.org/2000/svg"> <!-- 合并后的交织椭圆路径,起点重合于右侧交点 --> <path fill="none" stroke="lightgrey" d="M 117.9167 65 A 52.9167 26.4583 0 0 0 65 91.4583 A 52.9167 26.4583 0 0 0 8.0833 65 A 52.9167 26.4583 0 0 0 65 38.5417 A 52.9167 26.4583 0 0 0 117.9167 65 M 117.9167 65 A 26.4583 52.9167 90 0 1 65 117.9167 A 26.4583 52.9167 90 0 1 12.0833 65 A 26.4583 52.9167 90 0 1 65 12.0833 A 26.4583 52.9167 90 0 1 117.9167 65 Z" /> <circle r="5" fill="red"> <animateMotion dur="10s" repeatCount="indefinite" path="M 117.9167 65 A 52.9167 26.4583 0 0 0 65 91.4583 A 52.9167 26.4583 0 0 0 8.0833 65 A 52.9167 26.4583 0 0 0 65 38.5417 A 52.9167 26.4583 0 0 0 117.9167 65 A 26.4583 52.9167 90 0 1 65 117.9167 A 26.4583 52.9167 90 0 1 12.0833 65 A 26.4583 52.9167 90 0 1 65 12.0833 A 26.4583 52.9167 90 0 1 117.9167 65 Z" /> </circle> </svg> </div>
内容的提问来源于stack exchange,提问作者NicoB
相关产品推荐
相关产品推荐

