问题描述
我需要沿着路径为字母设置动画,以便它在动画播放时形成弧形以适应路径。
我尝试使用带有 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 对dx
和dy
进行了不同的间距调整。 - 由于最初字母表中的所有字母都不适合 交通路线,必须加长:
下面是完整的代码,点击后会开始字母移动的动画:
.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 来解决,它将用字母周围的框架替换拉丁字母。 Ⓐ
- Ⓐ
由于这本质上是一种字体,您可以对其进行样式设置:设置大小、颜色等。
其余与第一个示例相同。仅字母替换为 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"> Ⓐ</tspan>
<tspan dx="0" dy="0"> Ⓑ</tspan>
<tspan dx="0" dy="0"> Ⓒ</tspan>
<tspan dx="0" dy="0"> Ⓓ</tspan>
<tspan dx="0" dy="0"> Ⓔ</tspan>
<tspan dx="0" dy="0"> Ⓕ</tspan>
<tspan dx="0" dy="0"> Ⓖ</tspan>
<tspan dx="0" dy="0"> Ⓗ</tspan>
<tspan dx="0" dy="0"> Ⓘ</tspan>
<tspan dx="0" dy="0"> Ⓙ</tspan>
<tspan dx="0" dy="0"> Ⓚ</tspan>
<tspan dx="0" dy="0"> Ⓛ</tspan>
<tspan dx="0" dy="0"> Ⓜ</tspan>
<tspan dx="0" dy="0"> Ⓝ</tspan>
<tspan dx="0" dy="0"> Ⓞ</tspan>
<tspan dx="0" dy="0"> Ⓟ</tspan>
<tspan dx="0" dy="0"> Ⓠ</tspan>
<tspan dx="0" dy="0"> Ⓡ</tspan>
<tspan dx="0" dy="0"> Ⓢ</tspan>
<tspan dx="0" dy="0"> Ⓣ</tspan>
<tspan dx="0" dy="0"> Ⓤ</tspan>
<tspan dx="0" dy="0"> Ⓥ</tspan>
<tspan dx="0" dy="0"> Ⓦ</tspan>
<tspan dx="0" dy="0"> Ⓧ</tspan>
<tspan dx="0" dy="0"> Ⓨ</tspan>
<tspan dx="0" dy="0"> Ⓩ</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;"> Ⓐ</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;"> Ⓐ</tspan>
<tspan dx="0" dy="0"> Ⓑ</tspan>
<tspan dx="0" dy="0"> Ⓒ</tspan>
<tspan dx="0" dy="0"> Ⓓ</tspan>
<tspan dx="0" dy="0"> Ⓔ</tspan>
<tspan dx="0" dy="0"> Ⓕ</tspan>
<tspan dx="0" dy="0"> Ⓖ</tspan>
<tspan dx="0" dy="0"> Ⓗ</tspan>
<tspan dx="0" dy="0"> Ⓘ</tspan>
<tspan dx="0" dy="0" style="fill:dodgerblue; font-size:120px;"> Ⓙ</tspan>
<tspan dx="0" dy="0"> Ⓚ</tspan>
<tspan dx="0" dy="0"> Ⓛ</tspan>
<tspan dx="0" dy="0"> Ⓜ</tspan>
<tspan dx="0" dy="0" style="fill:yellowgreen; font-size:120px;"> Ⓝ</tspan>
<tspan dx="0" dy="0"> Ⓞ</tspan>
<tspan dx="0" dy="0"> Ⓟ</tspan>
<tspan dx="0" dy="0"> Ⓠ</tspan>
<tspan dx="0" dy="0"> Ⓡ</tspan>
<tspan dx="0" dy="0"> Ⓢ</tspan>
<tspan dx="0" dy="0" style="fill:gold; font-size:120px;"> Ⓣ</tspan>
<tspan dx="0" dy="0"> Ⓤ</tspan>
<tspan dx="0" dy="0"> Ⓥ</tspan>
<tspan dx="0" dy="0"> Ⓦ</tspan>
<tspan dx="0" dy="0"> Ⓧ</tspan>
<tspan dx="0" dy="0"> Ⓨ</tspan>
<tspan dx="0" dy="0" style="fill:crimson; font-size:120px;"> Ⓩ</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>