mobile-gesture
v1.0.0
Published
A lightweight gesture recognition library for pointer/touch events
Maintainers
Readme
Touch Gesture Library
A lightweight gesture recognition library for pointer/touch events. Supports tap, double-tap, long-press, drag, pinch-to-zoom, and scroll gestures.
Installation
npm install mobile-gestureFeatures
- Pure TypeScript - No external dependencies
- Pointer Events API - Works with both mouse and touch input
- Multiple Output Formats - ESM, CJS, and UMD bundles
- Configurable - Customize thresholds and acceleration
- Test Coverage - 23 unit tests with Vitest
Usage
ESM / TypeScript
import { GestureRecognizer } from 'touch-gesture-lib';
const recognizer = new GestureRecognizer({
onTap: (x, y) => console.log(`Tap at ${x}, ${y}`),
onDoubleTap: (x, y) => console.log(`Double tap at ${x}, ${y}`),
onLongPress: (x, y) => console.log(`Long press at ${x}, ${y}`),
onDrag: (x, y, delta) => console.log(`Drag to ${x}, ${y}`, delta),
onMove: (x, y, delta) => console.log(`Move to ${x}, ${y}`, delta),
onPinch: (scale, centerX, centerY) => console.log(`Pinch ${scale}`, centerX, centerY),
onScroll: (delta) => console.log(`Scroll`, delta),
});
// Attach to element
const element = document.getElementById('touchArea');
element.addEventListener('pointerdown', (e) => {
recognizer.handlePointerDown(e.pointerId, e.clientX, e.clientY);
});
element.addEventListener('pointermove', (e) => {
recognizer.handlePointerMove(e.pointerId, e.clientX, e.clientY);
});
element.addEventListener('pointerup', (e) => {
recognizer.handlePointerUp(e.pointerId);
});
element.addEventListener('pointercancel', () => {
recognizer.handlePointerCancel();
});UMD (Browser)
<script src="gesture.umd.js"></script>
<script>
const recognizer = new MobileGesture.GestureRecognizer({
onTap: (x, y) => console.log('Tap', x, y),
});
</script>React Example
import { useEffect, useRef } from 'react';
import { GestureRecognizer } from 'touch-gesture-lib';
function TouchComponent() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const recognizer = new GestureRecognizer({
onTap: (x, y) => console.log('Tap at', x, y),
onDrag: (x, y) => console.log('Drag to', x, y),
});
const container = containerRef.current;
if (!container) return;
const onPointerDown = (e: PointerEvent) => {
recognizer.handlePointerDown(e.pointerId, e.clientX, e.clientY);
};
const onPointerMove = (e: PointerEvent) => {
recognizer.handlePointerMove(e.pointerId, e.clientX, e.clientY);
};
const onPointerUp = (e: PointerEvent) => {
recognizer.handlePointerUp(e.pointerId);
};
container.addEventListener('pointerdown', onPointerDown);
container.addEventListener('pointermove', onPointerMove);
container.addEventListener('pointerup', onPointerUp);
container.addEventListener('pointercancel', () => recognizer.handlePointerCancel());
return () => {
container.removeEventListener('pointerdown', onPointerDown);
container.removeEventListener('pointermove', onPointerMove);
container.removeEventListener('pointerup', onPointerUp);
recognizer.destroy();
};
}, []);
return <div ref={containerRef} style={{ width: '100%', height: '100vh' }} />;
}API
GestureRecognizer
new GestureRecognizer(options: GestureRecognizerOptions)Options
| Option | Type | Description |
|--------|------|-------------|
| onTap | (x: number, y: number) => void | Called on single tap |
| onDoubleTap | (x: number, y: number) => void | Called on double tap within 300ms |
| onLongPress | (x: number, y: number) => void | Called after 800ms hold |
| onDrag | (x: number, y: number, delta: PointerDelta) => void | Called during drag |
| onMove | (x: number, y: number, delta: PointerDelta) => void | Called during move |
| onPinch | (scale: number, centerX: number, centerY: number) => void | Called during pinch-to-zoom |
| onScroll | (delta: PointerDelta) => void | Called during two-finger scroll |
| thresholds | ThresholdsConfig | Customize detection thresholds |
| acceleration | AccelerationConfig | Customize acceleration factors |
Methods
| Method | Description |
|--------|-------------|
| handlePointerDown(id, x, y) | Call on pointerdown event |
| handlePointerMove(id, x, y) | Call on pointermove event |
| handlePointerUp(id) | Call on pointerup event |
| handlePointerCancel() | Call on pointercancel event |
| reset() | Reset internal state |
| destroy() | Cleanup and destroy instance |
| getCursorPosition() | Returns { x, y } current cursor position |
| getActiveMode() | Returns current gesture mode |
| isInLongPress() | Returns boolean |
| isMoved() | Returns boolean |
Thresholds Configuration
{
TAP_DISTANCE: 5, // Max movement for tap (px)
MOVE_DISTANCE: 10, // Min movement to lock move mode (px)
LONG_PRESS_DURATION: 800, // Hold duration for long press (ms)
DOUBLE_TAP_WINDOW: 300, // Max time between taps (ms)
ZOOM_SPEED_THRESHOLD: 0.3, // Min speed for pinch (px/ms)
ZOOM_DISTANCE_THRESHOLD: 20, // Min distance change for pinch (px)
SCROLL_DISTANCE_THRESHOLD: 50, // Min center movement for scroll (px)
CALCULATION_PHASE: 150, // Calculation phase duration (ms)
}Gestures
| Gesture | Description | |---------|-------------| | Tap | Single finger down + up, movement < 5px | | Double Tap | Two taps within 300ms | | Long Press | Finger down for 800ms without movement | | Move | Single finger movement > 10px | | Drag | Long press + movement | | Pinch | Two fingers spreading/closing quickly | | Scroll | Two fingers moving together |
Build
npm install
npm run build # Build ESM, CJS, UMD bundles
npm run test # Run testsLicense
MIT
