import { Icon, Marker } from 'leaflet'; import { defineProps, num, str, on } from '../core/props.ts'; import { LeafletIconChangedEvent, registerChildren, unregisterChildren } from '../core/register.ts'; import { WithProps, buildAttrMap, buildOptions, numAttr, setLayerAttr } from '../core/utils.ts'; const PROPS = defineProps({ lat: num(), lng: num(), title: str(), alt: str(), draggable: on(), opacity: num(1.0), zIndexOffset: num(), }); const PROP_BY_ATTR = buildAttrMap(PROPS); export class LeafletMarker extends WithProps(HTMLElement, PROPS) { #obj?: Marker; #syncing = false; connectedCallback() { this.#obj = new Marker( [numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')], buildOptions(this, PROPS, ['lat', 'lng']), ); this.#obj.on('dragend move', this.#onChange, this); registerChildren(this, this.#obj); this.addEventListener('icon-changed', this.#onIconChanged); } disconnectedCallback() { this.#obj?.off('dragend move', this.#onChange, this); this.removeEventListener('icon-changed', this.#onIconChanged); unregisterChildren(this); this.#obj?.remove(); this.#obj = undefined; } get leafletObject() { return this.#obj; } attributeChangedCallback(name: string, _old: string | null, val: string | null) { if (!this.#obj || this.#syncing) return; if (name === 'lat' || name === 'lng') { this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]); } else if (name === 'draggable') { if (val !== null) this.#obj.dragging?.enable(); else this.#obj.dragging?.disable(); } else if (name === 'title') { const el = this.#obj.getElement(); if (el) (el as HTMLImageElement).title = val ?? ''; } else if (name === 'alt') { const el = this.#obj.getElement(); if (el) (el as HTMLImageElement).alt = val ?? ''; } else { setLayerAttr(this.#obj!, PROPS, PROP_BY_ATTR, name, val); } } #onChange() { if (!this.#obj || this.#syncing) return; this.#syncing = true; const pos = this.#obj.getLatLng(); this.setAttribute('lat', `${pos.lat}`); this.setAttribute('lng', `${pos.lng}`); this.#syncing = false; } #onIconChanged(e: LeafletIconChangedEvent) { if (!this.#obj) return; if (e.detail.icon) this.#obj.setIcon(e.detail.icon); else this.#obj.setIcon(new Icon.Default()); } } customElements.define('leaflet-marker', LeafletMarker);