Spaces:
Sleeping
Sleeping
| // @flow | |
| import DOM from '../../util/dom'; | |
| import type Point from '@mapbox/point-geometry'; | |
| const LEFT_BUTTON = 0; | |
| const RIGHT_BUTTON = 2; | |
| // the values for each button in MouseEvent.buttons | |
| const BUTTONS_FLAGS = { | |
| [LEFT_BUTTON]: 1, | |
| [RIGHT_BUTTON]: 2 | |
| }; | |
| function buttonStillPressed(e: MouseEvent, button: number) { | |
| const flag = BUTTONS_FLAGS[button]; | |
| return e.buttons === undefined || (e.buttons & flag) !== flag; | |
| } | |
| class MouseHandler { | |
| _enabled: boolean; | |
| _active: boolean; | |
| _lastPoint: Point; | |
| _eventButton: number; | |
| _moved: boolean; | |
| _clickTolerance: number; | |
| constructor(options: { clickTolerance: number }) { | |
| this.reset(); | |
| this._clickTolerance = options.clickTolerance || 1; | |
| } | |
| blur() { | |
| this.reset(); | |
| } | |
| reset() { | |
| this._active = false; | |
| this._moved = false; | |
| delete this._lastPoint; | |
| delete this._eventButton; | |
| } | |
| _correctButton(e: MouseEvent, button: number) { //eslint-disable-line | |
| return false; // implemented by child | |
| } | |
| _move(lastPoint: Point, point: Point) { //eslint-disable-line | |
| return {}; // implemented by child | |
| } | |
| mousedown(e: MouseEvent, point: Point) { | |
| if (this._lastPoint) return; | |
| const eventButton = DOM.mouseButton(e); | |
| if (!this._correctButton(e, eventButton)) return; | |
| this._lastPoint = point; | |
| this._eventButton = eventButton; | |
| } | |
| mousemoveWindow(e: MouseEvent, point: Point) { | |
| const lastPoint = this._lastPoint; | |
| if (!lastPoint) return; | |
| e.preventDefault(); | |
| if (buttonStillPressed(e, this._eventButton)) { | |
| // Some browsers don't fire a `mouseup` when the mouseup occurs outside | |
| // the window or iframe: | |
| // https://github.com/mapbox/mapbox-gl-js/issues/4622 | |
| // | |
| // If the button is no longer pressed during this `mousemove` it may have | |
| // been released outside of the window or iframe. | |
| this.reset(); | |
| return; | |
| } | |
| if (!this._moved && point.dist(lastPoint) < this._clickTolerance) return; | |
| this._moved = true; | |
| this._lastPoint = point; | |
| // implemented by child class | |
| return this._move(lastPoint, point); | |
| } | |
| mouseupWindow(e: MouseEvent) { | |
| if (!this._lastPoint) return; | |
| const eventButton = DOM.mouseButton(e); | |
| if (eventButton !== this._eventButton) return; | |
| if (this._moved) DOM.suppressClick(); | |
| this.reset(); | |
| } | |
| enable() { | |
| this._enabled = true; | |
| } | |
| disable() { | |
| this._enabled = false; | |
| this.reset(); | |
| } | |
| isEnabled() { | |
| return this._enabled; | |
| } | |
| isActive() { | |
| return this._active; | |
| } | |
| } | |
| export class MousePanHandler extends MouseHandler { | |
| mousedown(e: MouseEvent, point: Point) { | |
| super.mousedown(e, point); | |
| if (this._lastPoint) this._active = true; | |
| } | |
| _correctButton(e: MouseEvent, button: number) { | |
| return button === LEFT_BUTTON && !e.ctrlKey; | |
| } | |
| _move(lastPoint: Point, point: Point) { | |
| return { | |
| around: point, | |
| panDelta: point.sub(lastPoint) | |
| }; | |
| } | |
| } | |
| export class MouseRotateHandler extends MouseHandler { | |
| _correctButton(e: MouseEvent, button: number) { | |
| return (button === LEFT_BUTTON && e.ctrlKey) || (button === RIGHT_BUTTON); | |
| } | |
| _move(lastPoint: Point, point: Point) { | |
| const degreesPerPixelMoved = 0.8; | |
| const bearingDelta = (point.x - lastPoint.x) * degreesPerPixelMoved; | |
| if (bearingDelta) { | |
| this._active = true; | |
| return {bearingDelta}; | |
| } | |
| } | |
| contextmenu(e: MouseEvent) { | |
| // prevent browser context menu when necessary; we don't allow it with rotation | |
| // because we can't discern rotation gesture start from contextmenu on Mac | |
| e.preventDefault(); | |
| } | |
| } | |
| export class MousePitchHandler extends MouseHandler { | |
| _correctButton(e: MouseEvent, button: number) { | |
| return (button === LEFT_BUTTON && e.ctrlKey) || (button === RIGHT_BUTTON); | |
| } | |
| _move(lastPoint: Point, point: Point) { | |
| const degreesPerPixelMoved = -0.5; | |
| const pitchDelta = (point.y - lastPoint.y) * degreesPerPixelMoved; | |
| if (pitchDelta) { | |
| this._active = true; | |
| return {pitchDelta}; | |
| } | |
| } | |
| contextmenu(e: MouseEvent) { | |
| // prevent browser context menu when necessary; we don't allow it with rotation | |
| // because we can't discern rotation gesture start from contextmenu on Mac | |
| e.preventDefault(); | |
| } | |
| } | |