【问题标题】:Play SVG animation while hovering over button将鼠标悬停在按钮上时播放 SVG 动画
【发布时间】:2017-04-03 09:00:38
【问题描述】:

所以我得到了这个 svg 本身已经包含动画的 SVG,现在我的问题是如何在将鼠标悬停在 svg 图标上时启动动画,svg 已经具有每个移动部分的 id。

当鼠标悬停在 svg 之外时,我将如何重置它?

<?xml version="1.0" encoding="utf-8"?>
<svg id="family" image-rendering="auto" baseProfile="basic" 
version="1.1" x="0px" y="0px" width="550" height="550"

提供了 svg 本身: https://codepen.io/Zeruw/pen/MpLRqR

Codepen 项目: https://codepen.io/Zeruw/project/editor/DVeMEA/

在项目中,您可以看到,当您将鼠标悬停在按钮上时,它会变为橙色,并且 svg 开始旋转,但不是我想要的方式,我希望它首先冻结,一旦您将鼠标悬停在按钮上,它就会播放给定的动画在 SVG 中。

【问题讨论】:

  • 你试过什么?请创建一个minimal reproducible example
  • 我添加了codepen项目。
  • 您可能需要内联您的 SVG 文件,并使用 CSS 过渡来制作动画。这样您就可以对鼠标悬停做出反应。

标签: html animation svg hover


【解决方案1】:

原则上,可以修改 svg 文件中的 SVG/SMIL 动画,使其按照您希望的方式工作,而无需借助 CSS 动画。

不幸的是,这些动画的编写方式非常复杂。每组四个附加动画中使用了 20 个关键帧。由于它们都是animateTransform 类型,因此可以将它们写为每组单个动画中的矩阵乘积。对每个关键帧进行数学运算会得出一个明显的结果:全部为transform="rotate(a, cx, cy)",具有恒定的旋转中心cx, cy。而且运动节奏如此均匀,以至于所有这些关键帧都完全没有必要。

    <g id="fatherHead" transform="translate(96.35 53.15)">
        <animateTransform attributeName="transform" additive="replace" type="translate" dur="0.833s"
                          keyTimes="0;.05;.1;.15;.2;.25;.3;.35;.4;.45;.5;.55;.6;.65;.7;.75;.8;.85;.9;.95;1"
                          values="176.15,157.45;177.453,158.333;178.648,159.103;179.935,159.911;181.104,160.629;182.261,161.481;183.449,162.199;184.632,162.963;185.711,163.599;186.819,164.308;187.877,165.004;188.916,165.684;189.935,166.338;190.916,166.98;191.921,167.646;192.837,168.282;193.689,168.829;194.633,169.49;195.482,169.967;196.37,170.569;196.37,170.569"
                          fill="freeze"/>
        <animateTransform attributeName="transform" additive="sum" type="rotate" dur="0.833s"
                          keyTimes="0;.05;.1;.15;.2;.25;.3;.35;.4;.45;.5;.55;.6;.65;.7;.75;.8;.85;.9;.95;1"
                          values="0,0,0;.78,0,0;1.558,0,0;2.52,0,0;3.291,0,0;4.056,0,0;5.007,0,0;5.765,0,0;6.52,0,0;7.27,0,0;8.019,0,0;8.762,0,0;9.315,0,0;10.051,0,0;10.782,0,0;11.511,0,0;12.048,0,0;12.766,0,0;13.297,0,0;14,0,0;14,0,0"
                          fill="freeze"/>
        <animateTransform attributeName="transform" additive="sum" type="scale" dur="0.833s" keyTimes="0;.25;.3;1"
                          values="1,1;1,1;1,.999;1,.999" fill="freeze"/>
        <animateTransform attributeName="transform" additive="sum" type="translate" dur="0.833s"
                          keyTimes="0;.05;.1;.15;.2;.25;.3;.35;.4;.45;.5;.55;.6;.65;.7;.75;.8;.85;.9;.95;1"
                          values="-79.8,-104.3;-79.85,-104.4;-79.8,-104.4;-79.9,-104.4;-79.85,-104.35;-79.8,-104.35;-79.85,-104.4;-79.9,-104.4;-79.9,-104.3;-79.85,-104.35;-79.9,-104.3;-79.9,-104.35;-79.9,-104.3;-79.9,-104.3;-79.9,-104.4;-79.85,-104.4;-79.85,-104.35;-79.85,-104.4;-79.85,-104.35;-79.8,-104.35;-79.8,-104.35"
                          fill="freeze"/>
        <path d="..." />
    </g>

