如何将 html5 canvas 上的点击事件传递给同级 canvas 元素上的事件侦听器
How to pass click event on html5 canvas to event listener on sibling canvas element
我正在构建一个棋盘游戏应用程序,实际的棋盘游戏是在一个 html5 canvas 元素上玩的,具有多层。具体来说,在div中有多个canvas元素占据相同的位置和相同的大小,但使用z-index 属性分层。代码:
<div style="position: relative">
<canvas
id="base_layer"
style="position: absolute; left: 0; top: 0; z-index: 0"
></canvas>
<canvas
id="go_layer"
style="position: absolute; left: 0; top: 0; z-index: 1"
></canvas>
<canvas
id="chess_layer"
style="position: absolute; left: 0; top: 0; z-index: 2"
></canvas>
</div>
它的设置方式,在 canvas 上的任何点击都只注册到国际象棋层。我想将国际象棋层上的点击事件传递给围棋层,但我不知道该怎么做。我曾尝试使用 jQuery 在有人点击国际象棋层时触发 go 层上的点击事件,但该点击事件没有原始点击所具有的位置信息。原始点击:
MouseEvent {isTrusted: true, screenX: 452, screenY: 228, clientX: 452, clientY: 157, …}
altKey: false
bubbles: true
button: 0
buttons: 0
cancelBubble: false
cancelable: true
clientX: 452
clientY: 157
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 1
eventPhase: 0
fromElement: null
isTrusted: true
layerX: 444
layerY: 149
metaKey: false
movementX: 0
movementY: 0
offsetX: 445
offsetY: 149
pageX: 452
pageY: 157
path: (6) [canvas#chess_layer, div, body, html, document, Window]
relatedTarget: null
returnValue: true
screenX: 452
screenY: 228
shiftKey: false
sourceCapabilities: InputDeviceCapabilities {firesTouchEvents: false}
srcElement: canvas#chess_layer
target: canvas#chess_layer
timeStamp: 2274.085000004561
toElement: canvas#chess_layer
type: "click"
view: Window {window: Window, self: Window, document: document, name: "", location: Location, …}
which: 1
x: 452
y: 157
__proto__: MouseEvent
触发点击兄弟图层:
MouseEvent {isTrusted: false, screenX: 0, screenY: 0, clientX: 0, clientY: 0, …}
altKey: false
bubbles: true
button: 0
buttons: 0
cancelBubble: false
cancelable: true
clientX: 0
clientY: 0
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 0
eventPhase: 0
fromElement: null
isTrusted: false
layerX: -8
layerY: -8
metaKey: false
movementX: 0
movementY: 0
offsetX: 0
offsetY: 0
pageX: 0
pageY: 0
path: (6) [canvas#go_layer, div, body, html, document, Window]
relatedTarget: null
returnValue: true
screenX: 0
screenY: 0
shiftKey: false
sourceCapabilities: null
srcElement: canvas#go_layer
target: canvas#go_layer
timeStamp: 2277.075000005425
toElement: canvas#go_layer
type: "click"
view: Window {window: Window, self: Window, document: document, name: "", location: Location, …}
which: 1
x: 0
y: 0
__proto__: MouseEvent
请注意,对于触发的点击,event.clientX = event.clientY = 0,这与原始点击不同。如何将原始点击事件完全传递给另一层,而不丢失信息?我用来触发 go 层中的点击事件的代码是(这发生在国际象棋层的点击事件监听器中):
// Since this is the top layer, pass click event to go_layer
var gevent = jQuery.Event("click");
gevent.clientX = event.clientX;
gevent.clientY = event.clientY;
$("canvas#go_layer").trigger(gevent);
console.log(event);
我无法告诉您为什么您的 JQuery 方法会失败。尽管如此,您可以使用普通 JavaScript 做完全相同的事情,但它实际上会起作用。
基本上let event=document.createEvent('Event');
是用来创建一个事件的。因为这是一个 click 事件,我们需要调用
event.initEvent('click', true, true);
关于新创建的事件。与您的 JQuery 方法一样,这个新事件不是原始事件的克隆,因此我们需要手动复制我们感兴趣的所有属性。
event.clientX = e.clientX;
event.clientY = e.clientY;
之后只需使用 dispatchEvent()
在所需对象上触发事件,例如
document.getElementById("go_layer").dispatchEvent(event);
这是一个例子:
function canvasClicked(e) {
if (e.target.id == "chess_layer") {
let event = document.createEvent('Event');
event.initEvent('click', true, true);
event.clientX = e.clientX;
event.clientY = e.clientY;
document.getElementById("go_layer").dispatchEvent(event);
}
console.log(e.target.id, e.clientX, e.clientY);
}
document.getElementById("chess_layer").addEventListener("click", canvasClicked);
document.getElementById("go_layer").addEventListener("click", canvasClicked);
canvas {
border: 1px solid black;
}
<div style="position: relative">
<canvas id="base_layer" style="position: absolute; left: 0; top: 0; z-index: 0"></canvas>
<canvas id="go_layer" style="position: absolute; left: 0; top: 0; z-index: 1"></canvas>
<canvas id="chess_layer" style="position: absolute; left: 0; top: 0; z-index: 2"></canvas>
</div>
我正在构建一个棋盘游戏应用程序,实际的棋盘游戏是在一个 html5 canvas 元素上玩的,具有多层。具体来说,在div中有多个canvas元素占据相同的位置和相同的大小,但使用z-index 属性分层。代码:
<div style="position: relative">
<canvas
id="base_layer"
style="position: absolute; left: 0; top: 0; z-index: 0"
></canvas>
<canvas
id="go_layer"
style="position: absolute; left: 0; top: 0; z-index: 1"
></canvas>
<canvas
id="chess_layer"
style="position: absolute; left: 0; top: 0; z-index: 2"
></canvas>
</div>
它的设置方式,在 canvas 上的任何点击都只注册到国际象棋层。我想将国际象棋层上的点击事件传递给围棋层,但我不知道该怎么做。我曾尝试使用 jQuery 在有人点击国际象棋层时触发 go 层上的点击事件,但该点击事件没有原始点击所具有的位置信息。原始点击:
MouseEvent {isTrusted: true, screenX: 452, screenY: 228, clientX: 452, clientY: 157, …}
altKey: false
bubbles: true
button: 0
buttons: 0
cancelBubble: false
cancelable: true
clientX: 452
clientY: 157
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 1
eventPhase: 0
fromElement: null
isTrusted: true
layerX: 444
layerY: 149
metaKey: false
movementX: 0
movementY: 0
offsetX: 445
offsetY: 149
pageX: 452
pageY: 157
path: (6) [canvas#chess_layer, div, body, html, document, Window]
relatedTarget: null
returnValue: true
screenX: 452
screenY: 228
shiftKey: false
sourceCapabilities: InputDeviceCapabilities {firesTouchEvents: false}
srcElement: canvas#chess_layer
target: canvas#chess_layer
timeStamp: 2274.085000004561
toElement: canvas#chess_layer
type: "click"
view: Window {window: Window, self: Window, document: document, name: "", location: Location, …}
which: 1
x: 452
y: 157
__proto__: MouseEvent
触发点击兄弟图层:
MouseEvent {isTrusted: false, screenX: 0, screenY: 0, clientX: 0, clientY: 0, …}
altKey: false
bubbles: true
button: 0
buttons: 0
cancelBubble: false
cancelable: true
clientX: 0
clientY: 0
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 0
eventPhase: 0
fromElement: null
isTrusted: false
layerX: -8
layerY: -8
metaKey: false
movementX: 0
movementY: 0
offsetX: 0
offsetY: 0
pageX: 0
pageY: 0
path: (6) [canvas#go_layer, div, body, html, document, Window]
relatedTarget: null
returnValue: true
screenX: 0
screenY: 0
shiftKey: false
sourceCapabilities: null
srcElement: canvas#go_layer
target: canvas#go_layer
timeStamp: 2277.075000005425
toElement: canvas#go_layer
type: "click"
view: Window {window: Window, self: Window, document: document, name: "", location: Location, …}
which: 1
x: 0
y: 0
__proto__: MouseEvent
请注意,对于触发的点击,event.clientX = event.clientY = 0,这与原始点击不同。如何将原始点击事件完全传递给另一层,而不丢失信息?我用来触发 go 层中的点击事件的代码是(这发生在国际象棋层的点击事件监听器中):
// Since this is the top layer, pass click event to go_layer
var gevent = jQuery.Event("click");
gevent.clientX = event.clientX;
gevent.clientY = event.clientY;
$("canvas#go_layer").trigger(gevent);
console.log(event);
我无法告诉您为什么您的 JQuery 方法会失败。尽管如此,您可以使用普通 JavaScript 做完全相同的事情,但它实际上会起作用。
基本上let event=document.createEvent('Event');
是用来创建一个事件的。因为这是一个 click 事件,我们需要调用
event.initEvent('click', true, true);
关于新创建的事件。与您的 JQuery 方法一样,这个新事件不是原始事件的克隆,因此我们需要手动复制我们感兴趣的所有属性。
event.clientX = e.clientX;
event.clientY = e.clientY;
之后只需使用 dispatchEvent()
在所需对象上触发事件,例如
document.getElementById("go_layer").dispatchEvent(event);
这是一个例子:
function canvasClicked(e) {
if (e.target.id == "chess_layer") {
let event = document.createEvent('Event');
event.initEvent('click', true, true);
event.clientX = e.clientX;
event.clientY = e.clientY;
document.getElementById("go_layer").dispatchEvent(event);
}
console.log(e.target.id, e.clientX, e.clientY);
}
document.getElementById("chess_layer").addEventListener("click", canvasClicked);
document.getElementById("go_layer").addEventListener("click", canvasClicked);
canvas {
border: 1px solid black;
}
<div style="position: relative">
<canvas id="base_layer" style="position: absolute; left: 0; top: 0; z-index: 0"></canvas>
<canvas id="go_layer" style="position: absolute; left: 0; top: 0; z-index: 1"></canvas>
<canvas id="chess_layer" style="position: absolute; left: 0; top: 0; z-index: 2"></canvas>
</div>