feat(RenderWindowInteractor): add Tap and LongTap gestures - #3596
feat(RenderWindowInteractor): add Tap and LongTap gestures#3596UlysseDurand wants to merge 2 commits into
Conversation
20dfa20 to
af35a27
Compare
af35a27 to
1cd09c4
Compare
1cd09c4 to
485f201
Compare
| 'EndInteraction', | ||
| 'AnimationFrameRateUpdate', | ||
| 'Tap', | ||
| 'LongTap', |
There was a problem hiding this comment.
please add them after "Pan" events
| 'EndInteraction', | ||
| 'AnimationFrameRateUpdate', | ||
| 'Tap', | ||
| 'LongTap', |
| } | ||
|
|
||
| function distanceBetweenPositions(a, b) { | ||
| return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
longTapTimer != null to support longTapTimer=undefined
|
|
||
| function startLongTapTimer() { | ||
| if (longTapTimer !== null) { | ||
| clearTimeout(longTapTimer); |
| } | ||
| tapGestureActive = false; | ||
| tapPointerId = null; | ||
| if (longTapFired) { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
can't you reuse startingEventPositions ?
| return positions; | ||
| } | ||
|
|
||
| function distanceBetweenPositions(a, b) { |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
should probably have been already cancelled when a second pointer was made down.
|
Can you consider writing a test ? |
9ef22df to
0ac78f9
Compare
| /** | ||
| * @default true | ||
| */ | ||
| getRecognizeTapGestures(): boolean; |
| cancelTapGesture(); | ||
| tapObj.pointerId = pointerId; | ||
| tapObj.timer = setTimeout(() => { | ||
| cancelTapGesture(); |
There was a problem hiding this comment.
I would call it after longTapEvent
| let previousMouseButtons = 0; | ||
|
|
||
| // Tap / LongTap gesture tracking for touch and pen pointers. | ||
| let tapObj = { timer: null, pointerId: null }; |
| // Tests ------------------------------------------------------------------ | ||
|
|
||
| function tapTest(container, interactor, time, distance, expected) { | ||
| const finalX = 100 + distance / Math.sqrt(2); |
There was a problem hiding this comment.
move 100 into its own variable:
const origX = 100;
const finalX = origX + distance / Math.sqrt(2);
|
|
||
| tapTest(container, interactor, 490, 28, ['Tap']); | ||
| tapTest(container, interactor, 490, 32, []); | ||
| tapTest(container, interactor, 510, 28, ['LongTap']); |
There was a problem hiding this comment.
test when adding an additional touch
test when restarting a tap (and make sure a longtap still works)
0ac78f9 to
750c8c9
Compare
A simple test with 3 tap gestures cases is added
Remove 2 sqrt calls by comparing distances squared instead of distances originalDistance - newDistance is needed, we can't avoid using 2 sqrts for them
750c8c9 to
4f9e9a4
Compare
| @@ -1132,12 +1191,10 @@ function vtkRenderWindowInteractor(publicAPI, model) { | |||
| // of movement it is and then deal with it. | |||
| // calculate the distances | |||
| const originalDistance = Math.sqrt( | |||
There was a problem hiding this comment.
I think you can work with originalDistance2, you don't need the sqrt
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
TapEventandLongTapevents through the standardhandledEventsmechanism, alongside the existing press/move/release events.Changes
Sources/Rendering/Core/RenderWindowInteractor/index.jsTap, andLongTaptohandledEvents.Sources/Rendering/Core/RenderWindowInteractor/index.d.tshandledEventsenum,invokeTap,invokeLongTapand the correspondingon*/*Eventtypes, plus the new initial values/getters.Examples/Applications/TapGestureDemo/index.jsrecognizeTapGestures(true)longTapDuration(500 ms)longTapDistance(30 px)PR and Code Checklist
npm run reformatto have correctly formatted codeTesting
TapGestureDemoexample and tap and long-tap with a touch device or pen.