From a1edf3a4cfeb980499ec0ea4c0b23be110d31868 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Thu, 5 Mar 2020 15:18:39 -0800 Subject: [PATCH] Use pointer events for node dragging and drawing (re: #5505) Enable dragging nodes with touches and styluses (close #7415) --- modules/behavior/drag.js | 34 ++++++++++++++-------------------- modules/behavior/draw.js | 36 +++++++++++++++++------------------- modules/behavior/draw_way.js | 2 +- modules/modes/drag_node.js | 2 +- modules/renderer/map.js | 15 +++++++++------ 5 files changed, 42 insertions(+), 47 deletions(-) diff --git a/modules/behavior/drag.js b/modules/behavior/drag.js index 5dd4329759..a92b457feb 100644 --- a/modules/behavior/drag.js +++ b/modules/behavior/drag.js @@ -5,8 +5,7 @@ import { event as d3_event, mouse as d3_mouse, select as d3_select, - selection as d3_selection, - touches as d3_touches + selection as d3_selection } from 'd3-selection'; import { osmNote } from '../osm'; @@ -37,6 +36,8 @@ export function behaviorDrag() { var _target; var _surface; + // use pointer events on supported platforms; fallback to mouse events + var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'); var d3_event_userSelectSuppress = function() { @@ -68,15 +69,14 @@ export function behaviorDrag() { _event = eventOf(_target, arguments); var eventTarget = d3_event.target; - var touchId = d3_event.touches ? d3_event.changedTouches[0].identifier : null; var offset; var startOrigin = point(); var started = false; - var selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag'); + var selectEnable = d3_event_userSelectSuppress(); d3_select(window) - .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove) - .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true); + .on(_pointerPrefix + 'move.drag', dragmove) + .on(_pointerPrefix + 'up.drag', dragend, true); if (_origin) { offset = _origin.apply(_target, arguments); @@ -85,16 +85,12 @@ export function behaviorDrag() { offset = [0, 0]; } - if (touchId === null) { - d3_event.stopPropagation(); - } + d3_event.stopPropagation(); function point() { var p = _surface || _target.parentNode; - return touchId !== null ? d3_touches(p).filter(function(p) { - return p.identifier === touchId; - })[0] : d3_mouse(p); + return d3_mouse(p); } @@ -134,8 +130,8 @@ export function behaviorDrag() { } d3_select(window) - .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null) - .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null); + .on(_pointerPrefix + 'move.drag', null) + .on(_pointerPrefix + 'up.drag', null); selectEnable(); } @@ -171,15 +167,13 @@ export function behaviorDrag() { } selection - .on('mousedown.drag' + _selector, delegate) - .on('touchstart.drag' + _selector, delegate); + .on(_pointerPrefix + 'down.drag' + _selector, delegate); } behavior.off = function(selection) { selection - .on('mousedown.drag' + _selector, null) - .on('touchstart.drag' + _selector, null); + .on(_pointerPrefix + 'down.drag' + _selector, null); }; @@ -199,8 +193,8 @@ export function behaviorDrag() { behavior.cancel = function() { d3_select(window) - .on('mousemove.drag', null) - .on('mouseup.drag', null); + .on(_pointerPrefix + 'move.drag', null) + .on(_pointerPrefix + 'up.drag', null); return behavior; }; diff --git a/modules/behavior/draw.js b/modules/behavior/draw.js index 8959569f48..1011af090a 100644 --- a/modules/behavior/draw.js +++ b/modules/behavior/draw.js @@ -3,8 +3,7 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; import { event as d3_event, mouse as d3_mouse, - select as d3_select, - touches as d3_touches + select as d3_select } from 'd3-selection'; import { behaviorEdit } from './edit'; @@ -35,6 +34,9 @@ export function behaviorDraw(context) { var _mouseLeave = false; var _lastMouse = null; + // use pointer events on supported platforms; fallback to mouse events + var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; + // related code // - `mode/drag_node.js` `datum()` @@ -57,29 +59,25 @@ export function behaviorDraw(context) { } - function mousedown() { + function pointerdown() { function point() { - var p = context.container().node(); - return touchId !== null ? d3_touches(p).filter(function(p) { - return p.identifier === touchId; - })[0] : d3_mouse(p); + return d3_mouse(context.container().node()); } var element = d3_select(this); - var touchId = d3_event.touches ? d3_event.changedTouches[0].identifier : null; var t1 = +new Date(); var p1 = point(); - element.on('mousemove.draw', null); + element.on(_pointerPrefix + 'move.draw', null); - d3_select(window).on('mouseup.draw', function() { + d3_select(window).on(_pointerPrefix + 'up.draw', function() { var t2 = +new Date(); var p2 = point(); var dist = geoVecLength(p1, p2); - element.on('mousemove.draw', mousemove); - d3_select(window).on('mouseup.draw', null); + element.on(_pointerPrefix + 'move.draw', pointermove); + d3_select(window).on(_pointerPrefix + 'up.draw', null); if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) { // Prevent a quick second click @@ -100,7 +98,7 @@ export function behaviorDraw(context) { } - function mousemove() { + function pointermove() { _lastMouse = d3_event; dispatch.call('move', this, datum()); } @@ -120,7 +118,7 @@ export function behaviorDraw(context) { } // related code - // - `mode/drag_node.js` `doMode()` + // - `mode/drag_node.js` `doMove()` // - `behavior/draw.js` `click()` // - `behavior/draw_way.js` `move()` function click() { @@ -215,8 +213,8 @@ export function behaviorDraw(context) { selection .on('mouseenter.draw', mouseenter) .on('mouseleave.draw', mouseleave) - .on('mousedown.draw', mousedown) - .on('mousemove.draw', mousemove); + .on(_pointerPrefix + 'down.draw', pointerdown) + .on(_pointerPrefix + 'move.draw', pointermove); d3_select(document) .call(keybinding); @@ -238,11 +236,11 @@ export function behaviorDraw(context) { selection .on('mouseenter.draw', null) .on('mouseleave.draw', null) - .on('mousedown.draw', null) - .on('mousemove.draw', null); + .on(_pointerPrefix + 'down.draw', null) + .on(_pointerPrefix + 'move.draw', null); d3_select(window) - .on('mouseup.draw', null); + .on(_pointerPrefix + 'up.draw', null); // note: keyup.space-block, click.draw-block should remain d3_select(document) diff --git a/modules/behavior/draw_way.js b/modules/behavior/draw_way.js index abe786b7d7..47c955ad96 100644 --- a/modules/behavior/draw_way.js +++ b/modules/behavior/draw_way.js @@ -76,7 +76,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin // related code - // - `mode/drag_node.js` `doMode()` + // - `mode/drag_node.js` `doMove()` // - `behavior/draw.js` `click()` // - `behavior/draw_way.js` `move()` function move(datum) { diff --git a/modules/modes/drag_node.js b/modules/modes/drag_node.js index ce85f717ea..131c312d22 100644 --- a/modules/modes/drag_node.js +++ b/modules/modes/drag_node.js @@ -192,7 +192,7 @@ export function modeDragNode(context) { if (!_nudgeInterval) { // If not nudging at the edge of the viewport, try to snap.. // related code - // - `mode/drag_node.js` `doMode()` + // - `mode/drag_node.js` `doMove()` // - `behavior/draw.js` `click()` // - `behavior/draw_way.js` `move()` var d = datum(); diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 759e19c608..0c77ba2cb1 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -64,6 +64,9 @@ export function rendererMap(context) { // whether a pointerdown event started the zoom var _pointerDown = false; + // use pointer events on supported platforms; fallback to mouse events + var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; + // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom; @@ -169,27 +172,27 @@ export function rendererMap(context) { _gestureTransformStart = projection.transform(); }) .on('gesturechange.surface', gestureChange) - .on('mousedown.zoom', function() { + .on(_pointerPrefix + 'down.zoom', function() { if (d3_event.button === 2) { d3_event.stopPropagation(); } }, true) - .on('mouseup.zoom', function() { + .on(_pointerPrefix + 'up.zoom', function() { if (resetTransform()) { immediateRedraw(); } }) - .on('mousemove.map', function() { + .on(_pointerPrefix + 'move.map', function() { _mouseEvent = d3_event; }) - .on('mouseover.vertices', function() { + .on(_pointerPrefix + 'over.vertices', function() { if (map.editableDataEnabled() && !_isTransformed) { var hover = d3_event.target.__data__; surface.call(drawVertices.drawHover, context.graph(), hover, map.extent()); dispatch.call('drawn', this, { full: false }); } }) - .on('mouseout.vertices', function() { + .on(_pointerPrefix + 'out.vertices', function() { if (map.editableDataEnabled() && !_isTransformed) { var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__; surface.call(drawVertices.drawHover, context.graph(), hover, map.extent()); @@ -898,7 +901,7 @@ export function rendererMap(context) { map.startEase = function() { - utilBindOnce(surface, 'mousedown.ease', function() { + utilBindOnce(surface, _pointerPrefix + 'down.ease', function() { map.cancelEase(); }); return map;