mapbox-gl
Version:
A WebGL interactive maps library
190 lines (157 loc) • 5.2 kB
JavaScript
'use strict';
const DOM = require('../../util/dom');
const LngLatBounds = require('../../geo/lng_lat_bounds');
const util = require('../../util/util');
const window = require('../../util/window');
/**
* The `BoxZoomHandler` allows the user to zoom the map to fit within a bounding box.
* The bounding box is defined by clicking and holding `shift` while dragging the cursor.
*
* @param {Map} map The Mapbox GL JS map to add the handler to.
*/
class BoxZoomHandler {
constructor(map) {
this._map = map;
this._el = map.getCanvasContainer();
this._container = map.getContainer();
util.bindAll([
'_onMouseDown',
'_onMouseMove',
'_onMouseUp',
'_onKeyDown'
], this);
}
/**
* Returns a Boolean indicating whether the "box zoom" interaction is enabled.
*
* @returns {boolean} `true` if the "box zoom" interaction is enabled.
*/
isEnabled() {
return !!this._enabled;
}
/**
* Returns a Boolean indicating whether the "box zoom" interaction is active, i.e. currently being used.
*
* @returns {boolean} `true` if the "box zoom" interaction is active.
*/
isActive() {
return !!this._active;
}
/**
* Enables the "box zoom" interaction.
*
* @example
* map.boxZoom.enable();
*/
enable() {
if (this.isEnabled()) return;
this._el.addEventListener('mousedown', this._onMouseDown, false);
this._enabled = true;
}
/**
* Disables the "box zoom" interaction.
*
* @example
* map.boxZoom.disable();
*/
disable() {
if (!this.isEnabled()) return;
this._el.removeEventListener('mousedown', this._onMouseDown);
this._enabled = false;
}
_onMouseDown(e) {
if (!(e.shiftKey && e.button === 0)) return;
window.document.addEventListener('mousemove', this._onMouseMove, false);
window.document.addEventListener('keydown', this._onKeyDown, false);
window.document.addEventListener('mouseup', this._onMouseUp, false);
DOM.disableDrag();
this._startPos = DOM.mousePos(this._el, e);
this._active = true;
}
_onMouseMove(e) {
const p0 = this._startPos,
p1 = DOM.mousePos(this._el, e);
if (!this._box) {
this._box = DOM.create('div', 'mapboxgl-boxzoom', this._container);
this._container.classList.add('mapboxgl-crosshair');
this._fireEvent('boxzoomstart', e);
}
const minX = Math.min(p0.x, p1.x),
maxX = Math.max(p0.x, p1.x),
minY = Math.min(p0.y, p1.y),
maxY = Math.max(p0.y, p1.y);
DOM.setTransform(this._box, `translate(${minX}px,${minY}px)`);
this._box.style.width = `${maxX - minX}px`;
this._box.style.height = `${maxY - minY}px`;
}
_onMouseUp(e) {
if (e.button !== 0) return;
const p0 = this._startPos,
p1 = DOM.mousePos(this._el, e),
bounds = new LngLatBounds()
.extend(this._map.unproject(p0))
.extend(this._map.unproject(p1));
this._finish();
if (p0.x === p1.x && p0.y === p1.y) {
this._fireEvent('boxzoomcancel', e);
} else {
this._map
.fitBounds(bounds, {linear: true})
.fire('boxzoomend', { originalEvent: e, boxZoomBounds: bounds });
}
}
_onKeyDown(e) {
if (e.keyCode === 27) {
this._finish();
this._fireEvent('boxzoomcancel', e);
}
}
_finish() {
this._active = false;
window.document.removeEventListener('mousemove', this._onMouseMove, false);
window.document.removeEventListener('keydown', this._onKeyDown, false);
window.document.removeEventListener('mouseup', this._onMouseUp, false);
this._container.classList.remove('mapboxgl-crosshair');
if (this._box) {
this._box.parentNode.removeChild(this._box);
this._box = null;
}
DOM.enableDrag();
}
_fireEvent(type, e) {
return this._map.fire(type, { originalEvent: e });
}
}
module.exports = BoxZoomHandler;
/**
* @typedef {Object} MapBoxZoomEvent
* @property {MouseEvent} originalEvent
* @property {LngLatBounds} boxZoomBounds The bounding box of the "box zoom" interaction.
* This property is only provided for `boxzoomend` events.
*/
/**
* Fired when a "box zoom" interaction starts. See [`BoxZoomHandler`](#BoxZoomHandler).
*
* @event boxzoomstart
* @memberof Map
* @instance
* @property {MapBoxZoomEvent} data
*/
/**
* Fired when a "box zoom" interaction ends. See [`BoxZoomHandler`](#BoxZoomHandler).
*
* @event boxzoomend
* @memberof Map
* @instance
* @type {Object}
* @property {MapBoxZoomEvent} data
*/
/**
* Fired when the user cancels a "box zoom" interaction, or when the bounding box does not meet the minimum size threshold.
* See [`BoxZoomHandler`](#BoxZoomHandler).
*
* @event boxzoomcancel
* @memberof Map
* @instance
* @property {MapBoxZoomEvent} data
*/