如何沿 svg 路径为一组 svg 对象设置动画

问题描述

我需要沿着路径为字母设置动画,以便它在动画播放时形成弧形以适应路径。

我尝试使用带有 animateMotion 标签的圆弧路径,希望它能将字母组弯曲到其中,但它会跟随路径,同时将字母组保持在一条直线上。

有什么办法可以达到这个效果吗?

https://codepen.io/Finches/pen/vYgMBwW

编辑以包含强制性的 cody 片段(更容易从 codepen 获取完整的 svg):

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1359px"
 height="396px" viewBox="0 0 1359 396" style="overflow:visible;enable-background:new 0 0 1359 396;" xml:space="preserve">  

解决方法

您需要使用相同的动画和使用 begin 属性声明的延迟来为每个字母设置动画。在下一个示例中,我只为字母 A B 和 C 设置动画。

如果您为动画使用相同的路径,则可以使用 <mpath xlink:href="#path"></mpath> 元素来指向要使用的路径并将原始路径保存在 defs 中

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1359 396" style="overflow:visible;enable-background:new 0 0 1359 396;" xml:space="preserve">

  <style type="text/css">
    .st0 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
    }

    .st1 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 11.9626,11.9626;
    }

    .st2 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 11.9189,11.9189;
    }

    .st3 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 6.0125,6.0125;
    }
  </style>

  <defs>

    <path id="path" d="M1214.7,330.9L1214.7,330.9C1214.7,148.2,1047.5,841.1,0L373.6,0C167.2,330.9v0" />
  </defs>
  <path class="st0" d="M1215.7,395c0-147.7-135.7-267.9-302.4-267.9H445.7C279,127.1,143.3,247.2,395H1
    c0-53.2,11.8-104.8,35-153.4c22.4-46.9,54.5-89,95.3-125.2S219.6,51.8,272.6,32C327.5,11.4,385.7,1,445.7,1h467.6
    c60,118.3,10.4,173.1,31c53,19.8,100.5,48.2,141.3,84.4s72.9,78.3,95.3,125.2c23.2,48.6,35,100.2,153.4L1215.7,395z" />
  <g>
    <g>
      <path class="st0" d="M1230.6,395c0-2,0-4-0.1-6" />
      <path class="st1" d="M1230,377c-10.2-156-152.9-263.4-316.7-263.4H445.7c-165.9,0-310.1,110.2-317,269.4" />
      <path class="st0" d="M128.5,389c0,2-0.1,4-0.1,6" />
    </g>
  </g>
  <g>
    <g>
      <path class="st0" d="M16.5,395c0.1-2,0.2-4,0.3-6" />
      <path class="st2" d="M17.6,377.1c3.6-43,14.5-92.7,32.4-130.2c21.6-45.3,52.6-86,92-120.9c39.4-34.9,85.3-62.3,136.5-81.5
            c53-19.9,109.2-29.9,167.2-29.9h467.6c58,114.2,10.1,167.2,29.9c51.1,19.2,97.1,46.6,136.5,81.5c39.4,34.9,70.4,75.6,92,120.9
            c18.7,39.2,29.7,91.8,32.9,136.2" />
      <path class="st0" d="M1342.2,389c0.1,2,0.2,4,0.3,6" />
    </g>
  </g>
  <g>
    <g>
      <path class="st0" d="M1286.9,395L1286.9,395c0-1,0-2,0-3" />
      <path class="st3" d="M1286.7,385.9C1281.3,207.3,1116.2,64,913.3,64H445.7C241.7,75.8,209,72.2,388.9" />
      <path class="st0" d="M72.2,392c0,3v0" />
    </g>
  </g>

  <!-- Alphabet  -->
  <g>

    <g id="a" transform="translate(-35,-35)">
      <animateMotion dur="10s" repeatCount="indefinite">
        <mpath xlink:href="#path"></mpath>
      </animateMotion>
      <rect x="1" y="1" class="st0" width="69.2" height="69.2" />
      <path d="M14.7,52.2L31.8,7.6h6.4l18.3,44.6h-6.7l-5.2-13.5H25.9L21,52.2H14.7z M27.6,33.9h15.1L38,21.5c-1.4-3.8-2.5-6.8-3.2-9.3
            c-0.6,2.9-1.4,5.7-2.4,8.5L27.6,33.9z" />
    </g>

    <g id="b" transform="translate(-121,-35)">
      <animateMotion dur="10s" repeatCount="indefinite" begin="1s">
        <mpath xlink:href="#path"></mpath>
      </animateMotion>
      <rect x="85.9" y="1" class="st0" width="69.2" height="69.2" />
      <path d="M104.2,52.3V7.7h16.7c3.4,6.1,0.5,8.2,1.4c2.1,0.9,3.7,2.3,4.8,4.2c1.2,1.9,1.8,3.8,5.9c0,1.9-0.5,3.7-1.6,5.4
            s-2.6,3-4.7,4.1c2.7,0.8,2.1,6.2,4c1.4,2.2,4.2,6.8c0,2.1-0.4,4-1.3,5.8c-0.9,1.8-2,3.2-3.3,4.2
            c-1.3,1-2.9,1.7-4.9,2.2c-2,0.5-4.4,0.7-7.2,0.7H104.2z M110.1,26.5h9.6c2.6,4.5-0.2,5.6-0.5c1.5-0.4,2.6-1.2,3.4-2.2
            c0.8-1,1.1-2.3,1.1-3.9c0-1.5-0.4-2.8-1.1-3.9s-1.7-1.9-3-2.3S122.2,13,119,13h-8.9V26.5z M110.1,47.1h11.1c1.9,3.2-0.1,4-0.2
            c1.4-0.2,2.5-0.6,3.4-1.2s1.7-1.4,2.3-2.5c0.6-1.1,0.9-2.3,0.9-3.8c0-1.7-0.4-3.1-1.3-4.3s-2-2.1-3.5-2.6s-3.7-0.7-6.5-0.7h-10.3
            V47.1z" />
    </g>

    <g id="c" transform="translate(-209.4,-35)">
      <animateMotion dur="10s" repeatCount="indefinite" begin="2s">
        <mpath xlink:href="#path"></mpath>
      </animateMotion>
      <rect x="174.4" y="1.1" class="st0" width="69.2" height="69.2" />
      <path d="M224.8,36.7l5.9,1.5c-1.2,4.8-3.5,8.5-6.7,11.1c-3.2,2.5-7.1,3.8-11.8,3.8c-4.8,0-8.7-1-11.7-2.9c-3-2-5.3-4.8-6.9-8.5
            c-1.6-3.7-2.4-7.7-2.4-12c0-4.6,0.9-8.7,2.7-12.2c1.8-3.5,4.3-6.1,7.6-7.9S208.4,7,212.3,7c4.5,1.1,11.3,3.4
            c3,5.2,5.5,6.4,9.6l-5.8,1.4c-1-3.2-2.5-5.6-4.5-7.1c-2-1.5-4.4-2.2-7.4-2.2c-3.4,0-6.3,0.8-8.6,2.5s-3.9,3.8-4.9,6.6
            c-0.9,2.8-1.4,5.6-1.4,8.6c0,0.6,7.1,1.7,9.9c1.1,2.8,4.9,6.3c2.3,1.4,7.6,2.1c3.3,6.1-1,8.4-2.9
            C222.4,43.3,224,40.4,224.8,36.7z" />
    </g>

  </g>

