从 PIXI.js 中的兄弟或父 DOM 元素捕获鼠标事件

Capture mouse events from sibling or parent DOM element in PIXI.js

我想在 两个 层上捕获鼠标事件:PIXI 的 canvas 和覆盖层 div。我有以下类型的 HTML 设置,其中 div.overlay 高于 canvas.pixi:

<div class="parent">
  <canvas class="pixi"></canvas>
  <div class="overlay"></div>
</div>

canvas 位于顶部时,PIXI 交互工作正常,但当 canvas 被 div.overlay 覆盖时,我无法捕获任何事件。

我发现 setTargetElement 似乎可以让我们为捕获元素定义 DOM 元素,我尝试像这样使用它:

const renderer = PIXI.autoDetectRenderer(...);
renderer.plugins.interaction.setTargetElement(document.querySelector('.overlay'));

使用这种技术我能够捕获 mousemove 事件,但不幸的是 clickmousedown 等都不起作用。

我还尝试复制在 div.overlay 上捕获的原始事件,并复制 ans dispatch 在 canvas 上的事件,如下所示,但这也不起作用。

document.querySelector('.overlay').addEventListener('mousedown', (e) => {
  const eventCopy = document.createEvent('MouseEvents');
  eventCopy.initMouseEvent(
    e.type, e.bubbles, e.cancelable, e.view,
    e.detail, e.pageX || e.layerX,
    e.pageY || e.layerY, e.clientX,
    e.clientY, e.ctrlKey, e.altKey, e.shiftKey,
    e.metaKey, e.button, e.relatedTarget
  );

  document.querySelector('.pixi').dispatchEvent(eventCopy);
});

有没有什么方法可以在重叠的 DOM 元素上捕获鼠标事件并将事件传递给 PIXI?

为什么?

我想与 PIXI 元素交互,同时能够利用 D3 的缩放和画笔功能,目前正在叠加层上处理 div。

更新和代码示例

我成功地转发了事件,除了点击事件之外,所有事件都由 PIXI 注册。可以通过重新触发 pointerdownpointerup 事件来手动触发点击事件。查看 https://jsfiddle.net/v3chhhjk/1/

如果您只需要通过叠加层传递事件 - 使用 css pointer-events: none;.
此处有更多详细信息:https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

一种可能的解决方案是捕获父元素中的所有事件并将其遍历回子元素。像这样。这是为点击完成的,同样适用于 mousemove。

function traverseEventToChild(e){
 if(e.type="click"){
   const eventCopy = document.createEvent('MouseEvents');
   eventCopy.initMouseEvent(
      e.type, e.bubbles, e.cancelable, e.view,
      e.detail, e.pageX || e.layerX,
      e.pageY || e.layerY, e.clientX,
      e.clientY, e.ctrlKey, e.altKey, e.shiftKey,
      e.metaKey, e.button, e.relatedTarget
   );
    console.log('parent handler');
   document.querySelector('.pixi').dispatchEvent(eventCopy);
  }
}

function piximousemove(e){
 console.log('pixi click');
  e.stopPropagation();
}

function overlaymousemove(e){
 console.log('overlay click');
}
document.querySelector('.pixi').onclick = piximousemove;
document.querySelector('.overlay').onclick = overlaymousemove;
<div class="parent" id='parent' onclick="traverseEventToChild(event);">
  <canvas class="pixi" id='canvas'>pixi</canvas>
  <div class="overlay" id='overlay'>overlay</div>
</div>

问题是 DOM 是分层的。 Here's an old issue about the exact same thing。事实证明,您不能简单地将事件传播给兄弟姐妹,只能传播 parents 和 children。我建议将您的 canvas 放在 .overlay 内,然后您既可以捕获它又可以在冒泡阶段捕获它,具体取决于您是想在 canvas 之前还是之后处理它们。

我认为下面应该按预期工作。

HTML:

<div id="parent">
    <div id="overlay">
        <canvas></canvas>
    </div>
</div>

示例 JS:

(function() {
    let parent = document.getElementById('parent');
    let overlay = document.getElementById('overlay');
    let canvas = document.querySelector('canvas');

    parent.addEventListener('click', e => console.log('parent capture'), true);
    overlay.addEventListener('click', e => console.log('overlay capture'), true);
    canvas.addEventListener('click', e => console.log('canvas capture'), true);
    canvas.addEventListener('click', e => console.log('canvas bubble'), false);
    overlay.addEventListener('click', e => console.log('overlay bubble'), false);
    parent.addEventListener('click', e => console.log('parent bubble'), false);

})()

我通过克隆事件和重建 [=17] 来为 mouseovermouseoutmousedownmouseupclick 事件工作=] 事件来自 mousedownmouseup 事件。当从事件层克隆事件时,除了 click 事件之外的所有事件都可以开箱即用,但不知何故不会触发点击事件。

所以给定以下 HTML 结构:

<div id="parent">
  <canvas id="pixi"></canvas>
  <div id="overlay"></div>
</div>

我听到了一堆这样的事件:

const overlay = document.getElementById('overlay');

overlay.addEventListener('pointerdown', forwardDown);
overlay.addEventListener('pointerup', forwardUp);
overlay.addEventListener('pointermove', forward);
overlay.addEventListener('pointerover', forward);
overlay.addEventListener('pointerout', forward);

然后转发/克隆事件:

const canvas = document.getElementById('pixi');
let mousedown = false;

const clone = e => new e.constructor(e.type, e);
const forward = (e) => { canvas.dispatchEvent(clone(e)); };
const forwardDown = (e) => { mousedown = true; forward(e); };
const forwardUp = (e) => {
  forward(e);
  if (mousedown) console.log('It\'s a click!');
  mousedown = false;
};

该事件也可以发送到其他地方,例如被 D3 识别。

演示https://jsfiddle.net/v3chhhjk/3/

左上角演示了使用PIXI直接捕获事件时的工作原理。右上角显示克隆事件时的问题。左下角显示了一个奇怪的行为,重新触发相同的事件实际上使 PIXI 识别点击事件,最后,右下角。

对于访问此页面但希望 PIXI 成为叠加层的人,在仍然交互式的底层之上。然后你仍然可以使用来自@F Lekschas 的例子稍作修改。

在父级上设置指针事件:none,然后在底层上设置指针事件:全部,然后将事件从底层转发到 PIXI canvas,如示例所示。

我正在为这个而烦恼。我 运行 遇到了将事件从父级转发到底层的各种问题,但是将事件从底层转发到 PIXI canvas 就像一个魅力。