【发布时间】: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>
如果您使用钢琴键的时间足够长,您会注意到有时右上角的叉形链接会劫持对键(位于 <canvas> 内)的鼠标点击,从而导致错误行为.如果不清楚,这里有一个演示这个错误的 GIF:
我还没有确定这是什么原因造成的,并且很难始终如一地重现它(有时您只需要按一下键并等待它发生)。我认为这与链接的position: absolute 或z-index / tabindex 有关。但到目前为止,调整这些值并没有解决问题。
有谁知道这可能是什么原因以及我该如何解决?
更新:我发现在样式表中将.fork img { 设置为.fork { 会更频繁地重现该错误。希望这可以帮助某人找到解决方案。
【问题讨论】:
-
@Luke 你的 sn-p 没有错误
-
你可以让事件监听器只作用于“.app”的子元素,而不是整个窗口。这更像是一种解决方法,它不能解释行为。
-
不是三个.js 的问题
标签: javascript html canvas three.js anchor