import { ImmutableStore, Store } from "../../Logic/UIEventSource" import type { Map as MlMap } from "maplibre-gl" import { Marker } from "maplibre-gl" import { ShowDataLayerOptions } from "../ShowDataLayer/ShowDataLayerOptions" import { GeoOperations } from "../../Logic/GeoOperations" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import PointRenderingConfig from "../../Models/ThemeConfig/PointRenderingConfig" import { OsmFeature, OsmTags } from "../../Models/OsmFeature" import FeatureSource from "../../Logic/FeatureSource/FeatureSource" import { BBox } from "../../Logic/BBox" class PointRenderingLayer { private readonly _config: PointRenderingConfig private readonly _fetchStore?: (id: string) => Store private readonly _map: MlMap constructor( map: MlMap, features: FeatureSource, config: PointRenderingConfig, fetchStore?: (id: string) => Store ) { this._config = config this._map = map this._fetchStore = fetchStore const cache: Map = new Map() const self = this features.features.addCallbackAndRunD((features) => { const unseenKeys = new Set(cache.keys()) for (const { feature } of features) { const id = feature.properties.id unseenKeys.delete(id) const loc = GeoOperations.centerpointCoordinates(feature) if (cache.has(id)) { console.log("Not creating a marker for ", id) const cached = cache.get(id) const oldLoc = cached.getLngLat() console.log("OldLoc vs newLoc", oldLoc, loc) if (loc[0] !== oldLoc.lng && loc[1] !== oldLoc.lat) { cached.setLngLat(loc) console.log("MOVED") } continue } console.log("Creating a marker for ", id) const marker = self.addPoint(feature) cache.set(id, marker) } for (const unseenKey of unseenKeys) { cache.get(unseenKey).remove() cache.delete(unseenKey) } }) } private addPoint(feature: OsmFeature): Marker { let store: Store if (this._fetchStore) { store = this._fetchStore(feature.properties.id) } else { store = new ImmutableStore(feature.properties) } const { html, iconAnchor } = this._config.GenerateLeafletStyle(store, true) html.SetClass("marker") const el = html.ConstructElement() el.addEventListener("click", function () { window.alert("Hello world!") }) return new Marker(el) .setLngLat(GeoOperations.centerpointCoordinates(feature)) .setOffset(iconAnchor) .addTo(this._map) } } export class ShowDataLayer { private readonly _map: Store private _options: ShowDataLayerOptions & { layer: LayerConfig } constructor(map: Store, options: ShowDataLayerOptions & { layer: LayerConfig }) { this._map = map this._options = options const self = this map.addCallbackAndRunD((map) => self.initDrawFeatures(map)) } private initDrawFeatures(map: MlMap) { for (const pointRenderingConfig of this._options.layer.mapRendering) { new PointRenderingLayer( map, this._options.features, pointRenderingConfig, this._options.fetchStore ) } if (this._options.zoomToFeatures) { const features = this._options.features.features.data const bbox = BBox.bboxAroundAll(features.map((f) => BBox.get(f.feature))) map.fitBounds(bbox.toLngLat(), { padding: { top: 10, bottom: 10, left: 10, right: 10 }, }) } } }