</svg>

,

对于解决方案,可以使用 SVG:textPath

这将显着减少代码,因为沿着这条路径移动字母只会有一条路径和相同的动画。

  • 字母表中的每个字母都包裹在标签中 - <tspan dx="0" dy="30">A</tspan>
  • 字母间距可以通过dx参数调整 或与 letter-spacing = "0.18em"
    我选择了 letter-spacing,因为 Firefox 和 Chrome 对 dxdy 进行了不同的间距调整。
  • 由于最初字母表中的所有字母都不适合 交通路线,必须加长:

enter image description here

下面是完整的代码,点击后会开始字母移动的动画:

.container {
     width:100vw;
     height:100vh;
     }
    .st0 {
      fill: none;
      stroke: #000000;
      stroke-width: 3;
      stroke-miterlimit: 10;
    }

    .st1 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 11.9626,11.9189;
    }

    #st3 {
      fill: none;
      stroke: #565656;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 6.0125,6.0125;
    }
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1359 396" style="overflow:visible;enable-background:new 0 0 1359 396;" xml:space="preserve">
  
    <path  id="st3"  d="m73.1 2823.3 0-2367.5L72.2 388.9c0 0 6.7-64.1 17.1-94.2 10.2-29.6 24.9-58 43.6-83.1 19-25.4 42.8-47.4 68.1-66.5 25-18.8 52.8-33.9 81.4-46.5 29.6-13.1 79.6-27.3 92.5-29.8 8.5-1.7 568.1-7.2 597.3-1.8 30.1 5.5 64 14.6 94.4 26.7 25.5 10.2 50.3 22.8 73.1 38.2 25.4 17.2 49.5 36.9 69.8 59.8 21.2 23.9 40.8 50.3 53.2 79.7C1277.7 307.4 1286.7 385.9 1286.7 385.9" />
   
  <!-- Alphabet  -->
   <text font-size="100px" fill="#565656" letter-spacing="0.18em">
     <textPath xlink:href="#st3" startOffset="100%" >
        <tspan  dx="0" dy="30"> A</tspan>
         <tspan dx="0" dy="0"> B</tspan>
           <tspan   dx="0" dy="0"> C</tspan>
            <tspan  dx="0" dy="0"> D</tspan> 
             <tspan dx="0" dy="0"> E</tspan>   
              <tspan dx="0" dy="0"> F</tspan>
               <tspan dx="0" dy="0"> G</tspan>
                <tspan dx="0" dy="0"> H</tspan>  
                 <tspan dx="0" dy="0"> I</tspan>
                  <tspan dx="0" dy="0"> J</tspan>
                 <tspan dx="0" dy="0"> K</tspan>
                <tspan dx="0" dy="0"> L</tspan> 
               <tspan dx="0" dy="0"> M</tspan>  
              <tspan dx="0" dy="0"> N</tspan>
             <tspan dx="0" dy="0"> O</tspan>
            <tspan dx="0" dy="0"> P</tspan>
           <tspan dx="0" dy="0"> Q</tspan> 
          <tspan dx="0" dy="0">R</tspan> 
         <tspan dx="0" dy="0"> S</tspan>
        <tspan dx="0" dy="0"> T</tspan>
       <tspan dx="0" dy="0"> U</tspan> 
      <tspan dx="0" dy="0"> V</tspan>      
     <tspan dx="0" dy="0"> W</tspan>
      <tspan dx="0" dy="0"> X</tspan>
       <tspan dx="0" dy="0"> Y</tspan>
        <tspan dx="0" dy="0"> Z</tspan>    
        <animate  attributeName="startOffset" from="100%" to="-20%" begin="svg1.click" dur="20s" repeatCount="indefinite"/>
        </text>
    </textPath> 
    
  <path class="st0" d="M1215.7,395H1     c0-53.2,1h467.6     c60,395z" />
     
      <path class="st1" d="M1230,269.4" />
         
      <path class="st2" d="M17.6,136.5-81.5c53-19.9,136.2" /> 
     <rect x="0" y="398" width="1400" height="800" fill="white" />      
    </svg>

