【问题标题】:Dynamically animate an svg element动态地为 svg 元素设置动画
【发布时间】:2018-01-01 21:58:01
【问题描述】:

我正在实现一个简单的游戏,玩家将控制屏幕中间的一个红色圆圈。圆圈被实现为 SVG 元素。

我希望能够使用 SVG 动画 (SMIL) 在 SVG 视图框中的任意两个位置之间移动圆。每个动画的触发是在屏幕上的任意位置单击鼠标左键。

我有 written code,我相信它应该可以在 Firefox 和 Chrome 中使用。在 Chrome 中,它仅适用于第一个动画,而对于所有后续动画,圆圈只是“传送”。在 Firefox 中没有动画 (控制台中没有错误)

我的代码中是否存在错误,或者 SMIL 过于不成熟是否存在一些众所周知的问题?

我可以让 SMIL 在这个用例中工作还是应该改用画布?

这是我目前得到的代码:

<!DOCTYPE html>
<html>
  <body>
    <svg id="canvas" width="800" height="800" onclick="Move()">
      <circle id="player1" cx="300" cy="300" r="40" stroke="blue" stroke-width="4" fill="red">
      </circle>
    </svg>
    <script>

      function createAnimation(attribute, playerID, duration, from, to) {
        var animation = document.createElementNS("http://www.w3.org/2000/svg", "animate")
        animation.setAttribute("attributeType", "XML")
        animation.setAttribute("attributeName", attribute)
        animation.setAttribute("dur", duration)
        animation.setAttribute("to", to)
        animation.setAttribute("from", from)
        animation.setAttribute("fill", "freeze")
        animationID = playerID + "animation" + attribute
        animation.setAttribute("id", animationID)
        player = document.getElementById(playerID)
        previous_animation = document.getElementById(animationID)
        if (previous_animation != null) {
          player.removeChild(previous_animation)
        }
        player.appendChild(animation)
      }

      function Move() {
        console.log(event.clientX);
        console.log(event.clientY);
        createAnimation("cx", "player1", "2s", document.getElementById("player1").getAttribute("cx"), event.clientX);
        createAnimation("cy", "player1", "2s", document.getElementById("player1").getAttribute("cy"), event.clientY);
      }

    </script>
  </body>

</html>

【问题讨论】:

    标签: javascript animation svg smil


    【解决方案1】:

    有很多问题...

    • Firefox 中没有事件(或者更确切地说是 evt)对象,除非您从调用者那里传入一个。此错误确实显示在 Firefox 浏览器控制台中。
    • Firefox 仍然实现 SVG 1.1 动画,不更新属性值,您需要调用 animVal 来获取值
    • 一旦您制作了一次动画,时间轴现在为 2 秒,因此下次您在文档中为 0 到 2 秒的动画制作动画时,它会直接跳到 2 秒。每次下面的答案有变化时,我都会将时间线重置为 0。

    <!DOCTYPE html>
    <html>
      <body>
        <svg id="canvas" width="800" height="800" onclick="Move(evt)">
          <circle id="player1" cx="300" cy="300" r="40" stroke="blue" stroke-width="4" fill="red">
          </circle>
        </svg>
        <script>
        
          function createAnimation(attribute, playerID, duration, from, to) {
            var animation = document.createElementNS("http://www.w3.org/2000/svg", "animate")
            animation.setAttribute("attributeType", "XML")
            animation.setAttribute("attributeName", attribute)
            animation.setAttribute("dur", duration)
            animation.setAttribute("to", to)
            animation.setAttribute("from", from)
            animation.setAttribute("fill", "freeze")
            animationID = playerID + "animation" + attribute
            animation.setAttribute("id", animationID)
            player = document.getElementById(playerID)
            previous_animation = document.getElementById(animationID)
            if (previous_animation != null) {
              player.removeChild(previous_animation)
            }
            player.appendChild(animation)
          }
    
          function Move(evt) {
            console.log(evt.clientX);
            console.log(evt.clientY);
            createAnimation("cx", "player1", "2s", document.getElementById("player1").cx.animVal.value, evt.clientX);
            createAnimation("cy", "player1", "2s", document.getElementById("player1").cy.animVal.value, evt.clientY);
            document.getElementById("canvas").setCurrentTime(0);
          }
    
        </script>
      </body>
    
    </html>

    【讨论】:

    • 干杯!这完美!您将如何实施多个玩家的射击?每次玩家移动或发射弹丸时重置时钟会影响其他玩家/其他弹丸的移动吗?用document.getElementById("player1").setCurrentTime(0); 替换代码中的document.getElementById("canvas").setCurrentTime(0); 似乎不再起作用。是否可以仅为单个 svg 元素重置计时器?
    • 我尝试使用组标签&lt;g&gt; &lt;/g&gt; 解决问题,这是我的尝试:jsfiddle.net/q2js23t3/3,但没有成功。
    • 整个文档只有一个时间线。您可以改为在当前文档时间开始新动画。如果您仍然遇到问题,请提出一个新问题。
    • 干杯,它有效:jsfiddle.net/q2js23t3/4 我对它的外观很满意,所以“它已经足够好了”,但是 chrome 中有奇怪的“屏幕撕裂状”视觉伪影。它在 Firefox 中看起来更好,除了第一个动画有一个奇怪的视觉伪影(但之后就很流畅了)。
    • 我已经修复了 chrome 中的抖动问题,但没有修复 Firefox 中的抖动问题,只需使用来自 createAnimation 函数的 from 值更新 player1 的当前 cxcy 属性:jsfiddle.net/q2js23t3/6
    猜你喜欢
    • 2013-01-09
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 2011-03-01
    • 2015-03-27
    • 2022-08-13
    相关资源
    最近更新 更多