Upon waking up the following morning, I immediately identified the root of the problem, which stemmed from a flaw in the code's logic:
if (mouse.type === 'mousemove')
, with further conditionals for different event types. Here is the revised code, with some refactoring to enhance readability:
var ray = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var INTERSECTED; // Object closest to the camera
function onMouse( event ) {
event.preventDefault();
// Calculate mouse position in normalized device coordinates (-1 to +1) for both components
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
mouseEventHandler( event /*, transformGraphElement, unTransformGraphElement */ );
}
function listenFor(){
document.addEventListener( 'click', onMouse, false );
document.addEventListener( 'mousemove', onMouse, false );
document.addEventListener( 'mousedown', onMouse, false );
document.addEventListener( 'dblclick', onMouse, false )
document.addEventListener( 'wheel', onMouse, false );
document.addEventListener( 'contextmenu', onMouse, false );
}
listenFor();
/* ... */
function render() {
requestAnimationFrame( render );
renderer.render(scene, entities.cameras.perspCamera );
}
function mouseEventHandler( event /* , fn, revFn */ ){
// Update the picking ray with the camera and mouse position
ray.setFromCamera( mouse, entities.cameras.perspCamera );
// Calculate objects intersecting the picking ray
var intersects = ray.intersectObjects( scene.children );
// If there's at least one intersected object...
if ( intersects && intersects[0] && intersects[0].object ){
// Check for mouse move event and ensure INTERSECTED object exists and remains the same
if ( event.type === 'mousemove' ){
if ( intersects[ 0 ].object != INTERSECTED ){
if ( INTERSECTED ) {
unTransformGraphElementOnMouseOut( INTERSECTED, event );
}
INTERSECTED = intersects[ 0 ].object;
transformGraphElementOnMouseOver( INTERSECTED, event );
}
}
// Handle double click mouse event
if ( event.type === 'dblclick' ){
if ( intersects[ 0 ].object === INTERSECTED ){
transformGraphElementOnSelect( INTERSECTED, event );
}
if ( intersects[ 0 ].object !== INTERSECTED ){
if ( INTERSECTED )
unTransformGraphElementOnUnselect( INTERSECTED, event );
}
}
INTERSECTED && console.log( 'INTERSECTED.isGraphElement: ', INTERSECTED.isGraphElement, 'MouseEvent: ', event.type );
}
}
function transformGraphElementOnMouseOver( obj, event ){
if ( obj.isGraphElement ) { obj.referent.transformOnMouseOver(); }
}
function unTransformGraphElementOnMouseOut( obj, event ){
if ( obj.isGraphElement ) { obj.referent.transformOnMouseOut(); }
}
function transformGraphElementOnSelect( obj, event ){
if ( obj.isGraphElement ) { obj.referent.transformOnDblClick(); }
}
function unTransformGraphElementOnUnselect( obj, event ){
if ( obj.isGraphElement ) { obj.referent.unTransformOnDblClick(); }
}
While certain issues in the logic of mouseEventHandler()
remain, the fundamental problem has been addressed. Additionally, some refactoring has been carried out for improved clarity:
- Eliminated the need to include
event.type
in mouse
.
- Moved the call to
mouseEventHandler()
from render()
to onMouse()
, ensuring events are registered only once.
- Removed the 'fn'/'revFn' callbacks in
mouseEventHandler()
for simplification.
- Removed
event
as a parameter for the transform functions.
I hope this revised version proves helpful to others.