maplair
Version:
JavaScript library for mobile-friendly interactive maps
235 lines (234 loc) • 6.73 kB
JavaScript
import { setOptions } from "../../core/Util.js";
import { Point } from "../../geometry/Point.js";
import { off, on } from "../../dom/DomEvent.js";
import { setPosition } from "../../dom/DomUtil.js";
import { LatLng } from "../../geo/LatLng.js";
import { Layer } from "../Layer.js";
import { DefaultIcon } from "./DefaultIcon.js";
import { MarkerDrag } from "./Marker.Drag.js";
//#region src/layer/marker/Marker.js
var Marker = class Marker extends Layer {
static {
this.setDefaultOptions({
icon: new DefaultIcon(),
interactive: true,
keyboard: true,
title: "",
alt: "Marker",
zIndexOffset: 0,
opacity: 1,
riseOnHover: false,
riseOffset: 250,
pane: "markerPane",
shadowPane: "shadowPane",
shadow: true,
bubblingPointerEvents: false,
autoPanOnFocus: true,
draggable: false,
autoPan: false,
autoPanPadding: [50, 50],
autoPanSpeed: 10
});
}
constructor(latlng, options) {
super();
setOptions(this, options);
this._latlng = new LatLng(latlng);
this.callInitHooks(Marker);
}
onAdd(map) {
this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
if (this._zoomAnimated) map.on("zoomanim", this._animateZoom, this);
this._initIcon();
this.update();
if (map.options.markerCulling) this._updateCulling();
}
onRemove(map) {
if (this.dragging?.enabled()) {
this.options.draggable = true;
this.dragging.removeHooks();
}
delete this.dragging;
if (this._zoomAnimated) map.off("zoomanim", this._animateZoom, this);
this._removeIcon();
this._removeShadow();
this._culled = false;
}
getEvents() {
const events = {
zoom: this.update,
viewreset: this.update
};
if (this._map?.options.markerCulling) events.moveend = this._updateCulling;
return events;
}
getLatLng() {
return this._latlng;
}
setLatLng(latlng) {
const oldLatLng = this._latlng;
this._latlng = new LatLng(latlng);
if (this._map?.options.markerCulling) this._updateCulling();
this.update();
return this.fire("move", {
oldLatLng,
latlng: this._latlng
});
}
setZIndexOffset(offset) {
this.options.zIndexOffset = offset;
return this.update();
}
getIcon() {
return this.options.icon;
}
setIcon(icon) {
this.options.icon = icon;
if (this._map) {
this._initIcon();
this.update();
}
if (this._popup) this.bindPopup(this._popup, this._popup.options);
return this;
}
getElement() {
return this._icon;
}
update() {
if (this._icon && this._map && !this._culled) {
const pos = this._map.latLngToLayerPoint(this._latlng).round();
this._setPos(pos);
}
return this;
}
_initIcon() {
const options = this.options, classToAdd = `maplair-zoom-${this._zoomAnimated ? "animated" : "hide"}`;
const icon = options.icon.createIcon(this._icon);
let addIcon = false;
if (icon !== this._icon) {
if (this._icon) this._removeIcon();
addIcon = true;
if (options.title) icon.title = options.title;
if (icon.tagName === "IMG") icon.alt = options.alt ?? "";
}
icon.classList.add(classToAdd);
if (options.keyboard) {
icon.tabIndex = "0";
icon.setAttribute("role", "button");
}
this._icon = icon;
if (options.riseOnHover) this.on({
pointerover: this._bringToFront,
pointerout: this._resetZIndex
});
if (this.options.autoPanOnFocus) on(icon, "focus", this._panOnFocus, this);
const newShadow = options.shadow ? options.icon.createShadow(this._shadow) : null;
let addShadow = false;
if (newShadow !== this._shadow) {
this._removeShadow();
addShadow = true;
}
if (newShadow) {
newShadow.classList.add(classToAdd);
newShadow.alt = "";
}
this._shadow = newShadow;
if (options.opacity < 1) this._updateOpacity();
if (addIcon) this.getPane().appendChild(this._icon);
this._initInteraction();
if (newShadow && addShadow) this.getPane(options.shadowPane).appendChild(this._shadow);
}
_removeIcon() {
if (this.options.riseOnHover) this.off({
pointerover: this._bringToFront,
pointerout: this._resetZIndex
});
if (this.options.autoPanOnFocus) off(this._icon, "focus", this._panOnFocus, this);
this._icon.remove();
this.removeInteractiveTarget(this._icon);
this._icon = null;
}
_updateCulling() {
if (!this._icon || !this._map) return;
const visible = this._map.getBounds().pad(.5).contains(this._latlng) || !!this.dragging?._draggable?._moving || this._icon.contains(document.activeElement);
if (visible === !this._culled) return;
this._culled = !visible;
if (visible) {
this.getPane().appendChild(this._icon);
if (this._shadow) this.getPane(this.options.shadowPane).appendChild(this._shadow);
this.update();
} else {
this._icon.remove();
this._shadow?.remove();
}
}
_removeShadow() {
this._shadow?.remove();
this._shadow = null;
}
_setPos(pos) {
if (this._icon) setPosition(this._icon, pos);
if (this._shadow) setPosition(this._shadow, pos);
this._zIndex = pos.y + this.options.zIndexOffset;
this._resetZIndex();
}
_updateZIndex(offset) {
const zIndex = String(this._zIndex + offset);
if (this._icon && this._icon.style.zIndex !== zIndex) this._icon.style.zIndex = zIndex;
}
_animateZoom(opt) {
if (this._culled) return;
const pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
this._setPos(pos);
}
_initInteraction() {
if (!this.options.interactive) return;
this._icon.classList.add("maplair-interactive");
this.addInteractiveTarget(this._icon);
if (MarkerDrag) {
let draggable = this.options.draggable;
if (this.dragging) {
draggable = this.dragging.enabled();
this.dragging.disable();
}
this.dragging = new MarkerDrag(this);
if (draggable) this.dragging.enable();
}
}
setOpacity(opacity) {
this.options.opacity = opacity;
if (this._map) this._updateOpacity();
return this;
}
_updateOpacity() {
const opacity = this.options.opacity;
if (this._icon) this._icon.style.opacity = opacity;
if (this._shadow) this._shadow.style.opacity = opacity;
}
_bringToFront() {
this._updateZIndex(this.options.riseOffset);
}
_resetZIndex() {
this._updateZIndex(0);
}
_panOnFocus() {
const map = this._map;
if (!map) return;
const iconOpts = this.options.icon.options;
const size = iconOpts.iconSize ? new Point(iconOpts.iconSize) : new Point(0, 0);
const anchor = iconOpts.iconAnchor ? new Point(iconOpts.iconAnchor) : new Point(0, 0);
map.panInside(this._latlng, {
paddingTopLeft: anchor,
paddingBottomRight: size.subtract(anchor)
});
}
_getPopupAnchor() {
return this.options.icon.options.popupAnchor;
}
_getTooltipAnchor() {
return this.options.icon.options.tooltipAnchor;
}
};
//#endregion
export { Marker };
//# sourceMappingURL=Marker.js.map