

[!NOTE]
This is one of 206 standalone projects, maintained as part
of the @thi.ng/umbrella monorepo
and anti-framework.
🚀 Please help me to work full-time on these projects by sponsoring me on
GitHub. Thank you! ❤️
About
Unified mouse, mouse wheel & multi-touch event stream abstraction. This is a support package for @thi.ng/rstream.
Status
STABLE - used in production
Search or submit any issues for this package
Breaking changes
v3.0.0
The gestureStream()
now supports external zoom control/resetting via providing
a subscription as zoom
option. That itself isn't a breaking change, however a
result of this is that the GestureEvent
s emitted by the stream do not always
contain the original DOM
event
anymore (i.e. not in the case when the zoom factor is being reset via attached
subscription).
v2.0.0
Multi-touch support has been added in v2.0.0, resulting in a complete
rewrite of gestureStream()
and new event data formats.
Related packages
- @thi.ng/hdom - Lightweight vanilla ES6 UI component trees with customizable branch-local behaviors
- @thi.ng/rdom - Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and @thi.ng/hiccup compatible
Installation
yarn add @thi.ng/rstream-gestures
ESM import:
import * as gest from "@thi.ng/rstream-gestures";
Browser ESM import:
<script type="module" src="https://esm.run/@thi.ng/rstream-gestures"></script>
JSDelivr documentation
For Node.js REPL:
const gest = await import("@thi.ng/rstream-gestures");
Package sizes (brotli'd, pre-treeshake): ESM: 1.20 KB
Dependencies
Note: @thi.ng/api is in most cases a type-only import (not used at runtime)
Usage examples
16 projects in this repo's
/examples
directory are using this package:
 | Canvas based dial widget | Demo | Source |
 | Interactive visualization of closest points on ellipses | Demo | Source |
 | Interactive inverse FFT toy synth | Demo | Source |
 | Doodle w/ K-nearest neighbor search result visualization | Demo | Source |
 | K-nearest neighbor search in an hash grid | Demo | Source |
 | Mouse gesture / stroke analysis, simplification, corner detection | Demo | Source |
 | Interactive pattern drawing demo using transducers | Demo | Source |
 | Canvas based Immediate Mode GUI components | Demo | Source |
 | Minimal IMGUI usage example | Demo | Source |
 | Worker based, interactive Mandelbrot visualization | Demo | Source |
| Basic rstream-gestures multi-touch demo | Demo | Source |
| Minimal rstream dataflow graph | Demo | Source |
 | Basic 2D scenegraph example with pan/zoom functionality | Demo | Source |
 | Minimal shader graph developed during livestream #2 | Demo | Source |
 | Multi-layer vectorization & dithering of bitmap images | Demo | Source |
 | rdom & WebGL-based image channel editor | Demo | Source |
API
Generated API docs
GestureType
All native events are abstracted into one of the following event types:
move
- movemove
start
- mousedown / touchstart
drag
- mousemove (whilst dragging) / touchmove
end
- mouseup / touchend / touchcancel
zoom
- wheel
GestureEvent
The stream emits
GestureEvent
objects of:
- type - Current translated/abstracted event type (
GestureType
)
- event - Original DOM event
- pos - Event position (transformed as per
GestureStreamOpts
)
- active - Active cursors (i.e. ongoing drag / touch gestures)
- buttons - Mouse button bitmask (same as in standard
MouseEvent
),
or, if isTouch
is true, number of active
touches.
- zoom - Current zoom factor (as per
GestureStreamOpts
config)
- zoomDelta - Last
WheelEvent
's transformed deltaY
,
wheelDeltaY
- isTouch - True, if original event was a
TouchEvent
{
"type": "drag"
"event": MouseEvent,
"pos": [254, 169],
"active": [
{
"id": 0,
"start": [443, 37],
"pos": [254, 169],
"delta": [-189, 132]
}
],
"buttons": 2,
"zoom": 1,
"zoomDelta": 0,
"isTouch": false
}
GestureStreamOpts
See the
GestureStreamOpts
config options for further details.
Basic usage
import { gestureStream } from "@thi.ng/rstream-gestures";
import { trace } from "@thi.ng/rstream";
import { comp, dedupe, filter, map, pluck } from "@thi.ng/transducers";
const gestures = gestureStream(document.body, { smooth: 0.01 });
gestures.subscribe(
trace("zoom"),
comp(pluck("zoom"), dedupe())
);
gestures.subscribe(
trace("distance"),
comp(
filter((e) => e.type === "drag"),
map((e) => e.active.map((g) => Math.hypot(...g.delta)))
)
);
Resettable zoom
For some applications (e.g. graphical editors), it can be helpful to reset the
zoom value. This can be done by supplying a stream/subscription as part of the
config options:
import { reactive } from "@thi.ng/rstream";
import { gestureStream } from "@thi.ng/rstream-gestures";
const zoomReset = reactive(1);
const gestures = gestureStream(document.body, {
smooth: 0.01,
zoom: zoomReset
});
zoomReset.next(2);
Authors
If this project contributes to an academic publication, please cite it as:
@misc{thing-rstream-gestures,
title = "@thi.ng/rstream-gestures",
author = "Karsten Schmidt and others",
note = "https://thi.ng/rstream-gestures",
year = 2018
}
License
© 2018 - 2025 Karsten Schmidt // Apache License 2.0