PointerSensor
PointerSensor listens to pointer events, touch events and mouse events and normalizes them into unified drag events.
Example
import { PointerSensor } from 'dragdoll/sensors/pointer';
import { Draggable } from 'dragdoll/draggable';
// Create a pointer sensor instance which tracks pointer/touch/mouse events in
// window and emits drag events.
const pointerSensor = new PointerSensor(window);
// Listen to events.
pointerSensor.on('start', (e) => console.log('drag started', e));
pointerSensor.on('move', (e) => console.log('drag move', e));
pointerSensor.on('end', (e) => console.log('drag ended', e));
pointerSensor.on('cancel', (e) => console.log('drag canceled', e));
// Use the sensor to move an element.
const dragElement = document.querySelector('.dragElement');
const draggable = new Draggable([pointerSensor], {
elements: () => [dragElement],
});Class
class PointerSensor<E extends PointerSensorEvents = PointerSensorEvents> implements Sensor<E> {
constructor(element: Element | Window, options: Partial<PointerSensorSettings> = {}) {}
}The PointerSensor class is a generic that implements the Sensor interface.
Type Variables
- E
- The type of the events that the sensor will emit.
- Default:
PointerSensorEvents.
Constructor Parameters
- element
- The element (or window) whose events will be tracked.
- options
- An optional
PointerSensorSettingsobject, which you can also change later viaupdateSettingsmethod. - You only need to provide the options you want to change, the rest will be left as default.
- Default:
{}.
- An optional
Settings
The settings object follows the PointerSensorSettings interface. You can pass the settings object to the constructor or update them later via updateSettings method.
listenerOptions
type listenerOptions = {
capture?: boolean;
passive?: boolean;
};This object will be propagated to the source event listeners' options. You can use it to define whether the source event listeners should be passive and/or use capture.
Default: { capture: true, passive: true }
sourceEvents
type sourceEvents = 'pointer' | 'touch' | 'mouse' | 'auto';Define which type of events will be listened to and used as source events:
"pointer"->PointerEvents"touch"->TouchEvents"mouse"->MouseEvents"auto"-> Detect the best choice automatically (pointer > touch > mouse) based on what browser supports.
Default: "auto"
startPredicate
type startPredicate = (e: PointerEvent | TouchEvent | MouseEvent) => boolean;This function is called when drag process is starting up with the initial event as the argument. You can use it to define whether the drag process should be allowed to start (return true) or not (return false).
Default: (e) => ('button' in e && e.button > 0 ? false : true)
cancelOnVisibilityChange
type cancelOnVisibilityChange = boolean;Cancel the drag when the document becomes hidden (e.g. user switches tabs).
Default: true
cancelOnEscape
type cancelOnEscape = boolean;Cancel the drag when the Escape key is pressed.
Default: true
preventNativeDrag
type preventNativeDrag = boolean;Prevent the browser's native HTML5 drag behavior (e.g. for images and links) by calling preventDefault() on the window's dragstart event when a pointer interaction starts. This lets you avoid setting draggable="false" on individual elements.
Default: true
preventContextMenu
type preventContextMenu = boolean;Prevent the browser's context menu (right-click menu) from appearing during an active drag by calling preventDefault() on the window's contextmenu event. Useful to avoid jarring UX when the user right-clicks while dragging.
Default: false
Properties
element
type element = Element | Window;The observed element or window. Read-only.
drag
type drag = PointerSensorDragData | null;Current drag data or null when drag is inactive. The drag data follows the PointerSensorDragData interface. Read-only.
deltaX/deltaY represent the difference between the previous and current position, not the start and current position.
isDestroyed
type isDestroyed = boolean;Is sensor destroyed or not? Read-only.
Methods
on
type on<T extends keyof E> = (
type: T,
listener: (e: E[T]) => void,
listenerId?: SensorEventListenerId,
) => SensorEventListenerId;Adds a listener to a sensor event. Returns a listener id, which can be used to remove this specific listener. By default this will always be a symbol unless manually provided.
Please check the Events section for more information about the events and their payloads.
Example
pointerSensor.on('start', (e) => {
console.log('start', e);
});off
type off<T extends keyof E> = (type: T, listenerId: SensorEventListenerId) => void;Removes a listener (based on listener id) from a sensor event.
Example
const id = pointerSensor.on('start', (e) => console.log('start', e));
pointerSensor.off('start', id);updateSettings
type updateSettings = (options: Partial<PointerSensorSettings>) => void;Updates the sensor's settings. Accepts a partial PointerSensorSettings object as the first argument, only the options you provide will be updated. Read more about the settings in the Settings section.
Example
pointerSensor.updateSettings({
startPredicate: () => Math.random() > 0.5,
});cancel
type cancel = () => void;Forcibly cancel the sensor's current drag process. The purpose of this method is to have a manual way of aborting the drag procedure at all times.
Example
pointerSensor.cancel();preventClickOnEnd
type preventClickOnEnd = () => void;Prevents the next click event from propagating and performing its default action. This is useful for blocking clicks after a drag ends to avoid triggering click handlers on draggable elements (e.g., links, buttons).
The blocker automatically removes itself after blocking a click or when a new pointer interaction starts on this sensor.
Features:
- Only blocks native browser-generated clicks (
e.isTrusted). Programmatic clicks (e.g.,element.click()) are not blocked. - Uses both
preventDefault()andstopPropagation()in the capture phase. - Self-cleaning: no arbitrary timeouts needed.
NOTE
This method is typically called automatically by Draggable when the preventClickOnEnd setting is enabled (which is the default). You usually don't need to call this manually unless you're using PointerSensor without Draggable.
Example
// Manual usage (rare - usually handled by Draggable)
pointerSensor.on('end', () => {
pointerSensor.preventClickOnEnd();
});destroy
type destroy = () => void;Destroy the sensor. Disposes all allocated memory and removes all bound event listeners.
Example
pointerSensor.destroy();Events
NOTE
To minimize memory allocations, event data objects are pooled and mutated between events. Treat them as read-only and do not store them for later use. If you need to persist the data, extract the specific values you need or clone the object.
start
Emitted when the sensor starts dragging.
Payload follows the PointerSensorStartEvent interface.
move
Emitted when the sensor is moved during the drag.
Payload follows the PointerSensorMoveEvent interface.
cancel
Emitted when the drag is canceled.
Payload follows the PointerSensorCancelEvent interface.
end
Emitted when the drag ends without being canceled.
Payload follows the PointerSensorEndEvent interface.
destroy
Emitted when the sensor is destroyed.
Payload follows the PointerSensorDestroyEvent interface.
Exports
Here's a list of additional exports that are available in the dragdoll/sensors/pointer package.
PointerSensorDefaultSettings
// Import
import { PointerSensorDefaultSettings } from 'dragdoll/sensors/pointer';
// Constant
const PointerSensorDefaultSettings: PointerSensorSettings;Types
PointerSensorDragData
// Import
import type { PointerSensorDragData } from 'dragdoll/sensors/pointer';
// Type
type PointerSensorDragData = {
readonly pointerId: number;
readonly pointerType: 'mouse' | 'pen' | 'touch';
readonly startX: number;
readonly startY: number;
readonly x: number;
readonly y: number;
readonly deltaX: number;
readonly deltaY: number;
};PointerSensorSettings
// Import
import type { PointerSensorSettings } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorSettings {
listenerOptions: { capture?: boolean; passive?: boolean };
sourceEvents: 'pointer' | 'touch' | 'mouse' | 'auto';
startPredicate: (e: PointerEvent | TouchEvent | MouseEvent) => boolean;
cancelOnVisibilityChange?: boolean;
cancelOnEscape?: boolean;
preventNativeDrag?: boolean;
preventContextMenu?: boolean;
}PointerSensorStartEvent
// Import
import type { PointerSensorStartEvent } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorStartEvent {
type: 'start';
startX: number;
startY: number;
x: number;
y: number;
deltaX: number;
deltaY: number;
pointerId: number;
pointerType: 'mouse' | 'pen' | 'touch';
srcEvent: PointerEvent | TouchEvent | MouseEvent;
target: EventTarget | null;
}PointerSensorMoveEvent
// Import
import type { PointerSensorMoveEvent } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorMoveEvent {
type: 'move';
startX: number;
startY: number;
x: number;
y: number;
deltaX: number;
deltaY: number;
pointerId: number;
pointerType: 'mouse' | 'pen' | 'touch';
srcEvent: PointerEvent | TouchEvent | MouseEvent;
target: EventTarget | null;
}PointerSensorCancelEvent
// Import
import type { PointerSensorCancelEvent } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorCancelEvent {
type: 'cancel';
startX: number;
startY: number;
x: number;
y: number;
deltaX: number;
deltaY: number;
pointerId: number;
pointerType: 'mouse' | 'pen' | 'touch';
srcEvent: PointerEvent | TouchEvent | MouseEvent | null;
target: EventTarget | null;
}PointerSensorEndEvent
// Import
import type { PointerSensorEndEvent } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorEndEvent {
type: 'end';
startX: number;
startY: number;
x: number;
y: number;
deltaX: number;
deltaY: number;
pointerId: number;
pointerType: 'mouse' | 'pen' | 'touch';
srcEvent: PointerEvent | TouchEvent | MouseEvent | null;
target: EventTarget | null;
}PointerSensorDestroyEvent
// Import
import type { PointerSensorDestroyEvent } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorDestroyEvent {
type: 'destroy';
}PointerSensorEvents
// Import
import type { PointerSensorEvents } from 'dragdoll/sensors/pointer';
// Interface
interface PointerSensorEvents {
start: PointerSensorStartEvent;
move: PointerSensorMoveEvent;
cancel: PointerSensorCancelEvent;
end: PointerSensorEndEvent;
destroy: PointerSensorDestroyEvent;
}