| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | import type { Map as MlMap } from "maplibre-gl" | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  | import { GeoJSONSource, Marker } from "maplibre-gl" | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | import { ShowDataLayerOptions } from "./ShowDataLayerOptions" | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | import { GeoOperations } from "../../Logic/GeoOperations" | 
					
						
							|  |  |  | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | 
					
						
							|  |  |  | import PointRenderingConfig from "../../Models/ThemeConfig/PointRenderingConfig" | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | import { OsmTags } from "../../Models/OsmFeature" | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  | import { FeatureSource } from "../../Logic/FeatureSource/FeatureSource" | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | import { BBox } from "../../Logic/BBox" | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  | import { Feature, Point } from "geojson" | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | import LineRenderingConfig from "../../Models/ThemeConfig/LineRenderingConfig" | 
					
						
							|  |  |  | import { Utils } from "../../Utils" | 
					
						
							|  |  |  | import * as range_layer from "../../assets/layers/range/range.json" | 
					
						
							|  |  |  | import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter" | 
					
						
							|  |  |  | import FilteredLayer from "../../Models/FilteredLayer" | 
					
						
							|  |  |  | import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | class PointRenderingLayer { | 
					
						
							|  |  |  |     private readonly _config: PointRenderingConfig | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |     private readonly _visibility?: Store<boolean> | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     private readonly _fetchStore?: (id: string) => Store<Record<string, string>> | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     private readonly _map: MlMap | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |     private readonly _onClick: (feature: Feature) => void | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     private readonly _allMarkers: Map<string, Marker> = new Map<string, Marker>() | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |     private _dirty = false | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     constructor( | 
					
						
							|  |  |  |         map: MlMap, | 
					
						
							|  |  |  |         features: FeatureSource, | 
					
						
							|  |  |  |         config: PointRenderingConfig, | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         visibility?: Store<boolean>, | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         fetchStore?: (id: string) => Store<Record<string, string>>, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         onClick?: (feature: Feature) => void | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |         this._visibility = visibility | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         this._config = config | 
					
						
							|  |  |  |         this._map = map | 
					
						
							|  |  |  |         this._fetchStore = fetchStore | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         this._onClick = onClick | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         const self = this | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         features.features.addCallbackAndRunD((features) => self.updateFeatures(features)) | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |         visibility?.addCallbackAndRunD((visible) => { | 
					
						
							|  |  |  |             if (visible === true && self._dirty) { | 
					
						
							|  |  |  |                 self.updateFeatures(features.features.data) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             self.setVisibility(visible) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private updateFeatures(features: Feature[]) { | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |         if (this._visibility?.data === false) { | 
					
						
							|  |  |  |             this._dirty = true | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this._dirty = false | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         const cache = this._allMarkers | 
					
						
							|  |  |  |         const unseenKeys = new Set(cache.keys()) | 
					
						
							|  |  |  |         for (const location of this._config.location) { | 
					
						
							|  |  |  |             for (const feature of features) { | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |                 if (feature?.geometry === undefined) { | 
					
						
							|  |  |  |                     console.warn( | 
					
						
							|  |  |  |                         "Got an invalid feature:", | 
					
						
							|  |  |  |                         features, | 
					
						
							|  |  |  |                         " while rendering", | 
					
						
							|  |  |  |                         location, | 
					
						
							|  |  |  |                         "of", | 
					
						
							|  |  |  |                         this._config | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |                 const id = feature.properties.id + "-" + location | 
					
						
							|  |  |  |                 unseenKeys.delete(id) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                 const loc = GeoOperations.featureToCoordinateWithRenderingType( | 
					
						
							|  |  |  |                     <any>feature, | 
					
						
							|  |  |  |                     location | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 if (loc === undefined) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |                 if (cache.has(id)) { | 
					
						
							|  |  |  |                     const cached = cache.get(id) | 
					
						
							|  |  |  |                     const oldLoc = cached.getLngLat() | 
					
						
							|  |  |  |                     if (loc[0] !== oldLoc.lng && loc[1] !== oldLoc.lat) { | 
					
						
							|  |  |  |                         cached.setLngLat(loc) | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                 const marker = this.addPoint(feature, loc) | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |                 cache.set(id, marker) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         for (const unseenKey of unseenKeys) { | 
					
						
							|  |  |  |             cache.get(unseenKey).remove() | 
					
						
							|  |  |  |             cache.delete(unseenKey) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private setVisibility(visible: boolean) { | 
					
						
							|  |  |  |         for (const marker of this._allMarkers.values()) { | 
					
						
							|  |  |  |             if (visible) { | 
					
						
							|  |  |  |                 marker.getElement().classList.remove("hidden") | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 marker.getElement().classList.add("hidden") | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     private addPoint(feature: Feature, loc: [number, number]): Marker { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         let store: Store<Record<string, string>> | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         if (this._fetchStore) { | 
					
						
							|  |  |  |             store = this._fetchStore(feature.properties.id) | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |             store = new ImmutableStore(<OsmTags>feature.properties) | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         const { html, iconAnchor } = this._config.RenderIcon(store, true) | 
					
						
							| 
									
										
										
										
											2023-03-29 17:21:20 +02:00
										 |  |  |         html.SetClass("marker cursor-pointer") | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         const el = html.ConstructElement() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         if (this._onClick) { | 
					
						
							|  |  |  |             const self = this | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  |             el.addEventListener("click", function (ev) { | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |                 self._onClick(feature) | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  |                 ev.preventDefault() | 
					
						
							|  |  |  |                 // Workaround to signal the MapLibreAdaptor to ignore this click
 | 
					
						
							|  |  |  |                 ev["consumed"] = true | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |         const marker = new Marker(el).setLngLat(loc).setOffset(iconAnchor).addTo(this._map) | 
					
						
							|  |  |  |         store | 
					
						
							|  |  |  |             .map((tags) => this._config.pitchAlignment.GetRenderValue(tags).Subs(tags).txt) | 
					
						
							|  |  |  |             .addCallbackAndRun((pitchAligment) => marker.setPitchAlignment(pitchAligment)) | 
					
						
							|  |  |  |         store | 
					
						
							|  |  |  |             .map((tags) => this._config.rotationAlignment.GetRenderValue(tags).Subs(tags).txt) | 
					
						
							|  |  |  |             .addCallbackAndRun((pitchAligment) => marker.setRotationAlignment(pitchAligment)) | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  |         if (feature.geometry.type === "Point") { | 
					
						
							|  |  |  |             // When the tags get 'pinged', check that the location didn't change
 | 
					
						
							|  |  |  |             store.addCallbackAndRunD(() => { | 
					
						
							|  |  |  |                 // Check if the location is still the same
 | 
					
						
							|  |  |  |                 const oldLoc = marker.getLngLat() | 
					
						
							|  |  |  |                 const newloc = (<Point>feature.geometry).coordinates | 
					
						
							|  |  |  |                 if (newloc[0] === oldLoc.lng && newloc[1] === oldLoc.lat) { | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 marker.setLngLat({ lon: newloc[0], lat: newloc[1] }) | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |         return marker | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LineRenderingLayer { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * These are dynamic properties | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private static readonly lineConfigKeys = [ | 
					
						
							|  |  |  |         "color", | 
					
						
							|  |  |  |         "width", | 
					
						
							|  |  |  |         "lineCap", | 
					
						
							|  |  |  |         "offset", | 
					
						
							|  |  |  |         "fill", | 
					
						
							|  |  |  |         "fillColor", | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |     ] as const | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static readonly lineConfigKeysColor = ["color", "fillColor"] as const | 
					
						
							|  |  |  |     private static readonly lineConfigKeysNumber = ["width", "offset"] as const | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  |     private static missingIdTriggered = false | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     private readonly _map: MlMap | 
					
						
							|  |  |  |     private readonly _config: LineRenderingConfig | 
					
						
							|  |  |  |     private readonly _visibility?: Store<boolean> | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     private readonly _fetchStore?: (id: string) => Store<Record<string, string>> | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |     private readonly _onClick?: (feature: Feature) => void | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     private readonly _layername: string | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |     private readonly _listenerInstalledOn: Set<string> = new Set<string>() | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         map: MlMap, | 
					
						
							|  |  |  |         features: FeatureSource, | 
					
						
							|  |  |  |         layername: string, | 
					
						
							|  |  |  |         config: LineRenderingConfig, | 
					
						
							|  |  |  |         visibility?: Store<boolean>, | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         fetchStore?: (id: string) => Store<Record<string, string>>, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         onClick?: (feature: Feature) => void | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     ) { | 
					
						
							|  |  |  |         this._layername = layername | 
					
						
							|  |  |  |         this._map = map | 
					
						
							|  |  |  |         this._config = config | 
					
						
							|  |  |  |         this._visibility = visibility | 
					
						
							|  |  |  |         this._fetchStore = fetchStore | 
					
						
							|  |  |  |         this._onClick = onClick | 
					
						
							|  |  |  |         const self = this | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |         features.features.addCallbackAndRunD(() => self.update(features.features)) | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |     private calculatePropsFor( | 
					
						
							|  |  |  |         properties: Record<string, string> | 
					
						
							|  |  |  |     ): Partial<Record<typeof LineRenderingLayer.lineConfigKeys[number], string>> { | 
					
						
							|  |  |  |         const calculatedProps = {} | 
					
						
							|  |  |  |         const config = this._config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const key of LineRenderingLayer.lineConfigKeys) { | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             calculatedProps[key] = config[key]?.GetRenderValue(properties)?.Subs(properties).txt | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         for (const key of LineRenderingLayer.lineConfigKeysColor) { | 
					
						
							|  |  |  |             let v = config[key]?.GetRenderValue(properties)?.Subs(properties).txt | 
					
						
							|  |  |  |             if (v === undefined) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (v.length == 9 && v.startsWith("#")) { | 
					
						
							|  |  |  |                 // This includes opacity
 | 
					
						
							|  |  |  |                 calculatedProps[key + "-opacity"] = parseInt(v.substring(7), 16) / 256 | 
					
						
							|  |  |  |                 v = v.substring(0, 7) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             calculatedProps[key] = v | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (const key of LineRenderingLayer.lineConfigKeysNumber) { | 
					
						
							|  |  |  |             const v = config[key]?.GetRenderValue(properties)?.Subs(properties).txt | 
					
						
							|  |  |  |             calculatedProps[key] = Number(v) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return calculatedProps | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |     private currentSourceData | 
					
						
							|  |  |  |     private async update(featureSource: Store<Feature[]>) { | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         const map = this._map | 
					
						
							|  |  |  |         while (!map.isStyleLoaded()) { | 
					
						
							|  |  |  |             await Utils.waitFor(100) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // After waiting 'till the map has loaded, the data might have changed already
 | 
					
						
							|  |  |  |         // As such, we only now read the features from the featureSource and compare with the previously set data
 | 
					
						
							|  |  |  |         const features = featureSource.data | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         const src = <GeoJSONSource>map.getSource(this._layername) | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |         if (this.currentSourceData === features) { | 
					
						
							|  |  |  |             // Already up to date
 | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         if (src === undefined) { | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |             this.currentSourceData = features | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             map.addSource(this._layername, { | 
					
						
							|  |  |  |                 type: "geojson", | 
					
						
							|  |  |  |                 data: { | 
					
						
							|  |  |  |                     type: "FeatureCollection", | 
					
						
							|  |  |  |                     features, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 promoteId: "id", | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             const linelayer = this._layername + "_line" | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             map.addLayer({ | 
					
						
							|  |  |  |                 source: this._layername, | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |                 id: linelayer, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |                 type: "line", | 
					
						
							|  |  |  |                 paint: { | 
					
						
							|  |  |  |                     "line-color": ["feature-state", "color"], | 
					
						
							|  |  |  |                     "line-opacity": ["feature-state", "color-opacity"], | 
					
						
							|  |  |  |                     "line-width": ["feature-state", "width"], | 
					
						
							|  |  |  |                     "line-offset": ["feature-state", "offset"], | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 layout: { | 
					
						
							|  |  |  |                     "line-cap": "round", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  |             map.on("click", linelayer, (e) => { | 
					
						
							|  |  |  |                 e.originalEvent["consumed"] = true | 
					
						
							|  |  |  |                 this._onClick(e.features[0]) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             const polylayer = this._layername + "_polygon" | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             map.addLayer({ | 
					
						
							|  |  |  |                 source: this._layername, | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |                 id: polylayer, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |                 type: "fill", | 
					
						
							|  |  |  |                 filter: ["in", ["geometry-type"], ["literal", ["Polygon", "MultiPolygon"]]], | 
					
						
							|  |  |  |                 layout: {}, | 
					
						
							|  |  |  |                 paint: { | 
					
						
							|  |  |  |                     "fill-color": ["feature-state", "fillColor"], | 
					
						
							|  |  |  |                     "fill-opacity": 0.1, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2023-04-14 02:42:57 +02:00
										 |  |  |             map.on("click", polylayer, (e) => { | 
					
						
							|  |  |  |                 e.originalEvent["consumed"] = true | 
					
						
							|  |  |  |                 this._onClick(e.features[0]) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-29 17:21:20 +02:00
										 |  |  |             this._visibility?.addCallbackAndRunD((visible) => { | 
					
						
							| 
									
										
										
										
											2023-03-30 04:51:56 +02:00
										 |  |  |                 try { | 
					
						
							|  |  |  |                     map.setLayoutProperty(linelayer, "visibility", visible ? "visible" : "none") | 
					
						
							|  |  |  |                     map.setLayoutProperty(polylayer, "visibility", visible ? "visible" : "none") | 
					
						
							|  |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                     console.warn( | 
					
						
							|  |  |  |                         "Error while setting visiblity of layers ", | 
					
						
							|  |  |  |                         linelayer, | 
					
						
							|  |  |  |                         polylayer, | 
					
						
							|  |  |  |                         e | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             }) | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |             this.currentSourceData = features | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             src.setData({ | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |                 type: "FeatureCollection", | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |                 features: this.currentSourceData, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (let i = 0; i < features.length; i++) { | 
					
						
							|  |  |  |             const feature = features[i] | 
					
						
							|  |  |  |             const id = feature.properties.id ?? feature.id | 
					
						
							|  |  |  |             if (id === undefined) { | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  |                 if (!LineRenderingLayer.missingIdTriggered) { | 
					
						
							|  |  |  |                     console.trace( | 
					
						
							|  |  |  |                         "Got a feature without ID; this causes rendering bugs:", | 
					
						
							|  |  |  |                         feature, | 
					
						
							|  |  |  |                         "from" | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     LineRenderingLayer.missingIdTriggered = true | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (this._listenerInstalledOn.has(id)) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (this._fetchStore === undefined) { | 
					
						
							|  |  |  |                 map.setFeatureState( | 
					
						
							|  |  |  |                     { source: this._layername, id }, | 
					
						
							|  |  |  |                     this.calculatePropsFor(feature.properties) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 const tags = this._fetchStore(id) | 
					
						
							|  |  |  |                 this._listenerInstalledOn.add(id) | 
					
						
							|  |  |  |                 tags.addCallbackAndRunD((properties) => { | 
					
						
							|  |  |  |                     map.setFeatureState( | 
					
						
							|  |  |  |                         { source: this._layername, id }, | 
					
						
							|  |  |  |                         this.calculatePropsFor(properties) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | export default class ShowDataLayer { | 
					
						
							| 
									
										
										
										
											2023-03-25 02:48:24 +01:00
										 |  |  |     private static rangeLayer = new LayerConfig( | 
					
						
							|  |  |  |         <LayerConfigJson>range_layer, | 
					
						
							|  |  |  |         "ShowDataLayer.ts:range.json" | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |     private readonly _map: Store<MlMap> | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |     private readonly _options: ShowDataLayerOptions & { | 
					
						
							|  |  |  |         layer: LayerConfig | 
					
						
							|  |  |  |         drawMarkers?: true | boolean | 
					
						
							|  |  |  |         drawLines?: true | boolean | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |     constructor( | 
					
						
							|  |  |  |         map: Store<MlMap>, | 
					
						
							|  |  |  |         options: ShowDataLayerOptions & { | 
					
						
							|  |  |  |             layer: LayerConfig | 
					
						
							|  |  |  |             drawMarkers?: true | boolean | 
					
						
							|  |  |  |             drawLines?: true | boolean | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         this._map = map | 
					
						
							|  |  |  |         this._options = options | 
					
						
							|  |  |  |         const self = this | 
					
						
							|  |  |  |         map.addCallbackAndRunD((map) => self.initDrawFeatures(map)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     public static showMultipleLayers( | 
					
						
							|  |  |  |         mlmap: UIEventSource<MlMap>, | 
					
						
							|  |  |  |         features: FeatureSource, | 
					
						
							|  |  |  |         layers: LayerConfig[], | 
					
						
							|  |  |  |         options?: Partial<ShowDataLayerOptions> | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         const perLayer = new PerLayerFeatureSourceSplitter( | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  |             layers.filter((l) => l.source !== null).map((l) => new FilteredLayer(l)), | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             new StaticFeatureSource(features) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         perLayer.forEach((fs) => { | 
					
						
							|  |  |  |             new ShowDataLayer(mlmap, { | 
					
						
							|  |  |  |                 layer: fs.layer.layerDef, | 
					
						
							|  |  |  |                 features: fs, | 
					
						
							|  |  |  |                 ...(options ?? {}), | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-30 04:51:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |     public static showRange( | 
					
						
							|  |  |  |         map: Store<MlMap>, | 
					
						
							|  |  |  |         features: FeatureSource, | 
					
						
							|  |  |  |         doShowLayer?: Store<boolean> | 
					
						
							|  |  |  |     ): ShowDataLayer { | 
					
						
							|  |  |  |         return new ShowDataLayer(map, { | 
					
						
							|  |  |  |             layer: ShowDataLayer.rangeLayer, | 
					
						
							|  |  |  |             features, | 
					
						
							|  |  |  |             doShowLayer, | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private zoomToCurrentFeatures(map: MlMap) { | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |         if (this._options.zoomToFeatures) { | 
					
						
							|  |  |  |             const features = this._options.features.features.data | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |             const bbox = BBox.bboxAroundAll(features.map(BBox.get)) | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  |             map.fitBounds(bbox.toLngLat(), { | 
					
						
							|  |  |  |                 padding: { top: 10, bottom: 10, left: 10, right: 10 }, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initDrawFeatures(map: MlMap) { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         let { features, doShowLayer, fetchStore, selectedElement, selectedLayer } = this._options | 
					
						
							| 
									
										
										
										
											2023-04-02 02:59:20 +02:00
										 |  |  |         const onClick = | 
					
						
							|  |  |  |             this._options.onClick ?? | 
					
						
							|  |  |  |             ((feature: Feature) => { | 
					
						
							|  |  |  |                 selectedElement?.setData(feature) | 
					
						
							|  |  |  |                 selectedLayer?.setData(this._options.layer) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |         if (this._options.drawLines !== false) { | 
					
						
							|  |  |  |             for (let i = 0; i < this._options.layer.lineRendering.length; i++) { | 
					
						
							|  |  |  |                 const lineRenderingConfig = this._options.layer.lineRendering[i] | 
					
						
							|  |  |  |                 new LineRenderingLayer( | 
					
						
							|  |  |  |                     map, | 
					
						
							|  |  |  |                     features, | 
					
						
							|  |  |  |                     this._options.layer.id + "_linerendering_" + i, | 
					
						
							|  |  |  |                     lineRenderingConfig, | 
					
						
							|  |  |  |                     doShowLayer, | 
					
						
							|  |  |  |                     fetchStore, | 
					
						
							|  |  |  |                     onClick | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |         if (this._options.drawMarkers !== false) { | 
					
						
							|  |  |  |             for (const pointRenderingConfig of this._options.layer.mapRendering) { | 
					
						
							|  |  |  |                 new PointRenderingLayer( | 
					
						
							|  |  |  |                     map, | 
					
						
							|  |  |  |                     features, | 
					
						
							|  |  |  |                     pointRenderingConfig, | 
					
						
							|  |  |  |                     doShowLayer, | 
					
						
							|  |  |  |                     fetchStore, | 
					
						
							|  |  |  |                     onClick | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-03-24 19:21:15 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         features.features.addCallbackAndRunD((_) => this.zoomToCurrentFeatures(map)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-23 00:58:21 +01:00
										 |  |  | } |