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。

动画值更改时似乎不会发出事件,即使是粗粒度(即在给定动画完成百分比的情况下(也不会发出事件。

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

以下概念验证独立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>

参考

该解决方案基于SO问题和以下标准文件:

  • animateMotion元素
  • SVG-IDL
  • SVG最小长度

替代方案

anime.js似乎是一个动画库,可以满足问题中列出的需求(参见本节(,对于具有坚实js背景的作者来说是一个部分(我与该库和作者都没有任何关系(。

最新更新