leaflet
Version:
JavaScript library for mobile-friendly interactive maps
92 lines (70 loc) • 2.69 kB
JavaScript
import {Map} from '../Map.js';
import {Handler} from '../../core/Handler.js';
import * as DomEvent from '../../dom/DomEvent.js';
/*
* Handler.ScrollWheelZoom is used by Map to enable mouse scroll wheel zoom on the map.
*/
// @namespace Map
// @section Interaction Options
Map.mergeOptions({
// @section Mouse wheel options
// @option scrollWheelZoom: Boolean|String = true
// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
// it will zoom to the center of the view regardless of where the pointer was.
scrollWheelZoom: true,
// @option wheelDebounceTime: Number = 40
// Limits the rate at which a wheel can fire (in milliseconds). By default, the
// user can't zoom via wheel more often than once per 40 ms.
wheelDebounceTime: 40,
// @option wheelPxPerZoomLevel: Number = 60
// How many scroll pixels (as reported by [DomEvent.getWheelDelta](#domevent-getwheeldelta))
// mean a change of one full zoom level. Smaller values will make wheel-zooming
// faster (and vice versa).
wheelPxPerZoomLevel: 60
});
export class ScrollWheelZoom extends Handler {
addHooks() {
DomEvent.on(this._map._container, 'wheel', this._onWheelScroll, this);
this._delta = 0;
}
removeHooks() {
DomEvent.off(this._map._container, 'wheel', this._onWheelScroll, this);
clearTimeout(this._timer);
}
_onWheelScroll(e) {
const delta = DomEvent.getWheelDelta(e);
const debounce = this._map.options.wheelDebounceTime;
this._delta += delta;
this._lastMousePos = this._map.pointerEventToContainerPoint(e);
if (!this._startTime) {
this._startTime = +new Date();
}
const left = Math.max(debounce - (+new Date() - this._startTime), 0);
clearTimeout(this._timer);
this._timer = setTimeout(this._performZoom.bind(this), left);
DomEvent.stop(e);
}
_performZoom() {
const map = this._map,
zoom = map.getZoom(),
snap = this._map.options.zoomSnap ?? 0;
map._stop(); // stop panning and fly animations if any
// map the delta with a sigmoid function to -4..4 range leaning on -1..1
const d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
this._delta = 0;
this._startTime = null;
if (!delta) { return; }
if (map.options.scrollWheelZoom === 'center') {
map.setZoom(zoom + delta);
} else {
map.setZoomAround(this._lastMousePos, zoom + delta);
}
}
}
// @section Handlers
// @property scrollWheelZoom: Handler
// Scroll wheel zoom handler.
Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);