From 0473243930130d7bd033b345609e887b5d065b89 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Mon, 15 Jun 2020 12:27:53 -0400 Subject: [PATCH] Add workaround for broken rapid tapping on iOS 13.4+ (close #7694) --- css/80_app.css | 4 ++++ modules/renderer/map.js | 22 ++++++++++++++++++---- modules/ui/init.js | 20 +++++++++++++++++--- modules/util/detect.js | 8 ++++++++ 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index ba465a0c9..7dc4c5e42 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -25,6 +25,10 @@ -ms-user-select: none; -ms-content-zooming: none; } +.ideditor, .ideditor * { + /* disable pinch-to-zoom of the UI on touch devices */ + touch-action: pan-x pan-y; +} .main-content { position: relative; diff --git a/modules/renderer/map.js b/modules/renderer/map.js index e8b729f06..7ed26a2cb 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -175,10 +175,6 @@ export function rendererMap(context) { surface .call(drawLabels.observe) .call(_doubleUpHandler) - .on('gesturestart.surface', function() { - _gestureTransformStart = projection.transform(); - }) - .on('gesturechange.surface', gestureChange) .on(_pointerPrefix + 'down.zoom', function() { _lastPointerEvent = d3_event; if (d3_event.button === 2) { @@ -209,6 +205,24 @@ export function rendererMap(context) { } }); + var detected = utilDetect(); + + // only WebKit supports gesture events + if ('GestureEvent' in window && + // Listening for gesture events on iOS 13.4+ breaks double-tapping, + // but we only need to do this on desktop Safari anyway. – #7694 + !detected.isMobileWebKit) { + + // Desktop Safari sends gesture events for multitouch trackpad pinches. + // We can listen for these and translate them into map zooms. + surface + .on('gesturestart.surface', function() { + d3_event.preventDefault(); + _gestureTransformStart = projection.transform(); + }) + .on('gesturechange.surface', gestureChange); + } + // must call after surface init updateAreaFill(); diff --git a/modules/ui/init.js b/modules/ui/init.js index 19287ead7..35a5433bb 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -9,6 +9,7 @@ import { presetManager } from '../presets'; import { behaviorHash } from '../behavior'; import { modeBrowse } from '../modes/browse'; import { svgDefs, svgIcon } from '../svg'; +import { utilDetect } from '../util/detect'; import { utilGetDimensions } from '../util/dimensions'; import { uiAccount } from './account'; @@ -69,11 +70,24 @@ export function uiInit(context) { // disable double-tap-to-zoom on touchscreens d3_event.preventDefault(); - }) - // disable pinch-to-zoom in Safari - .on('gesturestart.ui gesturechange.ui gestureend.ui', function() { + }); + + var detected = utilDetect(); + + // only WebKit supports gesture events + if ('GestureEvent' in window && + // Listening for gesture events on iOS 13.4+ breaks double-tapping, + // but we only need to do this on desktop Safari anyway. – #7694 + !detected.isMobileWebKit) { + + // On iOS we disable pinch-to-zoom of the UI via the `touch-action` + // CSS property, but on desktop Safari we need to manually cancel the + // default gesture events. + container.on('gesturestart.ui gesturechange.ui gestureend.ui', function() { + // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari d3_event.preventDefault(); }); + } if ('PointerEvent' in window) { d3_select(window) diff --git a/modules/util/detect.js b/modules/util/detect.js index dd9c415a2..1eafa9c7b 100644 --- a/modules/util/detect.js +++ b/modules/util/detect.js @@ -78,6 +78,14 @@ export function utilDetect(refresh) { _detected.platform = 'Unknown'; } + _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || + // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent, + // so assume any "mac" with multitouch is actually iOS + (navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1)) && + /WebKit/.test(ua) && + !/Edge/.test(ua) && + !window.MSStream; + /* Locale */ // An array of locales requested by the browser in priority order.