biodiv / contactjs Goto Github PK
View Code? Open in Web Editor NEWPointer gestures for your webapp
License: MIT License
Pointer gestures for your webapp
License: MIT License
I'm trying to debug an issue I'm having with contact.js when using it via Chromium on a Raspberry Pi with touchscreen. It seems like a pointer-down event cancels early and fires onPointerCancel when you start panning, which then stops any pan/swipe event from working.
I'm not really sure if this is something specific to Chromium or the touchscreen drivers, but while debugging this I was noticing an error firing in the console relating to pointerupEvent being undefined.
This is the code causing the issue:
onPointerCancel (pointercancelEvent) {
this.onPointerUp(pointerupEvent);
if (this.DEBUG == true){
console.log("[Contact] pointercancel detected");
}
}
This line:
Line 137 in 17d6df9
Looks like 'pointerupEvent' should be 'pointercancelEvent'?
The documentation states that hooks can be added for the native JavaScript events, like pointerDown
etc. But the actual code uses all lowercase names and the hooks therefore did not work for me at first.
Hi thank you for an alternative library for HammerJS. π
Could you also support press actions?
It seems that v2.0.3 is missing a few types that are pretty important. I added them at one point after the initial TypeScript migration, but it seems they got lost when the v2 branch got merged.
I added them back in the following commits:
We should probably release a version v2.0.4 that includes these changes.
Hey, thx again for your amazing work !
I just have a small note about the documentation. What are the default values ββfor the recognizer-options in this page : https://biodiv.github.io/contactjs/documentation/recognizer-options/ ? ( maxDuration, maxDistance, bubbles, etc...) Could be great to add them in the doc.
Thanks
When I register for Pan gestures, I also get click events from event PointerEvent. Seems that Tap events are fired, which I did not register in the options. Why is that, how can I disable it?
After installing 2.x
I couldn't build the project. So I started going back in versions.
I'm having this error while building ReferenceError: CustomEvent is not defined
.
Moving back to 1.4.1
and using CustomEvent
in my code fixed the issue.
I guess you need to import that type in the contactjs code?
I don't know if it's a bug or if I didn't understand how to do it, but how to get multiples tap at the same time like on hammer.js ?
Ex :
var PointerListener = new PointerListener(document.body);
document.querySelectorAll('.box').forEach(box => {
box.addEventListener('tap, function(event){
// do something
});
});
For the moment if i "tap" on 3 boxes with 3 different fingers at the same time nothing happen !
DEBUG just say !
[PointerListener] pointerdown event detected 2 contact.nomodule.min.js:1:47954
[PointerListener] pointerup event detected contact.nomodule.min.js:1:48580
[PointerListener] hadActiveGestureDuringCurrentContact: false contact.nomodule.min.js:1:51538
[PointerListener] pointerup event detected contact.nomodule.min.js:1:48580
[PointerListener] hadActiveGestureDuringCurrentContact: false contact.nomodule.min.js:1:51538
Thanks for help !
When I add a Tap event, using mouse as input will trigger the event on all buttons (left-, middle-, right-click, even forward/back-clicks).
How do I limit the Tap listener to only be used on left-click?
Started working on Haxe version still very early stages, setup documentation to test structures and started to create some typed structures. Very ugly still subject to extensive changes and many methods yet to be populated, but a start atleast.
https://github.com/nanjizal/contacthx
I think later it maybe possible to autogenerate TS externs ( or easier ) but not a priority, more interested in fitting it to haxe toolkits that also do js and c++. Be aware stil learning about your library so details maybe far from ideal in this code at moment.
Based on the hints from ...
https://pagespeed.web.dev/report?url=https%3A%2F%2Fbiodiv.github.io%2Fcontactjs%2F
... this might be good to implement?
In general, this library is a GREAT replacement of hammer.js - thank you for that!
Hello
Firstly, thank you for creating this. I have tried various libraries including HammerJS and InteractJS and both failed me for multitouch with multiple users. Your library so far is looking incredibly promising.
I do have one issue though that I wanted to run by you.
I want to include pan, rotation and pinch in my app.
What I am experiencing which I want to check is the expected behaviour is when I do a pinch, a pan is also taking place after the pinchend despite not lifting my fingers from the touch table. It is possible one or both fingers leave the element that is being pinched but I am definitely not lifting my fingers off the table. This behaviour seems wrong as it caused my element being pinch zoomed to move off to the right or left.
Can you confirm if this is the expected behaviour.
I did try to eliminate this as follows but this appeared to have no effect:
let pan = new Contact.Pan(modal);
let pinch = new Contact.Pinch(modal);
pan.block(pinch);
pinch.block(pan);
Looking at my console with debugging for gestures I see the following:
[Gestures] firing event: pinchend
App.vue:246 pinchend
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 1, maxValue: 1, current value: 1
contact.module.js:884 [Gestures] checking duration[gesture.isActive: false] minValue: 0, maxValue: null, current value: 226.60000002384186
contact.module.js:884 [Gestures] checking currentSpeed[gesture.isActive: false] minValue: null, maxValue: null, current value: 3216.6920023552966
contact.module.js:884 [Gestures] checking averageSpeed[gesture.isActive: false] minValue: null, maxValue: null, current value: 0
contact.module.js:884 [Gestures] checking finalSpeed[gesture.isActive: false] minValue: null, maxValue: null, current value: null
contact.module.js:884 [Gestures] checking distance[gesture.isActive: false] minValue: 10, maxValue: null, current value: 353.83612025908263
contact.module.js:1162 [Gestures] firing event: panstart
App.vue:288 panstart
contact.module.js:1097 [Gestures] detected and firing event pan
contact.module.js:1132 [Gestures] detected and firing event panleft
contact.module.js:972 [Gestures] running recognition for rotate
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minrotate: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pinch
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minpinch: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: true] minValue: 1, maxValue: 1, current value: 1
contact.module.js:884 [Gestures] checking duration[gesture.isActive: true] minValue: null, maxValue: null, current value: 226.60000002384186
contact.module.js:884 [Gestures] checking currentSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 3216.6920023552966
contact.module.js:884 [Gestures] checking averageSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 0
contact.module.js:884 [Gestures] checking finalSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: null
contact.module.js:884 [Gestures] checking distance[gesture.isActive: true] minValue: null, maxValue: null, current value: 353.83612025908263
contact.module.js:1097 [Gestures] detected and firing event pan
contact.module.js:1132 [Gestures] detected and firing event panleft
contact.module.js:972 [Gestures] running recognition for rotate
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minrotate: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pinch
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minpinch: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: true] minValue: 1, maxValue: 1, current value: 1
contact.module.js:884 [Gestures] checking duration[gesture.isActive: true] minValue: null, maxValue: null, current value: 233.39999997615814
contact.module.js:884 [Gestures] checking currentSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 3063.383870866316
contact.module.js:884 [Gestures] checking averageSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 0
contact.module.js:884 [Gestures] checking finalSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: null
contact.module.js:884 [Gestures] checking distance[gesture.isActive: true] minValue: null, maxValue: null, current value: 314.91586177898375
contact.module.js:1097 [Gestures] detected and firing event pan
contact.module.js:1132 [Gestures] detected and firing event panleft
contact.module.js:1357 [Pan] preventing touchmove default
contact.module.js:972 [Gestures] running recognition for rotate
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minrotate: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pinch
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minpinch: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: true] minValue: 1, maxValue: 1, current value: 1
contact.module.js:884 [Gestures] checking duration[gesture.isActive: true] minValue: null, maxValue: null, current value: 248.30000001192093
contact.module.js:884 [Gestures] checking currentSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 2725.1942100459755
contact.module.js:884 [Gestures] checking averageSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 0
contact.module.js:884 [Gestures] checking finalSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: null
contact.module.js:884 [Gestures] checking distance[gesture.isActive: true] minValue: null, maxValue: null, current value: 320.7553584899245
contact.module.js:1097 [Gestures] detected and firing event pan
contact.module.js:1132 [Gestures] detected and firing event panleft
contact.module.js:1357 [Pan] preventing touchmove default
contact.module.js:972 [Gestures] running recognition for rotate
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minrotate: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pinch
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: false] minValue: 2, maxValue: 2, current value: 1
contact.module.js:890 dismissing minpinch: required pointerCount: 2, current value: 1
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:884 [Gestures] checking pointerCount[gesture.isActive: true] minValue: 1, maxValue: 1, current value: 1
contact.module.js:884 [Gestures] checking duration[gesture.isActive: true] minValue: null, maxValue: null, current value: 255.39999997615814
contact.module.js:884 [Gestures] checking currentSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 2455.679987135455
contact.module.js:884 [Gestures] checking averageSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: 0
contact.module.js:884 [Gestures] checking finalSpeed[gesture.isActive: true] minValue: null, maxValue: null, current value: null
contact.module.js:884 [Gestures] checking distance[gesture.isActive: true] minValue: null, maxValue: null, current value: 252.1983346495373
contact.module.js:1097 [Gestures] detected and firing event pan
contact.module.js:1132 [Gestures] detected and firing event panleft
contact.module.js:1357 [Pan] preventing touchmove default
contact.module.js:972 [Gestures] running recognition for rotate
contact.module.js:922 [Gestures] dismissing rotate: requiresActivePointer required: true, actual value: false
contact.module.js:972 [Gestures] running recognition for pinch
contact.module.js:922 [Gestures] dismissing pinch: requiresActivePointer required: true, actual value: false
contact.module.js:972 [Gestures] running recognition for pan
contact.module.js:922 [Gestures] dismissing pan: requiresActivePointer required: true, actual value: false
contact.module.js:1097 [Gestures] detected and firing event swipe
contact.module.js:1132 [Gestures] detected and firing event swipeleft
contact.module.js:1184 [Gestures] firing event: panend
App.vue:310 panend
Not so much an "issue", but for your consideration.
I noticed that the touch event listeners are attached directly onto the element passed to PointerListener
. This makes sense as it remains close to the EventTarget interface of the DOM element and gives the programmer the discretion to be responsible for cleaning up the listeners.
However, I can imagine an use case where the DOM element only gets event handlers for the touch events that are managed by PointerListener. It should also be possible to dispose a PointerListener instance throughout an applications lifetime (because the touch enabled elements are added and removed from the DOM depending on application state).
Would it make sense to have an interface added to PointerListener
that is similar to this:
Where type is the event type and handlerReference is the callback which is invoked whenever the event is dispatched. Since PointerListener has a reference to the element it manages, it can internally invoke element.addEventListener( type, handler )
.
Which is the inverse of PointerListener.on
and removes the previously attached listener from the element.
So far, the above doesn't provide any benefit over the current implementation. However:
To be invoked when the PointerListener is no longer needed. This would remove all event listeners attached to the element using PointerListener.on
allowing for an instant clean up. It also provides a benefit in the case other event handlers were attached to the DOM element (consider drop event handling) that are separate from the responsibilities of contactjs (and that need to be remain while only the touch handling is removed).
edit this method could also remove the touchmove
listeners that are added internally in addTouchListeners
which don't seem to be removed ?
The above would also greatly help preventing memory leaks (this is of course not a guaranteed problem as this is also up to the implementation, however I feel like offering a self managing event interface would be a welcome addition).
Hi,
I must not use GPL software. This means I won't use it, and can't help you to improve the library.
Why do you choose the viral GPL?
The doc is still listing gesture : gestureInstance,
, which is not up to date. it should be replaced with recognizer
Sorry I use issues for this kind of questions.
Do I understand correctly that I need to use CustomEvent<GestureEventData>
for the handler functions?
And if so, what do I do with the addEventListener
call type errors? It expects to have Event
for the event parameter, but gets CustomEvent<GestureEventData>
. Is there a wrapping function that could avoid this type conflict or am I missing something?
Should I use some workarounds to make TS linter happy?
Scenario: user pans element with one finger to another place. Then adds second finger and pinches. The GestureEventData.global.scale
is then sometimes off because the initial position of the first finger is used in the calculation.
Using the position of the finger when the gesture (pinch) is detected for the first time instead of when the pointer hit the surface for the first time for GestureEventData.global
should fix this problem.
Atm a lot of the frontend dev is done using TypeScript.
Do you plan to add types to the lib later on?
This has become a very common interaction in mobile devices: Google maps, Apple.
The way it works:
It would be great if this was included in the library and easy to add!
Provide a guide in the documentation for how to migrate from hammer.js to contact.js
https://biodiv.github.io/contactjs/documentation/contact-js/#Events
the documentation for Events should include swipeRight
and swipeLeft
event listeners
Hi there,
first of all fantastic work on the library as its a nice up-to-date variant of a certain popular library.
While I find the implementation of pinch much more accurate than HammerJS provides, I struggle to combine a pinch
and twofingerpan
listener on the same element. Basically the pan handler is conflicting with the pinch making it impossible to zoom, or vice versa. In HammerJS there was the concept of recognizeWith
which would give a PointerListener awareness of the other basically managing their priorities.
Is there something similar available or is my approach a little too naive ? My current code is:
const listener = new Contact.PointerListener( element, {
supportedGestures: [ Contact.Pinch, Contact.TwoFingerPan ]
});
element.addEventListener( "pinch", event => {
if ( this.panOrigin ) {
return; // attempt to not pinch while panning
}
if (!this.orgZoomLevel) {
this.orgZoomLevel = this.zoomLevel; // zoomLevel is a local reactive property (numerical)
}
const value = Math.max( MIN_ZOOM, Math.min( MAX_ZOOM, this.orgZoomLevel * event.detail.global.scale ));
this.zoomLevel = value; // updates reactive property which updates DOM
});
element.addEventListener( "pinchend", () => {
this.orgZoomLevel = null;
});
element.addEventListener( "twofingerpan", () => {
if (this.orgZoomLevel) {
return; // attempt to not pan while zooming
}
if ( !this.panOrigin ) {
this.panOrigin = { ...viewport }; // is bounding box of coordinates (left, top, width, height)
}
const { deltaX, deltaY } = event.detail.global;
this.panViewport( this.panOrigin.left - deltaX, this.panOrigin.top - deltaY ); // updates reactive property which updates DOM
});
element.addEventListener( "twofingerpanend", () => {
this.panOrigin = null;
});
Attaching either the pinch
or twofingerpan
listeners separately from each other works fine, when adding them both, twofingerpan
becomes dominant.
Not sure what's up and how to properly debug this.
I have a preact app and while I dev, the lib is working properly.
But in prod the event handlers bound to the element don't get called.
touch*
event handlers are working fine.
I set the DEBUG
to true
, the PointerListener
gets initialised and I get the debug info in the prod build.
But it's a lot of data and I'm not sure what to look for to understand the issue.
I tried different options to initialise with, but it makes no difference.
UPD
I think it's the minification that is messing up the code.
The event names get optimised, so for example panup
becomes qup
.
I'm not an expert in this, but if I'm not mistaken these event names should be assigned as strings and not variables. This way they'll get through the optimisations intact.
I saw in the documentation that nothing seem to happen for tap/press on screen between 200ms and 600ms ?
Is there a specific reason ?
Hammer.js used 250ms max duration for Tap and 251ms min duration for Press.
Maybe it could be good idea to to the same for contact.js ?
Do you want to provide an NPM Package, instead of downloading the min.js
file?
Thanks for providing this lib :-).
When I build my Project (typescript: 4.9.4) with a contactjs dependency, I receive the following error:
Error: node_modules/contactjs/dist/index.d.ts:18:1 - error TS1046: Top-level declarations in .d.ts files must start with either a 'declare' or 'export' modifier.
18 enum PointerManagerState {
~~~~
Could you export or declare these?
Can i pass global and/or individual duration properties for the different gestures somewhere?
I.e:
a) I want to set the global timer for a Tap event to register within max 600ms
b) I want to set some specific individual Tap events to 1000ms
(I want neither of the above to mess with timers of other gestures than Tap)
As the title says, pinching out an element does nothing. Only after a pinch in I can then normally pinch out.
You can reproduce this here: https://biodiv.github.io/contactjs/
Try to pinch out the square without pinching in, it won't shrink.
I did a bit of debugging and pinchstart
doesn't fire in this case.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.