JavaScript-SVG动画位置更改事件

时间:2018-07-13 18:24:53

标签: javascript svg

我正在尝试使用SVG和普通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背景,但这是我第一次涉足SVG。

1 个答案:

答案 0 :(得分:2)

似乎没有改变动画值时发出的事件,甚至没有粗糙的粒度(即以给定的动画完成百分比)。

但是,可以查询当前的动画值,因此以固定间隔调用伪处理程序可以在合理的范围内跟踪动画的进度。

以下概念验证的独立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背景的作者(我与该库没有任何关联)还是作者)。