@masatomakino/threejs-interactive-object
    Preparing search index...

    Class MouseEventManager

    Central event dispatcher for handling pointer interactions in Three.js scenes.

    MouseEventManager serves as the core interaction management system for Three.js applications, providing unified pointer interaction handling across mouse, touch, and pen input devices. It uses raycasting to detect object intersections and manages event distribution to interactive objects through a performance-optimized pipeline.

    The manager listens to DOM pointer events, performs raycasting to identify intersected objects, traverses parent hierarchies to find IClickableObject3D implementations, and delegates events to appropriate ButtonInteractionHandler instances.

    Performance Optimizations:

    • Throttling: RAFTicker-based throttling prevents excessive raycasting (33ms default)
    • Target Filtering: Configurable target arrays limit intersection testing scope
    • Recursive Control: Hierarchy traversal can be disabled for pre-registered objects

    Multi-Viewport Support: Compatible with Three.js WebGLRenderer.setViewport() for applications rendering multiple scenes or cameras to different canvas regions. The manager determines the corresponding viewport for each pointer event and processes only relevant objects.

    import { MouseEventManager, ClickableMesh } from '@masatomakino/threejs-interactive-object';
    import { Scene, PerspectiveCamera, WebGLRenderer, Vector4 } from 'three';

    // Basic setup
    const scene = new Scene();
    const camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new WebGLRenderer();
    const canvas = renderer.domElement;

    // Create interaction manager
    const mouseManager = new MouseEventManager(scene, camera, canvas);

    // Advanced setup with optimizations and viewport constraint
    const optimizedManager = new MouseEventManager(scene, camera, canvas, {
    throttlingTime_ms: 16, // Higher frequency for responsive interactions
    recursive: false, // Disable hierarchy search when using target arrays
    targets: [specificMesh1, specificMesh2], // Limit to known interactive objects
    viewport: new Vector4(0, 0, 512, 512) // Multi-viewport application support
    });
    • The manager automatically handles both mouse and touch interactions through PointerEvent API
    • Parent hierarchy traversal allows nested objects to inherit interactivity
    • Deprecated IClickableObject3D.model interface usage triggers console warnings
    Index

    Constructors

    • Creates a new MouseEventManager instance.

      Parameters

      • scene: Scene

        The Three.js scene containing interactive objects

      • camera: Camera

        The camera used for raycasting calculations

      • canvas: HTMLCanvasElement

        The HTML canvas element to attach pointer event listeners

      • Optionaloption: {
            recursive?: boolean;
            targets?: Object3D<Object3DEventMap>[];
            throttlingTime_ms?: number;
            viewport?: Vector4;
        }

        Optional configuration parameters

        • Optionalrecursive?: boolean

          Whether to recursively search object hierarchies during raycasting (default: true)

        • Optionaltargets?: Object3D<Object3DEventMap>[]

          Array of specific objects to test for intersections (default: scene.children)

        • OptionalthrottlingTime_ms?: number

          Throttling interval in milliseconds (default: 33ms for ~30fps)

        • Optionalviewport?: Vector4

          Viewport region for multi-viewport applications (Vector4: x, y, width, height)

      Returns MouseEventManager

      Initializes the interaction management system by setting up pointer event listeners and registering with RAFTicker for throttled updates. The manager immediately begins processing pointer interactions according to the specified configuration.

      Configuration Guidelines:

      • Use shorter throttlingTime_ms (16ms) for responsive interactions at cost of performance
      • Set recursive: false when using pre-registered targets array for optimization
      • Specify viewport for applications using WebGLRenderer.setViewport()
      • Limit targets to known interactive objects to reduce intersection testing overhead

      Recursive Flag Behavior: The recursive parameter is passed directly to Three.js Raycaster.intersectObjects() and only affects raycasting intersection detection. It does NOT affect the parent hierarchy traversal performed by checkTarget(). This means:

      • recursive: true (default): Raycaster tests all descendants of target objects
      • recursive: false: Raycaster tests only the direct target objects specified
      • Important: Even with recursive: false, if a child object is hit during raycasting, checkTarget() will still traverse upward to find parent ClickableGroup objects
      • Limitation: When using a custom targets array with recursive: false, child objects not in the targets array will not be detected by raycasting, preventing parent ClickableGroups from receiving events even if they would be found during hierarchy traversal
      // Basic setup
      const manager = new MouseEventManager(scene, camera, canvas);

      // Performance-optimized setup
      const fastManager = new MouseEventManager(scene, camera, canvas, {
      throttlingTime_ms: 16, // 60fps for responsive UI
      recursive: false, // Skip hierarchy traversal
      targets: [button1, button2] // Test only specific objects
      });

      // Multi-viewport application
      const viewportManager = new MouseEventManager(scene, camera, canvas, {
      viewport: new Vector4(100, 100, 400, 300) // x, y, width, height
      });
      • Pointer event listeners are attached using passive: false to allow preventDefault()
      • RAFTicker integration ensures throttling works with animation frame timing
      • The manager does not automatically remove event listeners; call dispose() when no longer needed
      • Canvas should be properly sized before creating the manager for accurate coordinate conversion

    Properties

    camera: Camera
    canvas: HTMLCanvasElement
    currentOver: Map<number, IClickableObject3D<unknown>[]> = ...
    hasThrottled: Set<number> = ...
    mouse: Vector2 = ...
    raycaster: Raycaster = ...
    recursive: boolean
    scene: Scene
    targets: Object3D<Object3DEventMap>[]
    throttlingDelta: number = 0
    throttlingTime_ms: number
    viewport?: Vector4

    Methods

    • Protected

      Searches for interactive objects by traversing up the parent hierarchy from a target object.

      Parameters

      • target: undefined | null | Object3D<Object3DEventMap>

        The Three.js Object3D to start searching from (may be null/undefined)

      • type: keyof ThreeMouseEventMap<unknown>

        The type of interaction event to process ("down", "up", "over", "out")

      • pointerId: number = 1
      • hasTarget: boolean = false

        Whether any interactive target has been found in the current search chain

      Returns boolean

      True if an interactive object was found and processed, false otherwise

      Performs upward traversal through the Three.js object hierarchy to locate objects implementing the IClickableObject3D interface. When an interactive object is found, it processes the specified event type and may continue searching parent objects for additional interactive targets.

      Hierarchy Traversal Process:

      1. Check for deprecated interface usage and emit warnings
      2. Validate if current object implements IClickableObject3D interface
      3. If interactive and enabled, process the event and continue to parent
      4. If not interactive, continue searching up the parent chain
      5. Stop when reaching Scene level or null parent

      Independence from Raycasting Recursive Flag: This hierarchy traversal operates independently of the constructor's recursive flag. Even when recursive: false is set for raycasting optimization, this method will still traverse upward to find parent ClickableGroup objects once an initial intersection is detected.

      Event Processing: When an interactive object is found, the method delegates to onButtonHandler() for actual event processing. For "over" events, it also maintains the currentOver array to track hover state across multiple objects.

      Recursive Search: The method can find multiple interactive objects in a single parent chain, allowing nested interactive elements where both child and parent respond to the same pointer event.

      • Supports nested interactive objects within the same hierarchy
      • Emits deprecation warnings for legacy interface usage
      • Stops traversal at Scene level to prevent unnecessary searches
      • The hasTarget parameter tracks whether any target was found across the chain
      • implementsIClickableObject3D - Interface validation
      • implementsDepartedIClickableObject3D - Deprecated interface detection
      • onButtonHandler - Event processing delegation
      • currentOver - Hover state tracking array
    • Clears hover states for a specific pointer or all pointers.

      Parameters

      • OptionalpointerId: number

        The ID of the pointer to clear hover state for. If undefined, clears hover states for ALL pointers.

      Returns void

      Resets hover state by emitting "out" events for objects currently tracked in the currentOver Map. When pointerId is specified, only that pointer's hover state is cleared. When undefined, ALL pointer states are cleared (useful for cleanup scenarios like dispose or scene changes).

      This method ensures proper cleanup of hover states to prevent objects from remaining in an incorrect "over" state when they should return to "normal". The all-pointers clearing mode (undefined pointerId) maintains backward compatibility with single-pointer implementations.

    • Cleans up DOM event listeners and RAF ticker subscriptions.

      Returns void

      Removes all event listeners attached to the canvas element and unsubscribes from RAFTicker to prevent memory leaks. Call this method when the MouseEventManager is no longer needed, especially in long-running applications that recreate managers (e.g., during scene rebuilds).

      The method performs comprehensive cleanup by:

      • Clearing current hover state to emit proper "out" events
      • Removing all three pointer event listeners from the canvas
      • Unsubscribing from RAFTicker to stop throttling callbacks
      • Resetting internal throttling state
      • After calling dispose(), the manager will no longer respond to pointer events
      • The manager cannot be reused after disposal; create a new instance if needed
      • Failure to call dispose() may result in memory leaks in long-lived applications
      • This method is safe to call multiple times
      // Clean up before recreating the manager
      manager.dispose();
      manager = new MouseEventManager(newScene, newCamera, canvas);

      // In a React component unmount
      useEffect(() => {
      const manager = new MouseEventManager(scene, camera, canvas);
      return () => manager.dispose(); // Cleanup on unmount
      }, []);

      // When switching scenes
      oldManager.dispose();
      const newManager = new MouseEventManager(newScene, newCamera, canvas);
      • constructor - Initial setup of listeners and subscriptions
      • clearOver - Hover state cleanup method used internally
    • Protected

      Performs raycasting to detect object intersections and filters duplicate results.

      Parameters

      • event: PointerEvent

        The pointer event containing screen coordinates

      Returns Intersection<Object3D<Object3DEventMap>>[]

      Array of intersection results filtered by unique Object3D instances

      Wraps Three.js raycasting functionality to detect objects intersected by the pointer. Converts screen coordinates to normalized device coordinates, performs raycasting against configured targets, and filters results to prevent duplicate detections from multi-face geometry intersections.

      Processing Steps:

      1. Convert pointer coordinates to normalized device coordinates using ViewPortUtil
      2. Configure raycaster with camera and normalized coordinates
      3. Perform intersection testing against target objects
      4. Filter results by Object3D UUID to eliminate duplicate face intersections

      Duplicate Filtering: Single Mesh objects with complex geometry can generate multiple intersection results when the ray hits multiple faces. UUID-based filtering ensures each Object3D appears only once in the results, using the closest intersection.

      • Uses the configured targets array and recursive flag from constructor options
      • The recursive flag is passed directly to Three.js Raycaster.intersectObjects()
      • Filtering preserves Z-order (closest to farthest) for proper event processing
      • ViewPortUtil handles multi-viewport coordinate transformations when applicable
    • Handles pointer move events with throttling and over/out state management.

      Parameters

      • event: PointerEvent

        The pointer move event from the DOM

      Returns void

      Processes pointer movement by performing raycasting to detect object intersections and managing hover state transitions. The method implements conditional throttling to prevent excessive raycasting during rapid pointer movements, which significantly improves performance in complex scenes.

      Throttling Behavior:

      • When throttlingTime_ms > 0: Applies throttling with hasThrottled flag management
      • When throttlingTime_ms <= 0: Bypasses throttling entirely for immediate processing

      The method checks throttling status (if enabled), performs raycasting, processes intersections in Z-order, updates hover targets, and emits "out"/"over" events as needed.

      The method maintains a currentOver array to track hovered objects and compares new intersection results with the previous state to determine event needs.

      • Throttling is controlled by the throttlingTime_ms constructor parameter
      • When throttling is disabled (throttlingTime_ms <= 0), events are processed immediately
      • Early termination occurs when the first interactive object is found in Z-order
      • The method calls preventDefault() to ensure consistent behavior across browsers
      • Empty intersection results trigger clearOver() to reset all hover states
      • getIntersects - Raycasting and intersection detection
      • checkTarget - Object interactivity validation and event dispatch
      • clearOver - Hover state cleanup
      • onTick - RAF ticker callback that manages throttling state
    • Handles pointer down and up events for interactive objects.

      Parameters

      • event: PointerEvent

        The pointer down or up event from the DOM

      Returns void

      Processes pointer press and release events by performing raycasting to identify intersected objects and delegating the appropriate event type ("down" or "up") to their interaction handlers. The method includes viewport boundary checking for multi-viewport applications.

      The method maps "pointerdown" to "down" and "pointerup" to "up" interaction events.

      For "down" events, validates pointer position within configured viewport boundaries to ensure interactions only occur within the designated rendering region.

      The method determines event type, validates viewport boundaries for down events, performs raycasting, and processes intersections in Z-order with early termination.

      • Viewport checking is only performed for "down" events to allow "up" events to complete interaction sequences even if the pointer moves outside the viewport
      • The method calls preventDefault() to ensure consistent behavior across browsers
      • Z-order processing ensures only the frontmost interactive object receives the event
    • Handles pointer cancel events for interrupted touch interactions.

      Parameters

      • event: PointerEvent

        The pointer cancel event containing the interrupted pointerId

      Returns void

      Processes pointercancel events by preventing default behavior and delegating cleanup to the common cleanup method.

      Browser Event Sequence: pointercancel → pointerout → pointerleave Mutual Exclusivity: pointercancel and pointerup never both occur Timing: preventDefault() called when cancelable to maintain consistent behavior

    • Handles browser-generated pointerleave events for reliable cleanup.

      Parameters

      • event: PointerEvent

        The pointerleave event from browser

      Returns void

      Processes pointerleave events by delegating cleanup to the common cleanup method.

      Why pointerleave is optimal:

      • Always fires after UP events (no click interference)
      • Indicates complete departure from element hierarchy
      • Reliable browser-generated event with stable execution order
      • Handles edge case: outside → move into button → up inside button

      cleanupPointerState - Common cleanup implementation

    • Dispatches interaction events to the appropriate handler methods.

      Parameters

      Returns void

      Static utility method that serves as the central event dispatcher for all interactive objects. It creates the appropriate ThreeMouseEvent and delegates to the correct handler method on the object's ButtonInteractionHandler.

      Event Routing:

      • "down" events → onMouseDownHandler()
      • "up" events → onMouseUpHandler()
      • "over" events → onMouseOverHandler()
      • "out" events → onMouseOutHandler()

      Direct Delegation: This method performs direct event delegation without duplicate checking or state validation. Individual ButtonInteractionHandler instances manage their own event duplicate suppression and state validation as appropriate for their specific interaction patterns.

      Event Object Creation: Uses createThreeMouseEvent() to create properly formatted event objects that include the event type, interaction handler reference, and selection state (for checkbox/radio button objects).

      • This static method allows consistent event dispatching from multiple entry points
      • Handler instances manage their own duplicate suppression and state validation
      • The method serves as the bridge between intersection detection and interaction handling