I'm trying to build a 3D piano using three.js; see the code snippet below.
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>
If you play around with the piano keys long enough, you'll notice that sometimes the fork link in the top-right corner hijacks mouse clicks made on the keys (which are inside a <canvas>
), leading to buggy behaviour. In case that's not clear, here's a GIF demonstrating this bug:
I've yet to determine what the cause of this is, and am having a hard time reproducing it consistently (sometimes you just have to click the keys for a while and wait for it to happen). I think it has something to do with the position: absolute
of the link, or maybe the z-index
/ tabindex
. But tweaking these values hasn't solved the problem so far.
Does anyone know what could be causing this and how I can fix it?
UPDATE: I've found that setting .fork img {
to .fork {
in the stylesheet reproduces the bug more often. Hopefully this helps someone figure out a solution.
答案 0 :(得分:0)
好吧,我发现将user-select: none;
添加到.fork
的CSS会修复该错误。但它更多的是一种解决方法,而不是直接解决问题的方法,所以我不会接受这个作为答案。我希望其他人可以使用适当的解决方案...