diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index 4099d5dc967..e6dd4f75b0f 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -6,7 +6,7 @@ import {interpolates} from '@maplibre/maplibre-gl-style-spec'; import {LngLat} from '../../geo/lng_lat'; import {TransformProvider} from './transform-provider'; -import type {Map} from '../map'; +import type {GestureOptions, Map} from '../map'; import type Point from '@mapbox/point-geometry'; import type {AroundCenterOptions} from './two_fingers_touch'; import {Handler} from '../handler_manager'; @@ -30,7 +30,11 @@ const maxScalePerFrame = 2; */ export class ScrollZoomHandler implements Handler { _map: Map; + _cooperativeGesturesScreen: HTMLElement; + _cooperativeGestures: boolean | GestureOptions; _tr: TransformProvider; + _metaKey: keyof MouseEvent; + //canvasContainer _el: HTMLElement; _enabled: boolean; _active: boolean; @@ -66,6 +70,7 @@ export class ScrollZoomHandler implements Handler { constructor(map: Map, triggerRenderFrame: () => void) { this._map = map; this._tr = new TransformProvider(map); + this._metaKey = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; this._el = map.getCanvasContainer(); this._triggerRenderFrame = triggerRenderFrame; @@ -136,7 +141,9 @@ export class ScrollZoomHandler implements Handler { if (this.isEnabled()) return; this._enabled = true; this._aroundCenter = !!options && (options as AroundCenterOptions).around === 'center'; - this._map._setupCooperativeGestures(); + if (this._map.getCooperativeGestures()) { + this.setupCooperativeGestures(); + } } /** @@ -150,13 +157,15 @@ export class ScrollZoomHandler implements Handler { disable() { if (!this.isEnabled()) return; this._enabled = false; - this._map._destroyCooperativeGestures(); + if (this._map.getCooperativeGestures()) { + this.destroyCooperativeGestures(); + } } wheel(e: WheelEvent) { if (!this.isEnabled()) return; if (this._map._cooperativeGestures) { - if (e[this._map._metaKey]) { + if (e[this._metaKey]) { e.preventDefault(); } else { return; @@ -360,4 +369,48 @@ export class ScrollZoomHandler implements Handler { delete this._finishTimeout; } } + + setupCooperativeGestures() { + this._cooperativeGestures = this._map.getCooperativeGestures(); + this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map._container); + let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; + if (navigator.platform.indexOf('Mac') === 0) { + desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; + } + const mobileMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.mobileHelpText ? this._cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; + this._cooperativeGesturesScreen.innerHTML = ` +
${desktopMessage}
+
${mobileMessage}
+ `; + + // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures + this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); + + // Add event to canvas container since gesture container is pointer-events: none + this._el.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); + + // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) + this._el.classList.add('maplibregl-cooperative-gestures'); + } + + destroyCooperativeGestures() { + DOM.remove(this._cooperativeGesturesScreen); + this._el.removeEventListener('wheel', this._cooperativeGesturesOnWheel, false); + this._el.classList.remove('maplibregl-cooperative-gestures'); + } + + _cooperativeGesturesOnWheel = (event: WheelEvent) => { + this._onCooperativeGesture(event, event[this._metaKey], 1); + }; + + _onCooperativeGesture(event: any, metaPress, touches) { + if (!metaPress && touches < 2) { + // Alert user how to scroll/pan + this._cooperativeGesturesScreen.classList.add('maplibregl-show'); + setTimeout(() => { + this._cooperativeGesturesScreen.classList.remove('maplibregl-show'); + }, 100); + } + return false; + } } diff --git a/src/ui/handler/touch_pan.ts b/src/ui/handler/touch_pan.ts index be3eff4fdbe..d07999ac48c 100644 --- a/src/ui/handler/touch_pan.ts +++ b/src/ui/handler/touch_pan.ts @@ -46,7 +46,7 @@ export class TouchPanHandler implements Handler { if (this._map._cooperativeGestures) { if (this._minTouches === 2 && mapTouches.length < 2 && !this._cancelCooperativeMessage) { // If coop gesture enabled, show panning info to user - this._map._onCooperativeGesture(e, false, mapTouches.length); + this._map.scrollZoom._onCooperativeGesture(e, false, mapTouches.length); } else if (!this._cancelCooperativeMessage) { // If user is successfully navigating, we don't need this warning until the touch resets this._cancelCooperativeMessage = true; diff --git a/src/ui/map.ts b/src/ui/map.ts index 1f4e28bb579..02a18935fcb 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -450,15 +450,12 @@ export class Map extends Camera { style: Style; painter: Painter; handlers: HandlerManager; - _container: HTMLElement; _canvasContainer: HTMLElement; _controlContainer: HTMLElement; _controlPositions: {[_: string]: HTMLElement}; _interactive: boolean; _cooperativeGestures: boolean | GestureOptions; - _cooperativeGesturesScreen: HTMLElement; - _metaKey: keyof MouseEvent; _showTileBoundaries: boolean; _showCollisionBoxes: boolean; _showPadding: boolean; @@ -583,7 +580,6 @@ export class Map extends Camera { this._interactive = options.interactive; this._cooperativeGestures = options.cooperativeGestures; - this._metaKey = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; this._maxTileCacheSize = options.maxTileCacheSize; this._maxTileCacheZoomLevels = options.maxTileCacheZoomLevels; this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat; @@ -656,8 +652,8 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); - if (this._cooperativeGestures && options.scrollZoom) { - this._setupCooperativeGestures(); + if (this._cooperativeGestures) { + this.scrollZoom.setupCooperativeGestures(); } const hashName = (typeof options.hash === 'string' && options.hash) || undefined; @@ -1176,9 +1172,9 @@ export class Map extends Camera { setCooperativeGestures(gestureOptions?: GestureOptions | boolean | null): Map { this._cooperativeGestures = gestureOptions; if (this._cooperativeGestures) { - this._setupCooperativeGestures(); + this.scrollZoom.setupCooperativeGestures(); } else { - this._destroyCooperativeGestures(); + this.scrollZoom.destroyCooperativeGestures(); } return this; @@ -2940,39 +2936,6 @@ export class Map extends Camera { this._container.addEventListener('scroll', this._onMapScroll, false); } - _cooperativeGesturesOnWheel = (event: WheelEvent) => { - this._onCooperativeGesture(event, event[this._metaKey], 1); - }; - - _setupCooperativeGestures() { - const container = this._container; - this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', container); - let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; - if (navigator.platform.indexOf('Mac') === 0) { - desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; - } - const mobileMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.mobileHelpText ? this._cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; - this._cooperativeGesturesScreen.innerHTML = ` -
${desktopMessage}
-
${mobileMessage}
- `; - - // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures - this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); - - // Add event to canvas container since gesture container is pointer-events: none - this._canvasContainer.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); - - // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) - this._canvasContainer.classList.add('maplibregl-cooperative-gestures'); - } - - _destroyCooperativeGestures() { - DOM.remove(this._cooperativeGesturesScreen); - this._canvasContainer.removeEventListener('wheel', this._cooperativeGesturesOnWheel, false); - this._canvasContainer.classList.remove('maplibregl-cooperative-gestures'); - } - _resizeCanvas(width: number, height: number, pixelRatio: number) { // Request the required canvas size taking the pixelratio into account. this._canvas.width = Math.floor(pixelRatio * width); @@ -3047,17 +3010,6 @@ export class Map extends Camera { return false; }; - _onCooperativeGesture(event: any, metaPress, touches) { - if (!metaPress && touches < 2) { - // Alert user how to scroll/pan - this._cooperativeGesturesScreen.classList.add('maplibregl-show'); - setTimeout(() => { - this._cooperativeGesturesScreen.classList.remove('maplibregl-show'); - }, 100); - } - return false; - } - /** * Returns a Boolean indicating whether the map is fully loaded. * @@ -3286,7 +3238,7 @@ export class Map extends Camera { DOM.remove(this._canvasContainer); DOM.remove(this._controlContainer); if (this._cooperativeGestures) { - this._destroyCooperativeGestures(); + this.scrollZoom.destroyCooperativeGestures(); } this._container.classList.remove('maplibregl-map');