Gesture Library
Category: BasicThe Gesture library is a multi-device gesture module dedicated to OrcaUI. It standardizes events such as click (single tap), dblclick (double tap), hold (long press), cancel, scale (pinch zoom), rotate, and translate (pan). It also specifically handles wheel (scroll) events and right-click events on desktop platforms.
Preface
Event naming conventions differ between desktop and mobile platforms. The primary event tool on desktop is the mouse, while mobile platforms primarily use fingers (single or multi-touch) as the event tool. This fundamental difference in triggering mechanisms results in distinct event sets across platforms.
For example, contextmenu
represents the right-click event in desktop environments, typically used to open tool windows for operations like adding, deleting, or modifying content. However, this event doesn't exist on mobile devices. If you need to trigger similar tool window functionality on mobile, how should you implement it? We can use single-finger long-press gestures as a substitute for the desktop contextmenu
event.
Another example: element scaling is a common operation on mobile devices. While less frequent on desktop, this requirement still exists. Unfortunately, neither platform natively provides a scale
event. To implement consistent element scaling across both platforms with a single event handler, our solution is:
- For desktop: Listen to the
scroll
event of the mouse wheel and scale based on scroll distance - For mobile: Calculate real-time distance between two fingers and compare with the initial two-finger distance, then use "new distance / initial distance" to determine element scale.
Yet another example: The click
event triggers immediately on desktop but has a 300ms
delay on mobile devices (as the device needs this time to determine if the user will touch the screen again for a double-tap event). If the touched element disappears within these 300ms, the click event propagates to underlying elements - this is the infamous "click through" bug.
Therefore, native click events have inherent bugs on mobile platforms. Our solution for this bug is breaking down the click event into three stages (press => move => release), using native events from both platforms to simulate the complete click process.
Basic Usage
This gesture module follows the same pattern as other modules - it can be applied either through the oc-gesture
attribute on elements or via new
instance creation. Considering that the gesture module primarily focuses on event definition and execution, using attributes isn't as convenient or aesthetically pleasing, so we recommend using the new
instance approach.
The module enables click
(single tap), dblclick
(double tap), and hold
(long press) events by default.
Event parameters are passed as an object containing essential event data, primarily including: drift
, scale
, rotate
, translate
, etc.
- Output
- HTML
- JS
-
-
-
let gesture = new orca.Gesture('#demo01',{ onClick:(data)=>{ console.log('Single clicked',data) }, onDblclick:(data)=>{ console.log('Double clicked',data) }, onHold:(data)=>{ console.log('Long pressed',data) }, });
Right-Click Event
Mobile platforms lack right-click events, but we can use the hold
(long press) event as an alternative. Desktop platforms support both hold
events and native right-click events (contextmenu
).
While desktop platforms can implement long-press using the left mouse button, right-click is typically the standard alternative for long-press actions. For consistency, by default the desktop hold
event is mapped to contextmenu
- meaning right-clicking an element executes the hold event.
If custom right-click behavior is needed on desktop, set click.hold2Menu:false
.
- Output
- HTML
- JS
-
-
-
let gesture = new orca.Gesture('#demo02',{ click:{ hold2Menu:false, }, onHold:(data)=>{ console.log('Long pressed',data) }, }); demo02.oncontextmenu = (e)=>{ //Right-click triggers default menu, so first prevent it then implement custom menu e.preventDefault(); console.log('Triggered right-click') }
Universal Events
This module standardizes desktop events (mousedown
, mousemove
, mouseup
, mouseleave
) and mobile events (touchstart
, touchmove
, touchend
, touchcancel
). Derived events like click and hold are all implemented through three core actions (press, move, release).
Thus, the module provides four universal events: start
(press), move
(move), end
(release), and cancel
(target node loss).
- Output
- HTML
- JS
-
-
-
let last, now, demo03 = document.querySelector('#demo03'), gesture = new orca.Gesture(demo03,{ onStart:(data)=>{ last = new Date().getTime(); console.log('Pressed',data) }, onMove:(data)=>{ now = new Date().getTime(); if(now - last >=3000){ //After moving for 3 seconds, make target node disappear to trigger cancel event demo03.remove(); } console.log('Moved',data) }, onEnd:(data)=>{ console.log('Released',data) }, onCancel:(data)=>{ console.log('Lost target',data) }, });
Scaling Events
The scaling event group consists of scale
(start), scaling
(in-progress), and scaled
(complete).
First, enable scaling by setting parameter scale:true
or scale.enable:true
.
On mobile:
- Requires at least two fingers (two touch points on the element)
- If more than two touch points exist, calculations use the first two
On desktop:
- Implemented via mouse wheel
- Requires setting parameter
wheel={enable:true,mode:'scale'}
(specifies wheel triggers scale event)
Since style.transform
can be complex to configure, we recommend using the framework's transformTools.set
method for value assignment.
- Output
- HTML
- JS
-
-
-
let demo04 = document.querySelector('#demo04'); new orca.Gesture(demo04,{ step:{ //Specify mouse wheel triggers scale event mode:'scale', duration:200 }, wheel:true, //Enable scale event scale:true, onScale:(data)=>{ console.log('Start scaling',data) }, onScaling:(data)=>{ //Use transformTools.set to configure scale value orca.transformTools.set({ el:demo04, data:{scale:data.scale.value} }); console.log('Scaling in progress',data); }, onScaled:(data)=>{ console.log('Scaling complete',data) } });
For nodes in a flipped state, the scale event can also be used.
- Output
- HTML
- JS
-
-
-
let demo204 = document.querySelector('#demo204'); new orca.Gesture(demo204,{ step:{ //Specify mouse wheel triggers scale event mode:'scale', duration:200 }, wheel:true, //Enable scale event scale:true, onScale:(data)=>{ console.log('Start scaling',data) }, onScaling:(data)=>{ //Use transformTools.set to configure scale value orca.transformTools.set({ el:demo204, data:{scale:data.scale.value} }); console.log('Scaling in progress',data); }, onScaled:(data)=>{ console.log('Scaling complete',data) } });
Rotation Events
The rotation event group consists of:
rotate
(begin)rotating
(progress)rotated
(complete)
Enable rotation by setting rotate:true
or rotate.enable:true
.
For mobile:
- Requires at least two touch points
- Only the first two touch points are considered
For desktop:
- Implemented via mouse wheel
- Requires parameter
step{mode:'rotate'}
(configures wheel for rotation)
- Output
- HTML
- JS
-
-
-
let demo05 = document.querySelector('#demo05'); new orca.Gesture(demo05,{ step:{ //Configure mouse wheel for rotation mode:'rotate', duration:200 }, wheel:true, //Enable rotation rotate:true, onRotate:(data)=>{ console.log('Rotation started',data) }, onRotating:(data)=>{ //Apply rotation via transformTools orca.transformTools.set({ el:demo05, data:{rotate:data.rotate.value} }); console.log('Rotating in progress',data); }, onRotated:(data)=>{ console.log('Rotation completed',data) } });
Translation (Drag) Events
Translation events (commonly called drag events) manipulate elements through either:
style.transform.translate
- Or
position.left/top
properties
The translation event group consists of:
translate
(begin)translating
(progress)translated
(complete)
Because desktop and mobile implement dragging similarly (via pointer movement), this set is enabled by default.
The dragging
attribute is automatically added to target elements during interaction.
Note: Console logging in this example may cause performance lag - disable logs for smoother dragging.
- Output
- HTML
- JS
-
-
-
new orca.Gesture('#demo06',{ onTranslate:(data)=>{ console.log('Translation started',data) }, onTranslating:(data)=>{ //Apply translation via transformTools orca.transformTools.set({ el:'#demo06', data:{translate:data.translate.value} });console.log(data.orgEvt.target) console.log('Translating in progress',data); }, onTranslated:(data)=>{console.log(data.orgEvt.target) console.log('Translation completed',data) } });
Drift (Momentum) Events
Drift events are secondary effects of translation events - when translation completes with sufficient velocity, momentum continues the movement.
Disabled by default - enable with drift:true
or drift.enable:true
.
- Output
- HTML
- JS
-
-
-
new orca.Gesture('#demo07',{ drift:true, onTranslating:(data)=>{ //Apply translation via transformTools orca.transformTools.set({ el:'#demo07', data:{translate:data.translate.value} }); console.log('Translating in progress',data); }, onDrifting:(data)=>{ //Note: data.translate may not have linear velocity orca.transformTools.set({ el:'#demo07', data:{translate:data.translate.value} }); console.log('Drift in progress',data); } });
Swipe (Quick Flick) Events
Translation (translate
) and drift (drift
) events are interrelated - drift begins immediately after translation if velocity thresholds are met.
swipe
events detect quick flick gestures. If movement starts rapidly (meeting swipe thresholds), momentum begins from the original touch point when released.
Key differences between drift and swipe:
- Drift requires preceding translation; swipe occurs without translation
- Mobile drift has visible translation; swipe feels more direct
- Drift starts from release point; swipe starts from initial touch point
- Swipe and drift events are mutually exclusive
- Output
- HTML
- JS
-
-
-
new orca.Gesture('#demo51',{ swipe:true, onTranslating:(data)=>{ orca.transformTools.set({ el:'#demo51', data:{translate:data.translate.value} }); }, onSwiping:(data)=>{ orca.transformTools.set({ el:'#demo51', data:{translate:data.translate.value} }); console.log('Swiping',data); } });
Basic Configuration
Property | Type | Default | Description |
---|---|---|---|
parent | string | '' | Parent container selector |
unbound | string | '[unbound]' | Elements to exclude from events |
origin | object | null | Transform origin point |
jitterClick | number | 10 | Click movement threshold (px) |
jitterTrans | number | 1 | Movement stabilization value |
Viewport Configuration
Property | Type | Default | Description |
---|---|---|---|
viewport.enable | boolean | false | Enables boundary resistance for viewport |
viewport.selector | string | '' | Viewport container selector |
viewport.dmpRatio | number | 0.8 | Drag momentum damping coefficient |
viewport.bouncy | boolean | true | Enables edge bounce effect |
viewport.duration | number | 0 | Bounce animation duration (ms) |
Click Configuration
Property | Type | Default | Description |
---|---|---|---|
click.timeThr | number | 200 | Click time threshold (ms) |
click.delay | number | 200 | Double-click delay (ms) |
click.dblclickable | boolean | true | Enables double-click |
click.holdDelay | number | 1000 | Long-press delay (ms) |
click.hold2Menu | boolean | false | Maps long-press to right-click |
Step Configuration
Property | Type | Default | Description |
---|---|---|---|
step.mode | 'translate'/'scale'/'rotate' | 'translate' | Step interaction mode |
step.axis | 'x'/'y' | 'y' | Movement axis |
step.value | number | 0 | Step increment value |
step.duration | number | 500 | Animation duration (ms) |
step.intvl | number | 200 | Throttle interval (ms) |
step.linkage | boolean | true | Whether to trigger events |
step.reverse | boolean | false | Reverse operation direction |
step.curve | 'linear'/'ease'/'easeIn'/'easeOut'/'easeInOut'/'easeOutIn' | 'easeOut' | Animation easing curve |
Keyboard Configuration
Property | Type | Default | Description |
---|---|---|---|
keyboard.enable | boolean | false | Whether to enable keyboard |
keyboard.prev | string | 'ArrowUp' | Next step key |
keyboard.next | string | 'ArrowDown' | Previous step key |
keyboard.intvl | number | 200 | Throttle interval (ms) |
keyboard.target | string/null | null | Keyboard event target element |
Translation Configuration
Property | Type | Default | Description |
---|---|---|---|
translate.enable | boolean | true | Whether to enable translation |
translate.max | number | 10000000 | Maximum translation (px) |
translate.min | number | -10000000 | Minimum translation (px) |
translate.instead | boolean | false | Whether to use position instead |
translate.target | string | '' | Translation handle selector |
Drift Configuration
Property | Type | Default | Description |
---|---|---|---|
drift.enable | boolean | false | Whether to enable drift |
drift.timeThr | number | 300 | Time threshold (ms) |
drift.distThr | number | 20 | Distance threshold (px) |
drift.coef | number | 0.5 | Momentum coefficient |
drift.duration | number | 500 | Animation duration (ms) |
drift.curve | 'linear'/'ease'/'easeIn'/'easeOut'/'easeInOut'/'easeOutIn' | 'easeOut' | Motion easing curve |
drift.auto | boolean | true | Whether to complete automatically |
Swipe Configuration
Property | Type | Default | Description |
---|---|---|---|
swipe.enable | boolean | false | Whether to enable swipe |
swipe.timeThr | number | 100 | Time threshold (ms) |
swipe.distThr | number | 20 | Distance threshold (px) |
swipe.coef | number | 0.5 | Momentum coefficient |
swipe.duration | number | 500 | Animation duration (ms) |
swipe.curve | 'linear'/'ease'/'easeIn'/'easeOut'/'easeInOut'/'easeOutIn' | 'easeOut' | Motion easing curve |
swipe.auto | boolean | true | Whether to complete automatically |
Scale Configuration
Property | Type | Default | Description |
---|---|---|---|
scale.enable | boolean | false | Whether to enable scaling |
scale.centered | boolean | true | Whether to scale from center |
scale.max | number | 100 | Maximum scale factor |
scale.min | number | 0 | Minimum scale factor |
Rotation Configuration
Property | Type | Default | Description |
---|---|---|---|
rotate.enable | boolean | false | Whether to enable rotation |
rotate.max | number | 3600 | Maximum rotation angle (deg) |
rotate.min | number | -3600 | Minimum rotation angle (deg) |
Callback Functions
Property | Type | Default | Description |
---|---|---|---|
onStart | function | null | Touch start callback |
onMove | function | null | Movement process callback |
onEnd | function | null | Touch end callback |
onClick | function | null | Single click callback |
onDblclick | function | null | Double click callback |
onHold | function | null | Long press callback |
onScale | function | null | Scale start callback |
onScaling | function | null | Scaling process callback |
onScaled | function | null | Scale end callback |
onRotate | function | null | Rotation start callback |
onRotating | function | null | Rotating process callback |
onRotated | function | null | Rotation end callback |
onTranslate | function | null | Translation start callback |
onTranslating | function | null | Translating process callback |
onTranslated | function | null | Translation end callback |
onDrift | function | null | Drift start callback |
onDrifting | function | null | Drifting process callback |
onDrifted | function | null | Drift end callback |
onCanceled | function | null | Loss of target callback |