diff --git a/src/drag.js b/src/drag.js index 790d9c7..70b5d77 100644 --- a/src/drag.js +++ b/src/drag.js @@ -34,26 +34,32 @@ export default function() { mousedowny, mousemoving, touchending, + framerate = 60, + timestamp = Date.now(), clickDistance2 = 0; function drag(selection) { selection - .on("mousedown.drag", mousedowned) + .on("pointerdown.drag", pointerdowned) .filter(touchable) - .on("touchstart.drag", touchstarted) - .on("touchmove.drag", touchmoved, nonpassive) - .on("touchend.drag touchcancel.drag", touchended) .style("touch-action", "none") .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); } - function mousedowned(event, d) { + function pointerdowned(event, d) { + requestAnimationFrame((t1) => { + requestAnimationFrame((t2) => { + framerate = 1000 / (t2 - t1); + }); + }); + if (touchending || !filter.call(this, event, d)) return; - var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse"); + + var gesture = beforestart(this, container.call(this, event, d), event, d, event.pointerId); if (!gesture) return; select(event.view) - .on("mousemove.drag", mousemoved, nonpassivecapture) - .on("mouseup.drag", mouseupped, nonpassivecapture); + .on("pointermove.drag", pointermoved, nonpassivecapture) + .on("pointerup.drag", pointerupped, nonpassivecapture); nodrag(event.view); nopropagation(event); mousemoving = false; @@ -62,64 +68,29 @@ export default function() { gesture("start", event); } - function mousemoved(event) { + function pointermoved(event) { + // Polling rate on some devices means our calculation of dx/dy will always result in 0 unless we wait long enough between updates + if (Date.now() - timestamp < (1000 / framerate)) return; + timestamp = Date.now(); + noevent(event); if (!mousemoving) { var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny; mousemoving = dx * dx + dy * dy > clickDistance2; } - gestures.mouse("drag", event); + gestures[event.pointerId]("drag", event); } - function mouseupped(event) { - select(event.view).on("mousemove.drag mouseup.drag", null); + function pointerupped(event) { + select(event.view).on("pointermove.drag pointerup.drag", null); yesdrag(event.view, mousemoving); noevent(event); - gestures.mouse("end", event); - } - - function touchstarted(event, d) { - if (!filter.call(this, event, d)) return; - var touches = event.changedTouches, - c = container.call(this, event, d), - n = touches.length, i, gesture; - - for (i = 0; i < n; ++i) { - if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) { - nopropagation(event); - gesture("start", event, touches[i]); - } - } - } - - function touchmoved(event) { - var touches = event.changedTouches, - n = touches.length, i, gesture; - - for (i = 0; i < n; ++i) { - if (gesture = gestures[touches[i].identifier]) { - noevent(event); - gesture("drag", event, touches[i]); - } - } - } - - function touchended(event) { - var touches = event.changedTouches, - n = touches.length, i, gesture; - - if (touchending) clearTimeout(touchending); - touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! - for (i = 0; i < n; ++i) { - if (gesture = gestures[touches[i].identifier]) { - nopropagation(event); - gesture("end", event, touches[i]); - } - } + gestures[event.pointerId]("end", event); } function beforestart(that, container, event, d, identifier, touch) { var dispatch = listeners.copy(), + pointerType = event.pointerType, p = pointer(touch || event, container), dx, dy, s; @@ -127,6 +98,7 @@ export default function() { sourceEvent: event, target: drag, identifier, + pointerType, active, x: p[0], y: p[1], @@ -134,10 +106,9 @@ export default function() { dy: 0, dispatch }), d)) == null) return; - - dx = s.x - p[0] || 0; - dy = s.y - p[1] || 0; - + dx = s.x - p[0] || 0; + dy = s.y - p[1] || 0; + return function gesture(type, event, touch) { var p0 = p, n; switch (type) { @@ -145,6 +116,7 @@ export default function() { case "end": delete gestures[identifier], --active; // falls through case "drag": p = pointer(touch || event, container), n = active; break; } + dispatch.call( type, that, @@ -153,6 +125,7 @@ export default function() { subject: s, target: drag, identifier, + pointerType, active: n, x: p[0] + dx, y: p[1] + dy, diff --git a/src/event.js b/src/event.js index 5f246fe..9782bf5 100644 --- a/src/event.js +++ b/src/event.js @@ -3,6 +3,7 @@ export default function DragEvent(type, { subject, target, identifier, + pointerType, active, x, y, dx, dy, dispatch @@ -13,6 +14,7 @@ export default function DragEvent(type, { subject: {value: subject, enumerable: true, configurable: true}, target: {value: target, enumerable: true, configurable: true}, identifier: {value: identifier, enumerable: true, configurable: true}, + pointerType: {value: pointerType, enumerable: true, configurable: true}, active: {value: active, enumerable: true, configurable: true}, x: {value: x, enumerable: true, configurable: true}, y: {value: y, enumerable: true, configurable: true},