在问题中,每个字母都包裹在一个框架中。

这可以通过使用 Unicode characters 来解决,它将用字母周围的框架替换拉丁字母。 &#9398; -

由于这本质上是一种字体,您可以对其进行样式设置:设置大小、颜色等。

其余与第一个示例相同。仅字母替换为 unicode 字符

.container {
     width:100vw;
     height:100vh;
     }
    .st0 {
      fill: none;
      stroke: #000000;
      stroke-width: 3;
      stroke-miterlimit: 10;
    }

    .st1 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 11.9626,6.0125;
    }
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1359 396" style="overflow:visible;enable-background:new 0 0 1359 396;" xml:space="preserve">
  
    <path  id="st3"  d="m73.1 2823.3 0-2367.5L72.2 388.9c0 0 6.7-64.1 17.1-94.2 10.2-29.6 24.9-58 43.6-83.1 19-25.4 42.8-47.4 68.1-66.5 25-18.8 52.8-33.9 81.4-46.5 29.6-13.1 79.6-27.3 92.5-29.8 8.5-1.7 568.1-7.2 597.3-1.8 30.1 5.5 64 14.6 94.4 26.7 25.5 10.2 50.3 22.8 73.1 38.2 25.4 17.2 49.5 36.9 69.8 59.8 21.2 23.9 40.8 50.3 53.2 79.7C1277.7 307.4 1286.7 385.9 1286.7 385.9" />
   
  <!-- Alphabet  -->
   <text font-size="100px" fill="#565656">
     <textPath xlink:href="#st3" startOffset="100%" >
        <tspan  dx="0" dy="30"> &#9398;</tspan>
         <tspan dx="0" dy="0"> &#9399;</tspan>
           <tspan   dx="0" dy="0"> &#9400;</tspan>
            <tspan  dx="0" dy="0"> &#9401;</tspan> 
             <tspan dx="0" dy="0"> &#9402;</tspan>   
              <tspan dx="0" dy="0"> &#9403;</tspan>
               <tspan dx="0" dy="0"> &#9404;</tspan>
                <tspan dx="0" dy="0"> &#9405;</tspan>  
                 <tspan dx="0" dy="0"> &#9406;</tspan>
                  <tspan dx="0" dy="0"> &#9407;</tspan>
                 <tspan dx="0" dy="0"> &#9408;</tspan>
                <tspan dx="0" dy="0"> &#9409;</tspan> 
               <tspan dx="0" dy="0"> &#9410;</tspan>    
              <tspan dx="0" dy="0"> &#9411;</tspan>
             <tspan dx="0" dy="0"> &#9412;</tspan>
            <tspan dx="0" dy="0"> &#9413;</tspan>
           <tspan dx="0" dy="0"> &#9414;</tspan> 
          <tspan dx="0" dy="0"> &#9415;</tspan> 
         <tspan dx="0" dy="0"> &#9416;</tspan>
        <tspan dx="0" dy="0"> &#9417;</tspan>
       <tspan dx="0" dy="0"> &#9418;</tspan> 
      <tspan dx="0" dy="0"> &#9419;</tspan>    
     <tspan dx="0" dy="0"> &#9420;</tspan>
      <tspan dx="0" dy="0"> &#9421;</tspan>
       <tspan dx="0" dy="0"> &#9422;</tspan>
        <tspan dx="0" dy="0"> &#9423;</tspan>      
        <animate  attributeName="startOffset" from="100%" to="-20%" begin="svg1.click" dur="20s" repeatCount="indefinite"/>
        </text>
    </textPath> 
    
  <path class="st0" d="M1215.7,136.2" /> 
     <rect x="0" y="398" width="1400" height="800" fill="white" />      
    </svg>

