沿不同路径同步两个 SVG 动画

Sync two SVG animations along different paths

希望我解释正确。 我有两个脉冲动画,它们 运行 沿着两条不同的路径。我玩过动画的持续时间,但我似乎可以让它们在它们加入的地方“同步”,这样只有一个圆圈到达顶部。 这可能吗?

这是我的代码:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="300"
   height="300"
   viewBox="0 0 120 120"
   version="1.1"
   id="svg11"
   sodipodi:docname="testAn.svg"
   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
  <metadata
     id="metadata17">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs15" />
  <sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="1600"
     inkscape:window-height="837"
     id="namedview13"
     showgrid="false"
     inkscape:zoom="2.4857496"
     inkscape:cx="201.80878"
     inkscape:cy="187.12268"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1"
     inkscape:current-layer="svg11" />
  <g
     id="g140"
     transform="translate(35.662173,31.252367)">
    <path
       id="theMotionPath-sa"
       d="M 10,10 V 40 H 52"
       inkscape:connector-curvature="0"
       style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle
       id="circle119"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="1;0"
         repeatCount="indefinite"
         dur="3s"
         begin="0s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle121"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="1;0"
         repeatCount="indefinite"
         dur="3s"
         begin="1s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle123"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="1;0"
         repeatCount="indefinite"
         dur="3s"
         begin="2s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle125"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="1;0"
         repeatCount="indefinite"
         dur="3s"
         begin="3s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
  </g>
  <g
     id="g57"
     transform="translate(15.662173,36.252367)">
    <path
       id="theMotionPath-ch"
       d="M 10,35 H 30 V 3"
       inkscape:connector-curvature="0"
       style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle
       id="circle36"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="0;1"
         repeatCount="indefinite"
         dur="3s"
         begin="0s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle38"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="0;1"
         repeatCount="indefinite"
         dur="3s"
         begin="1s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle40"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="0;1"
         repeatCount="indefinite"
         dur="3s"
         begin="2s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle42"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;1"
         calcMode="linear"
         keyPoints="0;1"
         repeatCount="indefinite"
         dur="3s"
         begin="3s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
  </g>
</svg>

希望这是有道理的!

你的主要问题是你的点以不同的速度移动,因为运动路径的长度不同。我认为最明智的解决方案是定义三个 单独的运动路径,一个用于左右腿,一个用于向上的腿。然后,为您的动画计时,使左右腿的动画 end 同时在中心点,并且 start 在向上的腿也是同样的时间。

这需要仔细规划运动速度和时间,并隐含地了解路径长度。为了更容易遵循推理,我已经解决了您的 SVG 的转换问题,并稍微重新定位和调整了路径的大小。另外,我已经反转了右腿的方向,这样你就不需要反转运动的方向——省得你拼出 keyPoints/keyTimes 属性。

这是我得到的:

id                   d              length   dur
theMotionPath-left   M 25 70 H 45   20       1.5s
theMotionPath-right  M 85 70 H 45   40       3s
theMotionPath-up     M 45 70 V 40   30       2s

不同腿的速度确实完全匹配,只是近似匹配。但这并没有威慑力,重要的是所有点 reach/leave 每一秒都是中心点。

但是左腿有问题。 repeatCount="indefinite"表示动画结束后立即重新开始。从 1.5 秒开始的运动将在 3 秒结束,然后在 4.5 秒、6 秒、7.5 秒后再次运动,......每秒钟运动将 根据需要与其他部分匹配。

解决这个问题的方法是在每个动画开始之间增加一个延迟:运行 1.5 秒,等待 1.5 秒,再次 运行 等。

这可以用一个技巧来完成。可以 bind the start of an animation to the end of another animation - 或同一动画的不同 运行。省略 repeatCount 属性,但定义 list begin 次:

      <animateMotion id="leftDot1" dur="1.5s" begin="1.5s;leftDot1.end + 1.5s">
        <mpath xlink:href="#theMotionPath-left" />
      </animateMotion>

1.5s后,第一次启动动画,另外每次id为leftDot1的动画(本身)结束,等待1.5s,然后再次启动。

<svg width="300" height="300" viewBox="0 0 120 120"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <g>
    <path id="theMotionPath-left" d="M 25 70 H 45"
          style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion id="leftDot1" dur="1.5s" begin="1.5s;leftDot1.end + 1.5s">
        <mpath xlink:href="#theMotionPath-left" />
      </animateMotion>
    </circle>
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion id="leftDot2" dur="1.5s" begin="2.5s;leftDot2.end + 1.5s">
        <mpath xlink:href="#theMotionPath-left" />
      </animateMotion>
    </circle>
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion id="leftDot3" dur="1.5s" begin="3.5s;leftDot3.end + 1.5s">
        <mpath xlink:href="#theMotionPath-left" />
      </animateMotion>
    </circle>
  </g>
  <g>
    <path id="theMotionPath-right" d="M 85 70 H 45"
          style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion repeatCount="indefinite" dur="3s" begin="0s">
        <mpath xlink:href="#theMotionPath-right" />
      </animateMotion>
    </circle>
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion repeatCount="indefinite" dur="3s" begin="1s">
        <mpath xlink:href="#theMotionPath-right" />
      </animateMotion>
    </circle>
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion repeatCount="indefinite" dur="3s" begin="2s">
        <mpath xlink:href="#theMotionPath-right" />
      </animateMotion>
    </circle>
  </g>
  <g>
    <path id="theMotionPath-up" d="M 45 70 V 40"
          style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion repeatCount="indefinite" dur="2s" begin="3s">
        <mpath xlink:href="#theMotionPath-up" />
      </animateMotion>
    </circle>
    <circle r="2" cy="0" cx="0" style="fill:#4789d0">
      <animateMotion repeatCount="indefinite" dur="2s" begin="4s">
        <mpath xlink:href="#theMotionPath-up" />
      </animateMotion>
    </circle>
  </g>
