Skip to content

feat(RenderWindowInteractor): add Tap and LongTap gestures - #3596

Open
UlysseDurand wants to merge 1 commit into
Kitware:masterfrom
UlysseDurand:feat-interactor-tap-gestures
Open

feat(RenderWindowInteractor): add Tap and LongTap gestures#3596
UlysseDurand wants to merge 1 commit into
Kitware:masterfrom
UlysseDurand:feat-interactor-tap-gestures

Conversation

@UlysseDurand

@UlysseDurand UlysseDurand commented Aug 10, 2026

Copy link
Copy Markdown

Context

There is a need for mobile web applications made with vtk-js to have more control interactions, especially because right click isn't available. The LongTap event can replace the right click, Tap comes along the way.

Results

  • Touch/pen pointers now emit dedicated TapEvent and LongTap events through the standard handledEvents mechanism, alongside the existing press/move/release events.
  • New configurable options allow tuning gesture detection per application.

Changes

  • Sources/Rendering/Core/RenderWindowInteractor/index.js
    • Added Tap, and LongTap to handledEvents.
    • Added gesture tracking (pointer ID, position, timers) for single touch/pen pointers, canceling gestures on multitouch or movement beyond the long-press distance.
  • Sources/Rendering/Core/RenderWindowInteractor/index.d.ts
    • Added new events to handledEvents enum, invokeTap, invokeLongTap and the corresponding on*/*Event types, plus the new initial values/getters.
  • Examples/Applications/TapGestureDemo/index.js
    • New demo application to try the three gestures.
  • New configurable values (defaults):
    • recognizeTapGestures (true)
    • longTapDuration (500 ms)
    • longTapDistance (30 px)
  • Documentation and TypeScript definitions were updated to match those changes

PR and Code Checklist

  • semantic-release commit messages
  • Run npm run reformat to have correctly formatted code

Testing

  • Demo: run the TapGestureDemo example and tap and long-tap with a touch device or pen.
  • No unit tests were added: existing Pan/Pinch/Rotate gestures are not unit-tested either.
  • Tested example with:
    • vtk.js: master
    • OS: Linux
    • Browser: Chrome on an Android tablet

@UlysseDurand
UlysseDurand force-pushed the feat-interactor-tap-gestures branch from 20dfa20 to af35a27 Compare August 10, 2026 14:29
@UlysseDurand UlysseDurand changed the title feat(RenderWindowInteractor): add Tap, DoubleTap, LongPress gestures feat(RenderWindowInteractor): add Tap and LongPress gestures Aug 10, 2026
@UlysseDurand
UlysseDurand force-pushed the feat-interactor-tap-gestures branch from af35a27 to 1cd09c4 Compare August 10, 2026 14:32
@UlysseDurand UlysseDurand changed the title feat(RenderWindowInteractor): add Tap and LongPress gestures feat(RenderWindowInteractor): add Tap and LongTap gestures Aug 10, 2026
@UlysseDurand
UlysseDurand force-pushed the feat-interactor-tap-gestures branch from 1cd09c4 to 485f201 Compare August 11, 2026 08:14
'EndInteraction',
'AnimationFrameRateUpdate',
'Tap',
'LongTap',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add them after "Pan" events

'EndInteraction',
'AnimationFrameRateUpdate',
'Tap',
'LongTap',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to move after "Pan" events

}

function distanceBetweenPositions(a, b) {
return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't compute sqrt, it is expensive: distanceBetweenPositions --> distance2BetweenPositions.

It can be a separate commit (because you would need to consider the pinchDistance, rotateDistance and panDistance as well)

let tapGestureActive = false;

function cancelTapGesture() {
if (longTapTimer !== null) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

longTapTimer != null to support longTapTimer=undefined


function startLongTapTimer() {
if (longTapTimer !== null) {
clearTimeout(longTapTimer);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

longTapTimer = null

}
tapGestureActive = false;
tapPointerId = null;
if (longTapFired) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you delete tapObject when you fire a long tap, you wouldn't have to keep the information of "fired" or not.

* Enable/Disable recognition of tap and long-press gestures.
* @param recognizeTapGestures
*/
setRecognizeTapGestures(recognizeTapGestures: boolean): boolean;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you want to add Tap gesture recognition granularity ?
Or said differently, by recognizing tap gestures, do you change the behavior of regular gestures ? do you decrease performance ?

longTapTimer = null;
}
tapPointerId = null;
tapStartPosition = null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't you reuse startingEventPositions ?

return positions;
}

function distanceBetweenPositions(a, b) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can take the opportunity in the file to call this function where the math is done manually (e.g. pinchDistance, rotateDistance and panDistance) . It can be a separate commit.

publicAPI.handleTouchMove = (event) => {
const pointers = [...pointerCache.values()];
if (model.recognizeGestures && pointers.length > 1) {
cancelTapGesture();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably have been already cancelled when a second pointer was made down.

@finetjul

Copy link
Copy Markdown
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants