Reputation: 9402
I'm working on an interface to allow the user to drag an object around the screen using hammer.js. In a desktop browser it works, but on mobile when I start dragging it works briefly, then suddenly acts as if the event's client coordinates suddenly went to 0,0.
I've got a simple SVG circle I'm trying to drag:
<svg version="1.1" viewBox="0 0 640 480" id="svg" style="width: 640px; height: 480px; top:0px; left: 0px; position: absolute;">
<circle class="selhan" cx="320" cy="240" r="200" id="circ"
style="fill: none; stroke: rgb(0, 0, 0); pointer-events: all;
touch-action: none; user-select: none; -webkit-user-drag: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
</circle>
</svg>
I'm setting up a simple pan
handler:
var circ = document.getElementById("circ")
var Hn1=new Hammer(circ, {/*domEvents:true*/})
Hn1.add( new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0, pointers:1 }) )
var X0,Y0
Hn1.on("panstart", function(e) {
var ob = e.target
var cx = ob.getAttribute("cx")
var cy = ob.getAttribute("cy")
X0=e.center.x-cx
Y0=e.center.y-cy
})
Hn1.on("pan", function(e) {
var ob = e.target
var X = e.center.x-X0
var Y = e.center.y-Y0
ob.setAttribute("cx",X)
ob.setAttribute("cy",Y)
})
I have created a Fiddle to demonstrate. On mobile, if I put my finger in the center of the circle and move very slowly I see the circle track for a brief period of time, but then suddenly the center jumps to 0,0, whereas on desktop it follows the pointer around all day.
I created an Updated Fiddle which displays when panstart
, pancancel
, and panend
events occur. What I am seeing is that when the circle jumps to the origin I am getting a pancancel
event. Why is my pan being cancelled even though I haven't lifted my finger from the screen?
Even stranger is this version. All I did was reverse the order of the spans (which display counters of how many times Ok, turns out it's the element that is scrolling, not the circle. However, version 41 behaves strangely on desktop too... when I first tried it, I couldn't get it to respond to mouse events at all, but then it started working, and then it stopped again, all by simply changing to different versions and back.panstart
, pancancel
, and panend
have occurred). If the spans come after the SVG, then suddenly I can pan the circle, but only horizontally. But if the spans come before or aren't there, then panning gets abruptly cancelled after a short amount of finger movement.
Update: In an attempt to get to the bottom of why the pancancel
callback is being called, I instrumented my copy of hammer.js. The PanRecognizer directionTest
function (line 1778) is returning false, causing the cancel to be generated. What happens is always some form of "nothing happened", resulting in hasMoved
being false, or distance being 0 (I tried setting threshold to -1, but this just moved where the problem showed up), or direction being DIRECTION_NONE.
This still doesn't make a lot of sense - I see this happen even when I'm panning at a fast enough rate that I should never get zero movement between two events, and even if I was panning slowly I wouldn't expect this to be a problem.
Update 2: I added the following instrumentation:
Hn1.on("hammer.input",function(ev) {
console.log("debug",ev)
})
When I do this, I see a source event pointercancel
which suggests that the browser is cancelling the pointer motion in the middle of is actually being used. In reviewing the documentation for this event, none of the four reasons mentioned for a pointer event being cancelled applies in this case. What is going on here?!
Upvotes: 3
Views: 1545
Reputation: 177
Michael, I ran into the same problem as you. I've filed a bug report on GitHub with example and video. Interesting to see you uncovered it has something to do with "pointercancel" being triggered by the browser, but so far it hasn't helped me figure out how to patch this issue. Did you make any progress on the matter?
For reference, this StackOverflow thread talks about the same issue. Unfortunately, none of the fixes has so far worked for me for HammerJS.
EDIT: It turns out that preventing the default "touchmove" event handling on the window will solve this problem for any SVG element on the page. That's great news, but it also disables all scrolling behaviour on the page. What I've done instead is catching the "touchmove" event on the SVG object, so any descendants in it will pan properly. I'm not yet sure if it has any bad side effects, but so far it has meant that my panning in SVG finally works on Android browsers!
For completeness' sake, here is the necessary code:
const options = { passive: false }; // needed because Chrome has this set to "true" by default for "touchmove" events
mySVG.addEventListener(
"touchmove",
e => e.preventDefault(),
options
);
Upvotes: 2
Reputation: 19327
I just remembered that I just need to add jquery.ui.touch-punch.js and it works fine on mobile
library:
Upvotes: 0