因此可以归结为

    <g id="fatherHead" transform="translate(96.35 53.15)">
        <animateTransform attributeName="transform" additive="sum"
                          type="rotate" dur="0.833s"
                          from="0,36.691,193.224" to="14,36.691,193.224"
                          fill="freeze"/>
        <path d="..." />
    </g>

对于下一步,您可以利用动画可以由任何元素上的事件启动这一事实。当鼠标悬停在最外层元素Scene-1r1 上时,可以开始动画,但这有一个问题:悬停将被解释为填充区域,行之间的所有内容都是“out”。解决方案是捕获一个与图像 viewBox 大小相同的覆盖矩形:

<rect id="mask" x="0px" y="0px" width="550" height="550" opacity="0"/>

将其作为最顶层元素插入; opacity="0" 使它不可见但可以悬停。

现在,动画可以得到属性begin="mask.mouseover"

    <g id="fatherHead" transform="translate(96.35 53.15)">
        <animateTransform attributeName="transform" additive="sum"
                          type="rotate" dur="0.833s" begin="mask.mouseover"
                          from="0,36.691,193.224" to="14,36.691,193.224"
                          fill="freeze"/>
        <path d="..." />
    </g>

您可以说,此时问题已解决。但是当您再次将鼠标移出和移入时会发生什么?它不是很漂亮。

如果您想让头部在悬停时只移动一次并且不再移动,只需添加一个属性restart="never"

如果您希望有一个受控的过渡回到原始位置,这可以通过在mouseout 上反转过渡来完成。将这些转换加起来会导致错误的行为,但可以通过稍微不同的结构来纠正:

    <g id="fatherHead" transform="translate(96.35 53.15)">
      <g>
        <animateTransform attributeName="transform" additive="replace"
                          type="rotate" dur="0.833s" begin="bg.mouseover"
                          from="0,36.691,193.224" to="14,36.691,193.224"
                          fill="freeze"/>
        <animateTransform attributeName="transform" additive="replace"
                          type="rotate" dur="0.1s" begin="bg.mouseout"
                          from="14,36.691,193.224" to="0,36.691,193.224"
                          fill="freeze"/>
        <path d="..." />
      </g>
    </g>

现在,当鼠标离开图像时,头部会回到原来的位置。

完整的代码笔:http://codepen.io/anon/pen/wJOjvg

【讨论】:

  • 哇,非常感谢,我还有 3 个 svg 动画,但有了这些信息,我可以做很多事情。我什至不知道鼠标面具部分,所以这真的很有帮助。
  • 所以我现在将 svg 本身更改为您提供给我的那个,当我将鼠标悬停在它上面时 svg 可以工作。但是一旦我尝试将它放在一个按钮中并将鼠标悬停在它上面它就不起作用了,我错过了什么吗? Codepen 链接:codepen.io/Zeruw/project/editor/DVeMEA
  • 似乎 标签仍然没有暴露 SVG 内容的影子 DOM。您可以改用 object 标签:&lt;object data="web/svg/animFamily.svg" title="FamilyIcon" id="iconLogo"/&gt;。请注意,&lt;svg&gt; 元素还需要一个属性 viewBox="0 0 550 550"
  • 是否不可能给对象标签一个href?这样我就可以在 svg 播放动画时使整个按钮可点击。我已经尝试了几件事,不知何故。它要么不会播放动画,要么只是没有用橙色突出显示。 codepen.io/Zeruw/project/editor/DVeMEA我尝试将href添加到对象标签,但没有成功。
  • &lt;object&gt; 没有 href 属性。这里有一个概念上的问题:SVG 需要能够接收事件,但如果可以,父文档一定不能获取它们,以免“为两个主服务”。我能想到的最好的方法是用 &lt;a xlink:href="#" target="_parent"&gt; 将蒙版 rect 包裹在 svg 中
猜你喜欢
  • 2021-11-13
  • 2015-09-16
  • 1970-01-01
  • 1970-01-01
  • 2013-04-04
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多