You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leaflet-components/src/components/leaflet-geojson.ts

70 lines
2.1 KiB
TypeScript

import { GeoJSON, PathOptions, Layer } from 'leaflet';
import { defineProps, num, str, on } from '../core/props.ts';
import { registerChildren, unregisterChildren, getChildren } from '../core/register.ts';
import { WithProps, buildOptions } from '../core/utils.ts';
const PROPS = defineProps({
data: str(),
stroke: str(),
color: str('#3388ff'),
weight: num(3),
opacity: num(1.0),
lineCap: str('round'),
lineJoin: str('round'),
dashArray: str(),
dashOffset: str(),
fill: on(),
fillColor: str('#3388ff'),
fillOpacity: num(0.2),
fillRule: str('evenodd'),
});
const PROP_BY_ATTR = new Map<string, string>(
Object.entries(PROPS).map(([name, spec]) => [spec.attr, name]),
);
export class LeafletGeoJSON extends WithProps(HTMLElement, PROPS) {
#obj?: GeoJSON;
connectedCallback() {
const raw = this.getAttribute('data');
const data = raw ? JSON.parse(raw) : undefined;
const styleOpts = Object.fromEntries(
Object.entries(buildOptions(this, PROPS, ['data'])).filter(([, v]) => v !== ''),
);
this.#obj = new GeoJSON(data, { style: styleOpts as PathOptions });
registerChildren(this, this.#obj);
}
disconnectedCallback() {
for (const [el, entry] of getChildren(this) ?? []) {
if (entry.type === 'popup') this.#obj?.unbindPopup();
else if (entry.type === 'tooltip') this.#obj?.unbindTooltip();
else if (entry.type === 'layer') this.#obj?.removeLayer(el as unknown as Layer);
}
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) return;
if (name === 'data') {
this.#obj.clearLayers();
if (val) this.#obj.addData(JSON.parse(val));
} else {
const propName = PROP_BY_ATTR.get(name);
if (!propName) return;
const spec = PROPS[propName as keyof typeof PROPS];
const styleVal = spec.kind === 'bool-on' ? val !== null : val;
this.#obj.setStyle({ [propName]: styleVal } as PathOptions);
}
}
}
customElements.define('leaflet-geojson', LeafletGeoJSON);