</svg>

只是根据@ccprog 的回答构建,您还可以使用 keyTimeskeyPoints 来改变水平和垂直部分的动画速度。您需要了解几件事:

  • 首先,需要将#theMotionPath-chd属性设置为d="M 10,35 H 30 V 5",使其到达与另一条路径相同的垂直点

  • 然后,计算每条路径相对于其长度变化的点:#theMotionPath-sa中的0.4167和#theMotionPath-ch中的0.4。

  • 最后加一个keyTime(我设置在0.6,意思是在0.6 * 3s = 1.8s和前面对应的keyPoint步骤。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="300"
   height="300"
   viewBox="0 0 120 120"
   version="1.1"
   id="svg11"
   sodipodi:docname="testAn.svg"
   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
  <metadata
     id="metadata17">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs15" />
  <sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="1600"
     inkscape:window-height="837"
     id="namedview13"
     showgrid="false"
     inkscape:zoom="2.4857496"
     inkscape:cx="201.80878"
     inkscape:cy="187.12268"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1"
     inkscape:current-layer="svg11" />
  <g
     id="g140"
     transform="translate(35.662173,31.252367)">
    <path
       id="theMotionPath-sa"
       d="M 10,10 V 40 H 52"
       inkscape:connector-curvature="0"
       style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle
       id="circle119"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="1;0.4167;0"
         repeatCount="indefinite"
         dur="3s"
         begin="0s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle121"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="1;0.4167;0"
         repeatCount="indefinite"
         dur="3s"
         begin="1s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle123"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="1;0.4167;0"
         repeatCount="indefinite"
         dur="3s"
         begin="2s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
    <circle
       id="circle125"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="1;0.4167;0"
         repeatCount="indefinite"
         dur="3s"
         begin="3s">
        <mpath
           xlink:href="#theMotionPath-sa" />
      </animateMotion>
    </circle>
  </g>
  <g
     id="g57"
     transform="translate(15.662173,36.252367)">
    <path
       id="theMotionPath-ch"
       d="M 10,35 H 30 V 5"
       inkscape:connector-curvature="0"
       style="fill:none;stroke:#4789d0;stroke-width:1" />
    <circle
       id="circle36"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="0;0.40;1"
         repeatCount="indefinite"
         dur="3s"
         begin="0s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle38"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="0;0.40;1"
         repeatCount="indefinite"
         dur="3s"
         begin="1s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle40"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="0;0.40;1"
         repeatCount="indefinite"
         dur="3s"
         begin="2s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
    <circle
       id="circle42"
       r="2"
       cy="0"
       cx="0"
       style="fill:#4789d0">
      <!-- Define the motion path animation -->
      <animateMotion
         keyTimes="0;0.6;1"
         calcMode="linear"
         keyPoints="0;0.40;1"
         repeatCount="indefinite"
         dur="3s"
         begin="3s">
        <mpath
           xlink:href="#theMotionPath-ch" />
      </animateMotion>
    </circle>
  </g>
</svg>

看了例子后我想到只要每个动画的时间保持不变并且 的间隔每个动画 运行 也保持不变那么路径不会有任何区别。唯一会改变的是动画的速度。

这是另一个示例:

<svg width="300" height="300"  viewBox="0 0 120 120"
     xmlns="http://www.w3.org/2000/svg" version="1.1"
     xmlns:xlink="http://www.w3.org/1999/xlink" >

    
   <!-- Edit This Path .   -->  
    <path d="M 10,60 H 60 "    stroke="#4789D0"  stroke-width="1"  fill="none" id="M-Right"/>
    <path d="M 60,60 v -50 "    stroke="#4789D0"  stroke-width="1"  fill="none" id="M-Up"/>
    <path d="M 60,60 h 30"    stroke="#4789D0"  stroke-width="1"  fill="none" id="M-Left"/>
   <!-- Here is a green circle which will be moved along the motion path. -->
   <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="c1" begin='0s' dur='3s' repeatCount="indefinite"  keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
    </circle>
    
       <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="c2" begin='1s' dur='3s' repeatCount="indefinite"  keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
    </circle>

       <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="c3" begin='2s' dur='3s' repeatCount="indefinite"  keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
    </circle>
        
       <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="c4" begin='3s' dur='3s' repeatCount="indefinite"  keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Right"/> </animateMotion>
    </circle>  
  
 <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="vc1"  begin='c1.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
    </circle>
    
 <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="vc2"  begin='c2.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
    </circle>   
    
 <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="vc3"  begin='c3.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
    </circle>

 <circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="vc4"  begin='c4.begin+3s' dur='3s' repeatCount="indefinite" keyPoints="0;1" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Up"/> </animateMotion>
    </circle>


<circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="lc1"  begin='c1.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
    </circle>
    
<circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="lc2"  begin='c2.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
    </circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="lc3"  begin='c3.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
    </circle>
<circle cx="" cy="" r="2" fill="#4789D0" >
         <!-- Define the motion path animation -->
      <animateMotion id="lc4"  begin='c4.begin+0s' dur='3s' repeatCount="indefinite" keyPoints="1;0" calcMode="linear" keyTimes="0;1"> <mpath xlink:href="#M-Left"/> </animateMotion>
    </circle>
                
    
    
</svg>

您可以编辑长度,但它仍会保持同步