Skip to content

Commit

Permalink
Reimplement compass using DragRotate handler
Browse files Browse the repository at this point in the history
Reuse the existing code directly, rather than synthesizing mouse events, which doesn't work on IE (#4784) and triggers mouse event listeners unexpectedly (#5148).
  • Loading branch information
jfirebaugh committed Aug 17, 2017
1 parent 8bc8c8a commit f9ec635
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 86 deletions.
89 changes: 16 additions & 73 deletions src/ui/control/navigation_control.js
Original file line number Diff line number Diff line change
@@ -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.
*
Expand All @@ -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() {
Expand All @@ -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
});
}
40 changes: 27 additions & 13 deletions src/ui/handler/drag_rotate.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,31 @@ class DragRotateHandler {
_el: HTMLElement;
_enabled: boolean;
_active: boolean;
_button: 'right' | 'left';
_bearingSnap: number;
_pitchWithRotate: boolean;
_pos: Point;
_startPos: Point;
_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([
'_onDown',
'_onMove',
'_onUp'
], this);

}

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit f9ec635

Please sign in to comment.