单个字母样式的示例

对于圆圈中字母A的unicode字符 -

<tspan dx="0" dy="30" style="fill:red; font-size:120px;"> &#9398;</tspan>

.container {
     width:100vw;
     height:100vh;
     }
    .st0 {
      fill: none;
      stroke: #000000;
      stroke-width: 3;
      stroke-miterlimit: 10;
    }

    .st1 {
      fill: none;
      stroke: #000000;
      stroke-width: 2;
      stroke-miterlimit: 10;
      stroke-dasharray: 11.9626,6.0125;
    }
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1359 396" style="overflow:visible;enable-background:new 0 0 1359 396;" xml:space="preserve">
  
    <path  id="st3"  d="m73.1 2823.3 0-2367.5L72.2 388.9c0 0 6.7-64.1 17.1-94.2 10.2-29.6 24.9-58 43.6-83.1 19-25.4 42.8-47.4 68.1-66.5 25-18.8 52.8-33.9 81.4-46.5 29.6-13.1 79.6-27.3 92.5-29.8 8.5-1.7 568.1-7.2 597.3-1.8 30.1 5.5 64 14.6 94.4 26.7 25.5 10.2 50.3 22.8 73.1 38.2 25.4 17.2 49.5 36.9 69.8 59.8 21.2 23.9 40.8 50.3 53.2 79.7C1277.7 307.4 1286.7 385.9 1286.7 385.9" />
   
  <!-- Alphabet  -->
   <text font-size="100px" fill="#565656">
     <textPath xlink:href="#st3" startOffset="100%" >
        <tspan  dx="0" dy="30"  style="fill:red; font-size:120px;"> &#9398;</tspan>
         <tspan dx="0" dy="0"> &#9399;</tspan>
           <tspan   dx="0" dy="0"> &#9400;</tspan>
            <tspan  dx="0" dy="0"> &#9401;</tspan> 
             <tspan dx="0" dy="0"> &#9402;</tspan>   
              <tspan dx="0" dy="0"> &#9403;</tspan>
               <tspan dx="0" dy="0"> &#9404;</tspan>
                <tspan dx="0" dy="0"> &#9405;</tspan>  
                 <tspan dx="0" dy="0"> &#9406;</tspan>
                  <tspan dx="0" dy="0" style="fill:dodgerblue; font-size:120px;"> &#9407;</tspan>
                 <tspan dx="0" dy="0"> &#9408;</tspan>
                <tspan dx="0" dy="0"> &#9409;</tspan> 
               <tspan dx="0" dy="0"> &#9410;</tspan>    
              <tspan dx="0" dy="0" style="fill:yellowgreen; font-size:120px;"> &#9411;</tspan>
             <tspan dx="0" dy="0"> &#9412;</tspan>
            <tspan dx="0" dy="0"> &#9413;</tspan>
           <tspan dx="0" dy="0"> &#9414;</tspan> 
          <tspan dx="0" dy="0"> &#9415;</tspan> 
         <tspan dx="0" dy="0"> &#9416;</tspan>
        <tspan dx="0" dy="0" style="fill:gold; font-size:120px;"> &#9417;</tspan>
       <tspan dx="0" dy="0"> &#9418;</tspan> 
      <tspan dx="0" dy="0"> &#9419;</tspan>    
     <tspan dx="0" dy="0"> &#9420;</tspan>
      <tspan dx="0" dy="0"> &#9421;</tspan>
       <tspan dx="0" dy="0"> &#9422;</tspan>
        <tspan dx="0" dy="0" style="fill:crimson; font-size:120px;"> &#9423;</tspan>       
        <animate  attributeName="startOffset" from="100%" to="-20%" begin="svg1.click" dur="20s" repeatCount="indefinite"/>
        </text>
    </textPath> 
    
  <path class="st0" d="M1215.7,136.2" /> 
     <rect x="0" y="398" width="1400" height="800" fill="white" />      
    </svg>