/**
* Base class that handles user interaction via device events (mouse/touch events).
* Provides an abstract user interface to define interaction actions such as panning, pinching, tapping, etc...
* The actions are implemented by pre-defined callback functions:
* * `panStart(e)` intercepts the initial pan event (movement of the mouse after pressing a mouse button or moving a finger).
* The event is captured calling `e.preventDefault()`.
* * `panMove(e)` receives and handles the pan event.
* * `panEnd(e)` intercepts the final pan event (the user releases the left mouse button or removes his finger from the screen).
* * `pinchStart(e1, e2)` intercepts the initial pinch event (a continuous gesture that tracks the positions between the first two fingers that touch the screen).
* The event is captured calling `e1.preventDefault()`.
* * `pinchMove(e1,e2)` receives and handles the pinch event.
* * `pinchEnd(e1,e2)` intercepts the final pinch event (the user removes one of their two fingers from the screen).
* * `mouseWheel(e)` receives and handles the mouse wheel event (the user rotates the mouse wheel button).
* * `fingerSingleTap(e)` receives and handles the single-tap event (the user presses a mouse button quickly or touches the screen shortly with a finger).
* * `fingerDoubleTap(e)` receives and handles the double-tap event (the user quickly presses a mouse button twice or shortly touches the screen with a finger twice).
*
* `e.preventDefault()` will capture the event and wont be propagated to other controllers.
*
* This class only describes user interactions by implementing actions or callbacks. A **Controller** works in concert with a **PointerManager** object
* that emits events and links them to actions.
*
* @abstract
* @example
* // Create a pan-zoom controller and associate it with the viewer's pointer manager
* const panzoom = new OpenLIME.ControllerPanZoom(viewer.camera, {
* priority: -1000,
* activeModifiers: [0, 1]
* });
* viewer.pointerManager.onEvent(panzoom);
*/
class Controller {
/**
* Creates a new Controller instance.
* @param {Object} [options] - Configuration options
* @param {boolean} [options.active=true] - Whether the controller is initially active
* @param {boolean} [options.debug=false] - Enable debug logging
* @param {number} [options.panDelay=50] - Inertial value for panning movements in milliseconds
* @param {number} [options.zoomDelay=200] - Delay for smoothing zoom events in milliseconds
* @param {number} [options.priority=0] - Controllers with higher priority are invoked first
* @param {number[]} [options.activeModifiers=[0]] - Array of modifier states that activate this controller
*/
constructor(options) {
Object.assign(this, {
active: true,
debug: false,
panDelay: 50,
zoomDelay: 200,
priority: 0,
activeModifiers: [0]
});
Object.assign(this, options);
}
/**
* Gets the modifier state from an event.
* @param {Event} e - The event to check
* @returns {number} Modifier state bitmask where:
* - 0 = No modifiers
* - 1 = Ctrl key
* - 2 = Shift key
* - 4 = Alt key
* Multiple modifiers combine their values (e.g., Ctrl+Shift = 3)
*/
modifierState(e) {
let state = 0;
if (e.ctrlKey) state += 1;
if (e.shiftKey) state += 2;
if (e.altKey) state += 4;
return state;
}
/**
* Captures all events, preventing them from reaching other controllers.
* @private
*/
captureEvents() {
this.capture = true;
}
/**
* Releases event capture, allowing events to reach other controllers.
* @private
*/
releaseEvents() {
this.capture = false;
}
/**
* Handles the start of a pan gesture.
* @virtual
* @param {Event} e - The pan start event
* @description Called when user starts panning (mouse down or finger touch).
* Call e.preventDefault() to capture the event.
*/
panStart(e) { }
/**
* Handles pan movement.
* @virtual
* @param {Event} e - The pan move event
* @description Called continuously during panning.
*/
panMove(e) { }
/**
* Handles the end of a pan gesture.
* @virtual
* @param {Event} e - The pan end event
* @description Called when panning ends (mouse up or finger lift).
*/
panEnd(e) { }
/**
* Handles the start of a pinch gesture.
* @virtual
* @param {Event} e1 - First finger event
* @param {Event} e2 - Second finger event
* @description Called when user starts a two-finger pinch.
* Call e1.preventDefault() to capture the event.
*/
pinchStart(e1, e2) { }
/**
* Handles pinch movement.
* @virtual
* @param {Event} e1 - First finger event
* @param {Event} e2 - Second finger event
* @description Called continuously during pinching.
*/
pinchMove(e1, e2) { }
/**
* Handles the end of a pinch gesture.
* @virtual
* @param {Event} e1 - First finger event
* @param {Event} e2 - Second finger event
* @description Called when pinch ends (finger lift).
*/
pinchEnd(e1, e2) { }
/**
* Handles mouse wheel events.
* @virtual
* @param {WheelEvent} e - The wheel event
* @description Called when user rotates mouse wheel.
*/
mouseWheel(e) { }
/**
* Handles single tap/click events.
* @virtual
* @param {Event} e - The tap event
* @description Called for quick mouse press or short finger touch.
*/
fingerSingleTap(e) { }
/**
* Handles double tap/click events.
* @virtual
* @param {Event} e - The double tap event
* @description Called for quick double mouse press or double finger touch.
*/
fingerDoubleTap(e) { }
}
export { Controller }