UNPKG

leaflet

Version:

JavaScript library for mobile-friendly interactive maps

133 lines (110 loc) • 3.83 kB
import {Control} from './Control.js'; import * as DomUtil from '../dom/DomUtil.js'; import * as DomEvent from '../dom/DomEvent.js'; /** @import {ControlOptions, Defaults, ZoomControlDefaults, ZoomControlOptions} from '../types.js' */ /** @import {LeafletMap} from '../map/Map.js' */ /** @satisfies {Defaults<ControlOptions>} */ const defaultOptions = { /** * The position of the control (one of the map corners). Possible values * are `'topleft'`, `'topright'`, `'bottomleft'` or `'bottomright'` */ position: 'topleft', /** The text set on the 'zoom in' button. */ zoomInText: '<span aria-hidden="true">+</span>', /** The title set on the 'zoom in' button. */ zoomInTitle: 'Zoom in', /** The text set on the 'zoom out' button. */ zoomOutText: '<span aria-hidden="true">&#x2212;</span>', /** The title set on the 'zoom out' button. */ zoomOutTitle: 'Zoom out' }; /** @typedef {typeof defaultOptions} ZoomControlDefaultsValues */ /** * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default * unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`. * @template {ZoomControlOptions} [O=ZoomControlOptions] * @extends {Control<O & ZoomControlDefaults>} */ export class ZoomControl extends Control { /** @type {Defaults<ZoomControlOptions>} */ static defaultOptions = defaultOptions; /** * @param {LeafletMap} map * @returns {HTMLElement} */ onAdd(map) { const zoomName = 'leaflet-control-zoom', container = DomUtil.create('div', `${zoomName} leaflet-bar`), options = this.options; /** @type {HTMLAnchorElement} */ this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle, `${zoomName}-in`, container, e => this._zoom(e, 1)); /** @type {HTMLAnchorElement} */ this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle, `${zoomName}-out`, container, e => this._zoom(e, -1)); this._updateDisabled(); map.on('zoomend zoomlevelschange', this._updateDisabled, this); return container; } /** @param {LeafletMap} map */ onRemove(map) { map.off('zoomend zoomlevelschange', this._updateDisabled, this); } /** Disables the zoom buttons. */ disable() { this._disabled = true; this._updateDisabled(); return this; } /** Enables the zoom buttons again after [`disable`](#zoomcontrol-disable). */ enable() { this._disabled = false; this._updateDisabled(); return this; } /** * @param {MouseEvent} e * @param {number} dir */ _zoom(e, dir) { const map = this._map; if (!this._disabled && (dir > 0 ? map._zoom < map.getMaxZoom() : map._zoom > map.getMinZoom())) { map.zoomIn(dir * map.options.zoomDelta * (e.shiftKey ? 3 : 1)); } } /** * @param {string} html * @param {string} title * @param {string} className * @param {HTMLElement} container * @param {(e: MouseEvent) => void} fn */ _createButton(html, title, className, container, fn) { const link = DomUtil.create('a', className, container); link.innerHTML = html; link.href = '#'; link.title = title; /* * Will force screen readers like VoiceOver to read this as "Zoom in - button" */ link.setAttribute('role', 'button'); link.setAttribute('aria-label', title); DomEvent.disableClickPropagation(link); DomEvent.on(link, 'click', (e) => { DomEvent.stop(e); fn.call(this, e); this._refocusOnMap(e); }); return link; } _updateDisabled() { const map = this._map; for (const [button, limit] of /** @type {[HTMLElement, number][]} */ ([[this._zoomInButton, map.getMaxZoom()], [this._zoomOutButton, map.getMinZoom()]])) { const disabled = this._disabled || map._zoom === limit; button.classList.toggle('leaflet-disabled', disabled); button.setAttribute('aria-disabled', `${disabled}`); } } }