【问题标题】:Animating SVG Path using CSS instead of <animateMotion>使用 CSS 而不是 <animateMotion> 动画 SVG 路径
【发布时间】:2020-05-08 12:57:33
【问题描述】:

我试图在贝塞尔曲线的中点放置一个箭头。在问题 How properly shift arrow head on cubic bezier in SVG to its center 中使用 &lt;animateMotion&gt; 的解决方案将移动箭头 &lt;path&gt; 并将其冻结在贝塞尔曲线的中间,仅适用于 Firefox。由于曲线的点在我的情况下经常变化,我不想使用marker-mid,因为每次计算贝塞尔曲线的中点对我来说成本很高。

<svg viewBox="0 0 500 500">
<g>
    <path id="path1" d="M291.698 268.340 C321.698 268.340, 411.904 93.133 441.904 93.133"></path>
    <path class="path_arrow" d="M0,0 L6,6 L0,12" transform="translate(-3,-6)">
        <animateMotion dur="0s" rotate="auto" fill="freeze" keyTimes="0;1" keyPoints="0.5;0.5">
            <mpath xlink:href="#path1"></mpath>
        </animateMotion>
    </path> 
</g>
<g transform="translate(166.698,243.340)">
    <circle r="5" class="p1"></circle>
</g>
<g transform="translate(441.904,68.133)" >
 <circle r="5" class="p2"></circle>
</g>
</svg>

有没有办法使用 CSS Animations 来避免使用 &lt;animateMotion&gt;

编辑 1:

这里曲线的端点是可拖动的,因此曲线的点往往会经常变化。动画是将箭头移动到曲线的中心而不计算中点。

编辑 2:

感谢 Kaiido 的评论,我添加了calcMode="linear",箭头现在按预期放置在路径上。但是当我通过拖动重新定位终点时,箭头在 Chrome 中保持在其初始位置(如图所示),但预计会沿着父路径移动。在 Firefox 中,这和以前一样工作正常。

【问题讨论】:

  • 分享完整的 SVG 和它的 viewbox,这样我们就可以看到动画了
  • 提供的解决方案缺少一些使其在 Blink 浏览器上工作的东西,但从那时起我添加了它。 (calcMode="linear")。因此,该解决方案现在适用于除 IE 之外的所有浏览器(尽管我没有测试,但它可能仍然适用于像 fakeSmile 这样的 polyfill)。你还需要一个纯 CSS 的解决方案吗?因为如果有的话,我担心你会得到比 SMIL 更低的浏览器支持。
  • 关于你的“编辑2”你如何修改你的路径?
  • 感谢 Kaiido 的回答。我只是根据移动的端点修改父路径的d值。我无法弄清楚 Firefox 如何自动执行动画,而 Chrome 没有。
  • 那么用javascript?

标签: css animation svg


【解决方案1】:

您可以使用 CSS offset-pathoffset-distanceoffset-rotate 属性实现相同的效果:

#path1 {
  fill: none;
  stroke: black;
}
.path_arrow {
  transform: translate( -3px, -6px );
  offset-path: path("M220 104C220 144,400 180,400 224");
  offset-rotate: auto;
  offset-distance: 50%;
}
body { background: white; }
<svg width="500" height="500" >
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path class="path_arrow" d="M0,0 L0,12 L12,6 z" />
</svg>

但是their browser support 远低于the one of SMIL,所以不推荐。

请注意,我确实修复了 the answer there 缺少 calcMode="linear" 属性的问题,以使 Blink 浏览器满意。

如果你需要 IE 支持,你可以试试this js implementation,它似乎支持&lt;animateMotion&gt;rotate,记住我自己没有测试过。



关于问题的“编辑2”:

Chrome 确实似乎需要一个明确的调用来更新&lt;mpath&gt;。这可以通过在每次更新后调用&lt;animationMotion&gt; 元素的beginElement() 方法来完成:

document.querySelector('svg').onmousemove = function(e) {
  const rect = this.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  path1.setAttribute( 'd', `M ${x} ${y} C 220 144 400 180 400 224` );
  // Chrome requires an explicit update
  document.querySelector('animateMotion').beginElement();
}
<pre style="position: absolute;pointer-events:none">move your mouse to change the path</pre>
<svg width="500" height="500" >
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path d="M0,0 L0,12 L12,6 z" transform="translate(-3,-6)">
    <animateMotion dur="0s" rotate="auto" fill="freeze"
                   keyTimes="0;1" keyPoints="0.5;0.5" calcMode="linear" >
       <mpath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#path1"/>
    </animateMotion>
  </path>
</svg>

【讨论】:

    【解决方案2】:

    你必须在 css 中使用 webkit 动画。我也推荐https://codepen.io/collection/yivpx/。是一个用于 SVG 优化的开源项目。我也鼓励你在你的 SVG 中命名你的所有类,以便用 animate 做一些很酷的 CSS 东西,比如:

    animation: kaboom 5s ease alternate infinite;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-23
      • 2021-07-25
      • 2015-04-18
      • 1970-01-01
      • 2015-02-03
      • 2020-02-16
      相关资源
      最近更新 更多