From f9ec6356d5757a035a259708af17c9b7ebb50e9b Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 16 Aug 2017 17:31:51 -0700 Subject: [PATCH] Reimplement compass using DragRotate handler Reuse the existing code directly, rather than synthesizing mouse events, which doesn't work on IE (#4784) and triggers mouse event listeners unexpectedly (#5148). --- src/ui/control/navigation_control.js | 89 +++++----------------------- src/ui/handler/drag_rotate.js | 40 +++++++++---- 2 files changed, 43 insertions(+), 86 deletions(-) diff --git a/src/ui/control/navigation_control.js b/src/ui/control/navigation_control.js index e6b85b9f3d2..58634a9bbfe 100644 --- a/src/ui/control/navigation_control.js +++ b/src/ui/control/navigation_control.js @@ -1,13 +1,11 @@ // @flow const DOM = require('../../util/dom'); -const window = require('../../util/window'); const util = require('../../util/util'); +const DragRotateHandler = require('../handler/drag_rotate'); import type Map from '../map'; -const className = 'mapboxgl-ctrl'; - /** * A `NavigationControl` control contains zoom buttons and a compass. * @@ -25,11 +23,20 @@ class NavigationControl { _zoomOutButton: HTMLElement; _compass: HTMLElement; _compassArrow: HTMLElement; + _handler: DragRotateHandler; constructor() { util.bindAll([ '_rotateCompassArrow' ], this); + + this._container = DOM.create('div', 'mapboxgl-ctrl mapboxgl-ctrl-group'); + this._container.addEventListener('contextmenu', (e) => e.preventDefault()); + + this._zoomInButton = this._createButton('mapboxgl-ctrl-icon mapboxgl-ctrl-zoom-in', 'Zoom In', () => this._map.zoomIn()); + this._zoomOutButton = this._createButton('mapboxgl-ctrl-icon mapboxgl-ctrl-zoom-out', 'Zoom Out', () => this._map.zoomOut()); + this._compass = this._createButton('mapboxgl-ctrl-icon mapboxgl-ctrl-compass', 'Reset North', () => this._map.resetNorth()); + this._compassArrow = DOM.create('span', 'mapboxgl-ctrl-compass-arrow', this._compass); } _rotateCompassArrow() { @@ -39,93 +46,29 @@ class NavigationControl { onAdd(map: Map) { this._map = map; - this._container = DOM.create('div', `${className} ${className}-group`, map.getContainer()); - this._container.addEventListener('contextmenu', this._onContextMenu.bind(this)); - - this._zoomInButton = this._createButton(`${className}-icon ${className}-zoom-in`, 'Zoom In', map.zoomIn.bind(map)); - this._zoomOutButton = this._createButton(`${className}-icon ${className}-zoom-out`, 'Zoom Out', map.zoomOut.bind(map)); - this._compass = this._createButton(`${className}-icon ${className}-compass`, 'Reset North', map.resetNorth.bind(map)); - - this._compassArrow = DOM.create('span', `${className}-compass-arrow`, this._compass); - - this._compass.addEventListener('mousedown', this._onCompassDown.bind(this)); - - util.bindAll(['_onCompassMove', '_onCompassUp'], this); - this._map.on('rotate', this._rotateCompassArrow); this._rotateCompassArrow(); - + this._handler = new DragRotateHandler(map, {button: 'left', element: this._compass, pitchWithRotate: false}); + this._handler.enable(); return this._container; } onRemove() { DOM.remove(this._container); this._map.off('rotate', this._rotateCompassArrow); - this._map = (undefined: any); - } - - _onContextMenu(e: MouseEvent) { - e.preventDefault(); - } + delete this._map; - _onCompassDown(e: MouseEvent) { - if (e.button !== 0) return; - - DOM.disableDrag(); - window.document.addEventListener('mousemove', this._onCompassMove); - window.document.addEventListener('mouseup', this._onCompassUp); - - this._map.getCanvasContainer().dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); - } - - _onCompassMove(e: MouseEvent) { - if (e.button !== 0) return; - - this._map.getCanvasContainer().dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); - } - - _onCompassUp(e: MouseEvent) { - if (e.button !== 0) return; - - window.document.removeEventListener('mousemove', this._onCompassMove); - window.document.removeEventListener('mouseup', this._onCompassUp); - DOM.enableDrag(); - - this._map.getCanvasContainer().dispatchEvent(copyMouseEvent(e)); - e.stopPropagation(); + this._handler.disable(); + delete this._handler; } _createButton(className: string, ariaLabel: string, fn: () => mixed) { const a = DOM.create('button', className, this._container); a.type = 'button'; a.setAttribute('aria-label', ariaLabel); - a.addEventListener('click', () => { fn(); }); + a.addEventListener('click', fn); return a; } - } module.exports = NavigationControl; - -function copyMouseEvent(e) { - return new window.MouseEvent(e.type, { - button: 2, // right click - buttons: 2, // right click - bubbles: true, - cancelable: true, - detail: e.detail, - view: e.view, - screenX: e.screenX, - screenY: e.screenY, - clientX: e.clientX, - clientY: e.clientY, - movementX: e.movementX, - movementY: e.movementY, - ctrlKey: e.ctrlKey, - shiftKey: e.shiftKey, - altKey: e.altKey, - metaKey: e.metaKey - }); -} diff --git a/src/ui/handler/drag_rotate.js b/src/ui/handler/drag_rotate.js index 34f8b3d46ad..55accf7c5f7 100644 --- a/src/ui/handler/drag_rotate.js +++ b/src/ui/handler/drag_rotate.js @@ -27,6 +27,7 @@ class DragRotateHandler { _el: HTMLElement; _enabled: boolean; _active: boolean; + _button: 'right' | 'left'; _bearingSnap: number; _pitchWithRotate: boolean; _pos: Point; @@ -34,10 +35,16 @@ class DragRotateHandler { _inertia: Array<[number, number]>; _center: Point; - constructor(map: Map, options: any) { + constructor(map: Map, options: { + button?: 'right' | 'left', + element?: HTMLElement, + bearingSnap?: number, + pitchWithRotate?: boolean + }) { this._map = map; - this._el = map.getCanvasContainer(); - this._bearingSnap = options.bearingSnap; + this._el = options.element || map.getCanvasContainer(); + this._button = options.button || 'right'; + this._bearingSnap = options.bearingSnap || 0; this._pitchWithRotate = options.pitchWithRotate !== false; util.bindAll([ @@ -45,7 +52,6 @@ class DragRotateHandler { '_onMove', '_onUp' ], this); - } /** @@ -95,16 +101,22 @@ class DragRotateHandler { if (this._map.dragPan && this._map.dragPan.isActive()) return; if (this.isActive()) return; - const button = (e.ctrlKey ? 0 : 2); // ? ctrl+left button : right button - let eventButton = e.button; - if (typeof window.InstallTrigger !== 'undefined' && e.button === 2 && e.ctrlKey && - window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) { - // Fix for https://github.com/mapbox/mapbox-gl-js/issues/3131: - // Firefox (detected by InstallTrigger) on Mac determines e.button = 2 when - // using Control + left click - eventButton = 0; + if (this._button === 'right') { + const button = (e.ctrlKey ? 0 : 2); // ? ctrl+left button : right button + let eventButton = e.button; + if (typeof window.InstallTrigger !== 'undefined' && e.button === 2 && e.ctrlKey && + window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) { + // Fix for https://github.com/mapbox/mapbox-gl-js/issues/3131: + // Firefox (detected by InstallTrigger) on Mac determines e.button = 2 when + // using Control + left click + eventButton = 0; + } + if (eventButton !== button) return; + } else { + if (e.ctrlKey || e.button !== 0) return; } - if (eventButton !== button) return; + + DOM.disableDrag(); window.document.addEventListener('mousemove', this._onMove, {capture: true}); window.document.addEventListener('mouseup', this._onUp); @@ -162,6 +174,8 @@ class DragRotateHandler { window.document.removeEventListener('mouseup', this._onUp); window.removeEventListener('blur', (this._onUp: any)); + DOM.enableDrag(); + if (!this.isActive()) return; this._active = false;