【问题标题】:SVG animate reverse on second clickSVG 在第二次点击时反转动画
【发布时间】:2021-02-13 08:56:39
【问题描述】:

我是一个尝试制作交互式 SVG 的新手——最好不使用任何外部脚本。我的目标是让一个 SVG 元素充当交互式切换开关,以使另一个元素出现和消失。

请在下面找到一个简单的版本,其中文本“Toggle”用作切换。单击时,这会将矩形的 opacity 属性从 0 设置为 1 以使其出现。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg"
   width="47.652294mm"
   height="10.096307mm"
   viewBox="0 0 47.652294 10.096307"
   version="1.1"
   id="svg8">
  <style
     id="style861"></style>
  <defs
     id="defs2" />
  <g
     id="layer1"
     transform="translate(-29.085516,-61.315985)">
    <rect
       fill="#ff0000"
       opacity="0"
       id="rect"
       width="9.8317242"
       height="9.8317242"
       x="66.773796"
       y="61.448277">
       <animate attributeName="opacity" fill="freeze" from="0" to="1" dur="2s" begin="toggletext.click" />
     </rect>
    <text
       xml:space="preserve"
       style="font-size:8.46667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.264583"
       x="29.085516"
       y="68.002762"
       id="toggletext"><tspan
         id="tspan857"
         x="29.085516"
         y="68.002762"
         style="stroke-width:0.264583">Toggle</tspan></text>
  </g>
</svg>

任何后续点击现在都只会重复相同的动画。但我希望任何第二次(第四次、第六次等)单击以反转动画(即使矩形消失)。换句话说,真正充当切换开关。

任何关于如何使用尽可能少的代码和/或不可见元素来实现此效果的建议将不胜感激。 谢谢!

【问题讨论】:

  • 你需要代码或不可见的元素,否则这是不可能的。
  • 您可以看到到目前为止的两个答案使用代码或额外元素。
  • 感谢您的评论@罗伯特。从我的谷歌搜索中,我确实只能找到包含不可见元素或额外代码的解决方案,但我不确定我是否错过了一些新的和/或简单的可能性。

标签: animation svg interactive


【解决方案1】:

我会这样做:我正在使用 2 个重叠的文本元素,并且我将指针事件设置为全部或无点击:这样您将在一个文本上单击一次,然后在另一个文本上单击下一个。

矩形有 2 个动画元素:单击第一个文本时将启动一个动画,单击第二个文本时将启动第二个动画。

text{font-size:8.46667px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583;}
<svg width="300" viewBox="0 0 47.652294 10.096307" id="svg8">

  <g id="layer1" transform="translate(-29.085516,-61.315985)">
    <rect fill="#ff0000" opacity="0" id="rect" width="9.8317242" height="9.8317242" x="66.773796" y="61.448277">
      <animate attributeName="opacity" fill="freeze" from="0" to="1" dur="2s" begin="toggletext1.click" />
      <animate attributeName="opacity" fill="freeze" from="1" to="0" dur="2s" begin="toggletext2.click" />
    </rect>
    

    <text x="29.085516" y="68.002762" id="toggletext2">
      <tspan x="29.085516" y="68.002762">Toggle</tspan>
      <set attributeName="pointer-events" from="none" to="all" begin="toggletext1.click" />
      <set attributeName="pointer-events" from="all" to="none" begin=".click" />
    </text>
    
    <text x="29.085516" y="68.002762" id="toggletext1">
      <tspan x="29.085516" y="68.002762">Toggle</tspan>
      <set attributeName="pointer-events" from="none" to="all" begin="toggletext2.click" />
      <set attributeName="pointer-events" from="all" to="none" begin=".click" />
    </text>
  </g>
</svg>

【讨论】:

  • 谢谢 enxaneta!非常有趣的想法
  • 感谢@enxaneta,这确实很有帮助。我现在明白,如果没有一些解决方法,就不可能达到预期的结果,并且在我看来,您切换两个元素的指针事件的解决方案似乎是最直接的。
【解决方案2】:

添加第二个矩形渐变动画

<animate  id="hide" attributeName="opacity" fill="freeze" 
  from="1" to="0" dur="2s" begin="indefinite" /> 

并添加一个JS触发器,用于切换矩形出现和消失的动画

