Source: Controller.js

/**
 * 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 }