I have a bunch of child divs in a scrollable area, something like this:
<div style='overflow: scroll;'>
<div id='a' />
<div id='b' />
<div id='c' />
...
</div>
I listen to pointerdown events on each child, and when one fires, I setup pointermove handlers on the document. eg:
const pointerdownHandle = e => {
e.target.releasePointerCapture(e.pointerId)
document.addEventListener('pointermove', pointermoveHandle)
document.addEventListener('pointerup', pointerupHandle)
}
const pointermoveHandle = e => { ... }
const pointerupHandle = {
document.removeEventListener('pointermove', pointermoveHandle)
document.removeEventListener('pointerup', pointerupHandle)
}
document.getElementById('a').addEventListener('pointerdown', pointerdownHandle)
This works great on desktop and on iOS safari. However on Android Chrome, the pointercancel event fires almost immediately, breaking things.
This appears to be the expected behaviour: "The pointercancel event is fired when the browser determines that there are unlikely to be any more pointer events, or if after the pointerdown event is fired, the pointer is then used to manipulate the viewport by panning, zooming, or scrolling."
The recommended solution is to apply the css property "touch-action: none" to the parent element. And this works. However unfortunately that will also break scrolling, because now touch actions are ignored.
I have tried programatically applying the css property after the pointerdown event has fired, but this does not work. Nor does adding preventDefault / stopPropagation to pointermoveHandle.
Has anyone got a solution to this problem? How can I stop the pointercancel event from firing without disabling scrolling on the parent element?
(I realize I can fall back on touch events, but pointer events, which support pointerenter and pointerleave, are much simpler and cleaner to work with..)
touch-action: pan-y
? – Igbo