【问题标题】:Why is an <a> stealing mouse clicks from a <canvas>?为什么 <a> 会从 <canvas> 窃取鼠标点击?
【发布时间】:2018-03-15 10:02:58
【问题描述】:

我正在尝试使用 three.js 构建一个 3D 钢琴;参见下面的代码 sn-p。

let renderer, camera, scene, light, keys, selectedKey;

init();
render();

function init() {
  renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.querySelector(".app").appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight);
  camera.position.z = 400;

  scene = new THREE.Scene();

  light = new THREE.SpotLight("#777777");
  light.position.y = 800;
  scene.add(light);
  
  keys = new THREE.Group();
  for (let i = 0; i < 15; i++) {
    let key = new THREE.Mesh();
    key.geometry = new THREE.BoxGeometry(30, 30, 130);
    key.material = new THREE.MeshPhysicalMaterial({ color: "#dddddd", emissive: "#888888" });
    key.position.x = (key.geometry.parameters.width + 2) * i;
    key.rotation.x = Math.PI / 4;
    keys.add(key);
  }
  scene.add(keys);
  
  // Center the keys.
  new THREE.Box3().setFromObject(keys).getCenter(keys.position).multiplyScalar(-1); 

  // Add mouse listeners.
  window.addEventListener("mousedown", onMouseDown);
  window.addEventListener("mouseup", onMouseUp);
  window.addEventListener("mousemove", onMouseMove);
  renderer.domElement.addEventListener("mouseleave", onMouseLeave);
}

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

function onMouseDown(event) {
  unpressKey(); // In case the previous mousedown event wasn't followed by a mouseup, force a key unpress now.
  if (event.buttons !== 1) return; // Only accept left mouse button clicks.
  selectedKey = keys.children.find(key => isKeyAtCoord(key, event.clientX, event.clientY));
  pressKey();
}

function onMouseUp(event) {
  unpressKey();
}

function onMouseMove(event) {
  let key = keys.children.find(key => isKeyAtCoord(key, event.clientX, event.clientY));

  renderer.domElement.style.cursor = key ? "pointer" : null;

  // If a key was previously selected and the mouse has moved to another key, make that
  // the new "selected" key. This allows keys to be pressed in a click+drag manner.
  if (selectedKey && key && selectedKey !== key) {
    unpressKey();
    selectedKey = key;
    pressKey();
  }
}

function onMouseLeave(event) {
  unpressKey(); // The mouse left the canvas, so cancel the last click.
}

function pressKey() {
  if (selectedKey) {
    selectedKey.position.y -= selectedKey.geometry.parameters.height / 2;
  }
}

function unpressKey() {
  if (selectedKey) {
    selectedKey.position.y += selectedKey.geometry.parameters.height / 2;
    selectedKey = null;
  }
}

function isKeyAtCoord(key, x, y) {
  x = (x / renderer.domElement.clientWidth) * 2 - 1;
  y = -(y / renderer.domElement.clientHeight) * 2 + 1;
  let raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
  return raycaster.intersectObject(key).length > 0;
}
body, .app {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: #ff6600;
}

.fork img {
  position: absolute;
  top: 0;
  right: 0;
  border: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.js">
</script>

<div class="app">
</div>

<a class="fork" href="https://github.com">
  <img src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png">
</a>

如果您使用钢琴键的时间足够长,您会注意到有时右上角的叉形链接会劫持对键(位于 &lt;canvas&gt; 内)的鼠标点击,从而导致错误行为.如果不清楚,这里有一个演示这个错误的 GIF:

我还没有确定这是什么原因造成的,并且很难始终如一地重现它(有时您只需要按一下键并等待它发生)。我认为这与链接的position: absolutez-index / tabindex 有关。但到目前为止,调整这些值并没有解决问题。

有谁知道这可能是什么原因以及我该如何解决?

更新:我发现在样式表中将.fork img { 设置为.fork { 会更频繁地重现该错误。希望这可以帮助某人找到解决方案。

【问题讨论】:

  • @Luke 你的 sn-p 没有错误
  • 你可以让事件监听器只作用于“.app”的子元素,而不是整个窗口。这更像是一种解决方法,它不能解释行为。
  • 不是三个.js 的问题

标签: javascript html canvas three.js anchor


【解决方案1】:

好吧,我发现将user-select: none; 添加到.fork 的CSS 修复了该错误。但这更像是一种解决方法,而不是直接解决问题的方法,所以我不会接受这个作为答案。我希望其他人可以提出适当的解决方案...

【讨论】:

    猜你喜欢
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 2011-04-20
    • 2012-04-13
    • 1970-01-01
    • 2012-02-23
    相关资源
    最近更新 更多