代码之家  ›  专栏  ›  技术社区  ›  David

javascript-svg动画位置更改事件

  •  0
  • David  · 技术社区  · 6 年前

    我试着用svg和vanilla javascript做一个简单的乒乓球游戏。我遇到的问题是,如何绑定事件以确定球的位置何时移动?例如,有没有类似的东西:

    document.getElementById("ball").getAttribute("cx").onChange = ...;
    

    我当前生成的代码是:

    window.onload = function() {
      
    }
    
    window.onkeydown = function(e){
      /*
      Player 1:
      up    -> 38
      down  -> 40
      */
      var increment = 0;
      
      if (e.keyCode === 38 || e.keyCode === 40) {
        increment = 5;
        
        if (e.keyCode === 38) {
          increment = -increment;
        }
      }
    
      document.getElementById("paddle1").setAttribute("y", parseFloat(document.getElementById("paddle1").getAttribute("y")) + increment);
    };
    
    window.onmousemove = function(e) {
      // Player2: Based on the y position of the mouse
      document.getElementById("paddle2").setAttribute("y", e.clientY);
    }
    <svg width="576px" height="300px">
      <!-- background -->
      <rect x="0" y="0" width="576" height="300" stroke="black" stroke-width="1" />
      
      <!-- ball -->
      <circle cx="0" cy="0" r="5" fill="white" id="ball">
        <animateMotion path="M 0 150 H 576 Z" dur="5s" repeatCount="indefinite" />
      </circle>
      
      <!-- mid-point -->
      <line stroke-dasharray="5, 10" x1="287.5" y1="1" x2="287.5" y2="300"  stroke="white" stroke-width="1" />
      
      <!-- scores -->
      <text x="261" y="27" font-family="monospace" font-size="22px" fill="white" id="score1">0</text>
      <text x="298" y="27" font-family="monospace" font-size="22px" fill="white" id="score2">0</text>
    		  
      <!-- paddles -->
      <rect x="10" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle1" />
      <rect x="561" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle2" />
      
    </svg>

    请记住,虽然我有相当广泛的javascript背景,但这是我第一次跳转到svgs。

    1 回复  |  直到 6 年前
        1
  •  2
  •   collapsar    6 年前

    在动画值发生变化时,似乎没有事件发出,即使粒度较粗(即动画完成的给定百分比)。

    但是,可以查询当前动画值,因此定期调用伪处理程序可以在合理的限制内跟踪动画的进度。

    以下概念证明独立SVG补充并修改了问题中的代码:

    • 定义一个间隔处理程序,将球的当前X位置写入控制台
    • 在onload处理程序中设置间隔处理程序
    • 使用 animate 要素
    <?xml version="1.0" encoding="UTF-8"?>
    <svg
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 1000 500"
        width="1150px" height="600px"
    >
        <script type="text/javascript">
            function cb_ball ( pdom_ball ) {
                console.log ( `attr 'cx': '${pdom_ball.cx.animVal.value}'.`);
            } // cb_ball
    
            window.onload = function() {
                let dom_ball = document.getElementById("ball")
                  ;
    
                setInterval ( () => { cb_ball ( dom_ball ); }, 100 );
            }
    
            window.onkeydown = function(e){
                /*
                    Player 1:
                        up    -> 38
                        down  -> 40
                */
                var increment = 0;
    
                if (e.keyCode === 38 || e.keyCode === 40) {
                    increment = 5;
    
                    if (e.keyCode === 38) {
                        increment = -increment;
                    }
                }
    
                document.getElementById("paddle1").setAttribute("y", parseFloat(document.getElementById("paddle1").getAttribute("y")) + increment);
            };
    
            window.onmousemove = function(e) {
                // Player2: Based on the y position of the mouse
                document.getElementById("paddle2").setAttribute("y", e.clientY);
            }
        </script>
    
        <!-- background -->
        <rect x="0" y="0" width="576" height="300" stroke="black" stroke-width="1" />
    
        <!-- ball -->
        <circle cx="0" cy="150" r="5" fill="white" id="ball">
            <!-- was: animateMotion path="M 0 150 H 576 Z" dur="5s" repeatCount="indefinite" /-->
            <animate id="ball-animation"
                attributeName="cx"
                attributeType="XML"
                values = "0;285;570;285;0"
                keyTimes="0;0.25;0.5;0.75;1"
                calcMode="linear"
                dur="5s"
                repeatCount="indefinite"
            />
        </circle>
    
        <!-- mid-point -->
        <line stroke-dasharray="5, 10" x1="287.5" y1="1" x2="287.5" y2="300"  stroke="white" stroke-width="1" />
    
        <!-- scores -->
        <text x="261" y="27" font-family="monospace" font-size="22px" fill="white" id="score1">0</text>
        <text x="298" y="27" font-family="monospace" font-size="22px" fill="white" id="score2">0</text>
    
        <!-- paddles -->
        <rect x="10" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle1" />
        <rect x="561" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle2" />
    </svg>
    

    工具书类

    解决方案基于 this SO question 以及以下标准文件:

    选择

    anime.js 似乎是一个动画库,可以满足问题中概述的需要(参见 this section ,对于有着坚实js背景的作者来说(我与库和作者都没有关系)。