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?!