A lightweight pointer event library for handling mouse, touch, and pen interactions in browsers. Provides unified APIs for down, move, click, long, hover, drag, resize and more.
- 🖱️ Unified pointer event handling (mouse, touch, pen)
- 📱 Mobile-friendly with touch support
- 🎯 Click, double-click, and long-press detection
- 👆 Hover detection with enter/move/leave callbacks
- 🔄 Drag and drop with customizable constraints
- 📐 Resize functionality with border detection
- 🎨 Global cursor management
- 🪝 Global hooks for move events
- 📦 Zero dependencies
- 🔷 Full TypeScript support
- 🌐 ESM and UMD bundle support
npm install @litert/pointer<!-- UMD (Development) -->
<script src="https://unpkg.com/@litert/pointer/dist/index.umd.js"></script>
<!-- UMD (Production, minified) -->
<script src="https://unpkg.com/@litert/pointer/dist/index.umd.min.js"></script>import * as pointer from '@litert/pointer';
element.addEventListener('pointerdown', (e) => {
pointer.move(e, {
move: (e, detail) => {
console.log('Moving:', detail.ox, detail.oy);
}
});
});<script src="https://unpkg.com/@litert/pointer/dist/index.umd.min.js"></script>
<script>
element.addEventListener('pointerdown', function(e) {
pointer.move(e, {
move: function(e, detail) {
console.log('Moving:', detail.ox, detail.oy);
}
});
});
</script>Down and up events, bind to pointer events.
pointer.down(e, {
down: (e) => { /* Triggered when pressed */ },
start: (e) => { /* Triggered when start moving, return false to cancel subsequent events */ },
move: (e, dir) => { /* Triggered when moving, dir is the direction of movement */ },
up: (e) => { /* Triggered when released */ },
end: (e) => { /* Triggered when moving ends */ }
});Click takes effect only when the pointer does not move and the time is less than 250ms.
element.addEventListener('pointerdown', (e) => {
pointer.click(e, (e, x, y) => {
console.log('Clicked at:', x, y);
});
});Double-click event, the interval between two clicks is less than 300ms and the position difference is less than 10px.
element.addEventListener('pointerdown', (e) => {
pointer.dblClick(e, (e, x, y) => {
console.log('Double clicked at:', x, y);
});
});Long press event, default 300ms.
element.addEventListener('pointerdown', (e) => {
pointer.long(e, (e) => {
console.log('Long press detected!');
}, { 'time': 500 });
});Hover event, handles enter, move, and leave for mouse and touch.
const cb = (e) => {
pointer.hover(e, {
enter: (e) => {
console.log('Pointer entered');
},
move: (e) => {
console.log('Pointer moving at:', e.clientX, e.clientY);
},
leave: (e) => {
console.log('Pointer left');
}
});
};
element.addEventListener('pointerdown', cb);
element.addEventListener('pointerenter', cb);Drag event, supports boundary detection and constraints.
element.addEventListener('pointerdown', (e) => {
pointer.move(e, {
// --- Constraint area ---
left: 0,
top: 0,
right: window.innerWidth,
bottom: window.innerHeight,
// --- Or use an element as a constraint area ---
// areaObject: document.getElementById('container'),
// --- Drag object (used to calculate boundary offset) ---
object: element,
// --- Callbacks ---
start: (x, y) => {
console.log('Start at:', x, y);
},
move: (e, detail) => {
console.log('Move:', detail.ox, detail.oy);
console.log('Position:', detail.x, detail.y);
console.log('Border:', detail.border);
console.log('Direction:', detail.dir);
},
up: (moveTimes, e) => {
console.log('Up');
},
end: (moveTimes, e) => {
console.log('End');
},
borderIn: (x, y, border, e) => {
console.log('Border in:', border);
},
borderOut: () => {
console.log('Border out');
}
});
});Global hooks for move events. These hooks are called for all move operations.
// --- Register global move down hook ---
pointer.addMoveHook('down', (e, opt) => {
console.log('Global move down hook:', e, opt);
});
// --- Register global move up hook ---
pointer.addMoveHook('up', (e, opt) => {
console.log('Global move up hook:', moveTimes, e, opt);
});
// --- Remove a hook ---
pointer.removeMoveHook('down', hookFunction);Resize event.
element.addEventListener('pointerdown', (e) => {
pointer.resize(e, {
object: element,
border: 'rb', // lt, t, tr, r, rb, b, bl, l
minWidth: 100,
minHeight: 100,
maxWidth: 500,
maxHeight: 500,
start: (x, y) => {
console.log('Resize start');
},
move: (left, top, width, height, x, y, border) => {
element.style.left = left + 'px';
element.style.top = top + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
},
end: () => {
console.log('Resize end');
}
});
});Drag event, supports drag and drop to target elements.
// --- Set drag source ---
dragSource.addEventListener('pointerdown', (e) => {
pointer.drag(e, dragSource, {
data: { id: 1, name: 'item' },
start: (x, y) => {
console.log('Drag start');
},
move: (e, detail) => {
console.log('Dragging');
},
end: (moveTimes, e) => {
console.log('Drag end');
}
});
});
// --- Set drop target ---
dropTarget.dataset.drop = '';
dropTarget.addEventListener('dragenter', (e) => {
console.log('Drag enter');
});
dropTarget.addEventListener('dragleave', (e) => {
console.log('Drag leave');
});
dropTarget.addEventListener('drop', (e) => {
const data = pointer.getDragData();
console.log('Dropped:', data);
});Scale/zoom event, supports pinch-to-zoom on touch devices and mouse wheel.
element.addEventListener('pointerdown', (e) => {
pointer.scale(e, (e, scale, cpos) => {
console.log('Scale:', scale, 'Center:', cpos.x, cpos.y);
});
});
element.addEventListener('wheel', (e) => {
pointer.scale(e, (e, scale, cpos) => {
console.log('Scale:', scale, 'Center:', cpos.x, cpos.y);
});
});Gesture event for swipe actions (up, down, left, right).
element.addEventListener('pointerdown', (e) => {
pointer.gesture(e, (e, dir) => {
// Return 1 to show gesture indicator, 0 to ignore, -1 to stop propagation
return 1;
}, (dir) => {
console.log('Gesture completed:', dir);
});
});
element.addEventListener('wheel', (e) => {
pointer.gesture(e, (e, dir) => {
return 1;
}, (dir) => {
console.log('Wheel gesture:', dir);
});
});Set/cancel global mouse style.
pointer.setCursor('move');
// ...
pointer.setCursor(); // CancelCheck if the pointer event is from a touch device.
const isTouch = pointer.isTouch(e);
console.log('Is touch device:', isTouch);Direction type.
type TDirection = 'top' | 'right' | 'bottom' | 'left';Border direction type.
type TBorder = 'lt' | 't' | 'tr' | 'r' | 'rb' | 'b' | 'bl' | 'l' | '';Options for the down function.
interface IDownOptions {
down?: (e: PointerEvent) => void;
start?: (e: PointerEvent) => any;
move?: (e: PointerEvent, dir: TDirection) => any;
up?: (e: PointerEvent) => void | Promise<void>;
end?: (e: PointerEvent) => void | Promise<void>;
}Options for the hover function.
interface IHoverOptions {
enter?: (e: PointerEvent) => void;
move?: (e: PointerEvent) => void;
leave?: (e: PointerEvent) => void;
}Options for the long function.
interface ILongOptions {
time?: number; // Long press time, default 300 ms
down?: (e: PointerEvent) => void | Promise<void>;
up?: (e: PointerEvent) => void | Promise<void>;
}Detailed information in the move callback.
interface IMoveDetail {
ox: number; // x-axis offset
oy: number; // y-axis offset
x: number; // Current x coordinate
y: number; // Current y coordinate
border: TBorder; // Border type
inBorder: { // Whether at the border
top: boolean;
right: boolean;
bottom: boolean;
left: boolean;
};
dir: TDirection; // Direction of movement
}Movement time record.
interface IMoveTime {
time: number;
ox: number;
oy: number;
}Options for the move function.
interface IMoveOptions {
areaObject?: HTMLElement;
left?: number;
top?: number;
right?: number;
bottom?: number;
offsetLeft?: number;
offsetTop?: number;
offsetRight?: number;
offsetBottom?: number;
objectLeft?: number;
objectTop?: number;
objectWidth?: number;
objectHeight?: number;
object?: HTMLElement;
cursor?: string;
start?: (x: number, y: number) => any;
move?: (e: PointerEvent, detail: IMoveDetail) => void;
borderIn?: (x: number, y: number, border: TBorder, e: PointerEvent) => void;
borderOut?: () => void;
up?: (moveTimes: IMoveTime[], e: PointerEvent) => void;
end?: (moveTimes: IMoveTime[], e: PointerEvent) => void;
}Result returned by the move function.
interface IMoveResult {
left: number;
top: number;
right: number;
bottom: number;
}Options for the resize function.
interface IResizeOptions {
border: TBorder;
minWidth?: number;
minHeight?: number;
maxWidth?: number;
maxHeight?: number;
object?: HTMLElement;
objectLeft?: number;
objectTop?: number;
objectWidth?: number;
objectHeight?: number;
start?: (x: number, y: number) => any;
move?: (left: number, top: number, width: number, height: number, x: number, y: number, border: TBorder) => void;
end?: (moveTimes: IMoveTime[], e: PointerEvent) => void;
}Options for the drag function.
interface IDragOptions {
data?: any;
start?: (x: number, y: number) => any;
move?: (e: PointerEvent, detail: IMoveDetail) => void;
end?: (moveTimes: IMoveTime[], e: PointerEvent) => void;
}Handler function type for scale events.
type TScaleHandler = (e: PointerEvent | WheelEvent, scale: number, cpos: { x: number; y: number; }) => void | Promise<void>;Before handler function type for gesture events. Return 1 to show gesture, 0 to ignore, -1 to stop propagation.
type TGestureBeforeHandler = (e: PointerEvent | WheelEvent, dir: TDirection) => number;Handler function type for gesture events.
type TGestureHandler = (dir: TDirection) => void | Promise<void>;Handler function type for menu events.
type TMenuHandler = (e: PointerEvent | MouseEvent) => void | Promise<void>;Global hook function type for move down events.
type TMoveDownHook = (e: PointerEvent, opt: IMoveOptions) => void | Promise<void>;Global hook function type for move up events.
type TMoveUpHook = (e: PointerEvent, opt: IMoveOptions) => void | Promise<void>;Clone the repository and open dist/test/index.html in your browser.
git clone https://github.com/litert/pointer.js.git
cd pointer.js
npm install
npm run buildThen open dist/test/index.html in your browser.
- Chrome 55+
- Firefox 59+
- Safari 13+
- Edge 79+
- Mobile browsers (iOS Safari 13+, Chrome for Android)
Requires Pointer Events API support. For older browsers, consider using a polyfill.
This library is published under Apache-2.0 license.