z-index:-1;
コードで#backgroundとを設定しますdisplay:absolute;
。つまり、これは体のz レイヤーの背後にあり、マウス イベントは体または上のレイヤー内の他のものを対象とします。
本文またはすべての要素を設定することもできますが、それは後でサイトに含まれる他のコードで悪いことになる可能性がありpointer-events:none;
ます. #containerと#container>canvasのように、他のカバー要素をより高い z-index で絶対的に配置することをお勧めします。
DOM イベントが伝播するパスを確認してください: http://www.w3.org/TR/DOM-Level-3-Events/
キャプチャ フェーズでは、イベントは最初にビューに伝播され、次に html と body に伝播され、その後、マウス カーソルの下に表示されているターゲットに到達します。バブリング フェーズでは、伝搬は逆方向にビューに戻ります。
レンダリングされたシーン オブジェクトは、この DOM イベント パスにはありません。ドキュメント イベント リスナーでヒットをレイトレーシングしました。伝播が #background 要素に到達する前にこれを行い、イベントが処理されることがわかっている場合はどこかで安全にします。を試しpreventDefault()
ました。残念ながら、mousemove イベントはキャンセルできないため、これは効果がありません。後で呼び出されるイベント リスナーpreventedDefault
が取得しfalse
ます。の意味は、ユーザー エージェントによる伝播後にpreventDefault()
実行される既定の操作を防止することです。たとえば、ダブルクリック後にマウス ポインターの下にある単語をマークします。デフォルトの操作を実行する必要がある場合、イベントがすでに処理されていることを他のリスナーに伝えるために使用することはできません。preventDefault()
Event のカスタム プロパティを true に設定できます。少なくとも firefox では動作しますが、ホスト オブジェクトは W3C によって厳密に指定されていません。これにより、他のブラウザまたは将来的に何らかのエラーが発生する可能性があります。stopPropagation()
他のリスナーを呼び出す必要がない場合に使用できます。状況によっては、一部の JavaScript フレームワークと組み合わせて、望ましくない動作やバグが発生する可能性があります。
もう 1 つの方法は、すべてのイベント リスナーがアクセスできるスコープに変数を設定することです。たとえば、グローバル スコープまたはカプセル化された無名関数などです。これは、最後に処理されたイベントを保持でき、伝播が完了するまで変更されません (次のイベントは前に発生しません)。
レイトレーサーがシーン オブジェクトにヒットしない場合は、ドキュメントのリスナーで#backgroundを対象とするイベントを処理することもできます。Event.target
マウスイベントがヒットした最上位の DOM 要素を保持します。
さまざまなアプローチのデモンストレーションを含む変更されたコード:
<!DOCTYPE html>
<html>
<head>
<title>events passthrough</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
body {
font-family: Monospace;
margin: 0px;
overflow: hidden;
}
div#background {
position: absolute;
top: 40px;
left: 40px;
width: 100px;
height: 100px;
background-color: pink;
/*z-index: -1; /* this is behind the body */
}
#container>canvas
{ position: absolute;
z-index: 100;
}
/* Explicitly disable mouse events on covering element. */
/* If z-index of background object is below zero then also disable body */
/* body, */
#container, #container canvas
{ pointer-events:none;
}
/* but let enabled all other elements */
*
{ pointer-events:auto;
}
</style>
</head>
<body>
<script type="text/javascript" src="https://mrdoob.github.io/three.js/build/three.min.js"></script>
<script type="text/javascript" src="https://mrdoob.github.io/three.js/examples/js/libs/stats.min.js"></script>
<div id="background"></div>
<div id="container"></div>
<script type="text/javascript">
var lastHandledEvent;
var container, stats;
var camera, scene, projector, renderer;
var particleMaterial;
var objects = [];
// don't run DOM relevant scripts before construction of DOM is guaranteed
document.addEventListener("DOMContentLoaded", function()
{
init();
animate();
}, false);
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 10, 300, 500 );
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry( 100, 100, 100 );
for ( var i = 0; i < 10; i ++ ) {
var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, opacity: 0.5 } ) );
object.position.x = Math.random() * 800 - 400;
object.position.y = Math.random() * 800 - 400;
object.position.z = Math.random() * 800 - 400;
object.scale.x = Math.random() * 2 + 1;
object.scale.y = Math.random() * 2 + 1;
object.scale.z = Math.random() * 2 + 1;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
scene.add( object );
objects.push( object );
}
var PI2 = Math.PI * 2;
particleMaterial = new THREE.SpriteCanvasMaterial( {
color: 0x000000,
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 0.5, 0, PI2, true );
context.fill();
}
} );
projector = new THREE.Projector();
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( window.innerWidth, window.innerHeight );
// renderer.domElement.style.position = 'absolute'; // is done in CSS
// renderer.domElement.style.zIndex = 100; // is done in CSS
container.appendChild( renderer.domElement );
// register document mousemove in capturing phase
// if you want to use another handlers subsequently
document.addEventListener('mousemove', onDocumentMouseMove, true );
document.querySelector('#background').addEventListener('mousemove', onMouseMove, false);
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var background = document.getElementById('background');
function onDocumentMouseMove( event )
{
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 )
{
intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );
//event.preventDefault(); // mousemove is not cancelable
// extending event objects works at least in Firefox, not sure if crossbrowser combatible
// always be careful when extending DOM
event.handled = true; // add custom property
lastHandledEvent = event; // another way: store in a variable accessible by all handlers
// to remember this one was the last handled event
console.log('event marked as handled in document listener');
//event.stopPropagation(); // or could stop propagation, however,
// often not a good praxis in conjuction with frameworks
}
else if(event.target === background)
console.log('background could be handled in document listener');
}
function onMouseMove( event )
{
// if(event.defaultPrevented // mousemove not cancable, always false
if(event.handled) // TODO: check crossbrowser compatibility
// of custom properties on event objects.
// In doubt use a var outside the functions.
console.log('other listener: event.handled is: '+event.handled);
if(lastHandledEvent === event) // the safer way: use variable accessible
{
console.log('NOT handling event in other listener');
return;
}
console.log(event.target, '...or handled in other listener');
event.target.style.backgroundColor = '#'+('00000' + (Math.random() * 0xffffff).toString(16)).slice(-6);
}
function animate() {
requestAnimationFrame( animate );
render();
}
var radius = 600;
var theta = 0;
function render() {
theta += 0.1;
camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
</body>
</html>