var svg_1 = document.getElementById("svg8"),
  hide = document.getElementById("hide"),
  visable = document.getElementById("visable");

let flag = true;

svg_1.addEventListener('click', function() {
  if (flag == true) {
    visable.beginElement();
    flag = false;
  } else {
    hide.beginElement();
    flag = true;
  }
});
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg"
   width="47.652294mm"
   height="10.096307mm"
   viewBox="0 0 47.652294 10.096307"
   version="1.1"
   id="svg8">
  <style
     id="style861"></style>
  <defs
     id="defs2" />
  <g
     id="layer1"
     transform="translate(-29.085516,-61.315985)">
    <rect
       fill="#ff0000"
       opacity="0"
       id="rect"
       width="9.8317242"
       height="9.8317242"
       x="66.773796"
       y="61.448277">
       <animate id="visable" attributeName="opacity" fill="freeze" from="0" to="1" dur="2s" begin="indefinite" /> 
         <animate  id="hide" attributeName="opacity" fill="freeze" from="1" to="0" dur="2s" begin="indefinite" />
     </rect>
    <text
       xml:space="preserve"
       style="font-size:8.46667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.264583"
       x="29.085516"
       y="68.002762"
       id="toggletext"><tspan
         id="tspan857"
         x="29.085516"
         y="68.002762"
         style="stroke-width:0.264583">Toggle</tspan></text>
  </g>
</svg>

【讨论】:

    【解决方案3】:

    虽然我喜欢 No-JavaScript pointer-events 方法;我会这样做:

    当 OP 说:最好没有任何外部脚本。
    我想他的意思不是第 3 方库。

    所以我会使用自定义元素 &lt;svg-toggle&gt;(所有现代浏览器都支持)
    为您想要的任意数量的切换创建 SVG

    切换动画:

    • 在每次点击时切换from 和to 参数
    • 重启动画

    <style>
      svg {
        display: inline-block; width: 30%; vertical-align: top;
        cursor: pointer; background: teal; color: white;
      }
    </style>
    
    <svg-toggle></svg-toggle>
    <svg-toggle color="yellow"></svg-toggle>
    <svg-toggle color="blue" label="Blue" duration=".5"></svg-toggle>
    
    <script>
    customElements.define('svg-toggle', class extends HTMLElement {
      connectedCallback() {
        this.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 18">
        <text x="2" y="12" font-size="10px" fill="currentColor">
              ${this.getAttribute("label")||'Toggle'}</text>  
          <rect fill="${this.getAttribute("color")||'red'}" x='33' y="3" width="12" height="12">
            <animate attributeName="opacity" dur="${this.getAttribute("duration")||2}s" from="0" to="1" fill="freeze" begin="indefinite"/> 
          </rect></svg>`;
        this.animate = this.querySelector("animate");
        this.onclick = (evt) => this.toggle();
      }
      toggle( // method, so can be called from Javascript
        from = this.animate.getAttribute("from"), // optional from/to parameters
        to   = this.animate.getAttribute("to"),
      ) { 
        this.animate.setAttribute( "from", to   );
        this.animate.setAttribute( "to"  , from );
        this.animate.beginElement();
      }
    });
    </script>

    我不想要现代 W3C 标准的 Web 组件大杂烩...

    然后将 JavaScript 粘贴到 每个 SVG 上:

    <svg 
      onclick="{
        let a = this.querySelector('animate');
        let from = a.getAttribute('from');
        a.setAttribute('from',a.getAttribute('to'));
        a.setAttribute('to',from);
        a.beginElement();
      }"
      xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 18">
      <text x="2" y="12" font-size="10px" fill="currentColor">Gold</text>  
      <rect fill="gold" x="33" y="3" width="12" height="12">
        <animate attributeName="opacity" dur=".3s" from="0" to="1" 
                 fill="freeze" begin="indefinite"></animate> 
      </rect>
    </svg>

    我不想要 JavaScript

    查看 Enxaneta 他的pointer-events 答案

    【讨论】:

    • 感谢@Danny 提供了这个不错的解决方案。这并不是我想要的(我最终想要在同一个 SVG 中进行多个切换),所以我会选择 Enxaneta 的答案。但我相信这会对其他人有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    相关资源
    最近更新 更多