| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * The data layer shows all the given geojson elements with the appropriate icon etc | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | import {UIEventSource} from "../Logic/UIEventSource"; | 
					
						
							|  |  |  | import * as L from "leaflet" | 
					
						
							| 
									
										
										
										
											2021-01-04 18:55:10 +01:00
										 |  |  | import "leaflet.markercluster" | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  | import LayerConfig from "../Customizations/JSON/LayerConfig"; | 
					
						
							|  |  |  | import State from "../State"; | 
					
						
							|  |  |  | import FeatureInfoBox from "./Popup/FeatureInfoBox"; | 
					
						
							| 
									
										
										
										
											2021-01-04 18:55:10 +01:00
										 |  |  | import LayoutConfig from "../Customizations/JSON/LayoutConfig"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default class ShowDataLayer { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-20 01:45:51 +01:00
										 |  |  |     private _layerDict; | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     private readonly _leafletMap: UIEventSource<L.Map>; | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |     private _cleanCount = 0; | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     constructor(features: UIEventSource<{ feature: any, freshness: Date }[]>, | 
					
						
							|  |  |  |                 leafletMap: UIEventSource<L.Map>, | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |                 layoutToUse: UIEventSource<LayoutConfig>) { | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         this._leafletMap = leafletMap; | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |         const mp = leafletMap.data; | 
					
						
							| 
									
										
										
										
											2021-02-20 01:45:51 +01:00
										 |  |  |         self._layerDict = {}; | 
					
						
							| 
									
										
										
										
											2021-02-05 19:11:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |         layoutToUse.addCallbackAndRun(layoutToUse => { | 
					
						
							|  |  |  |             for (const layer of layoutToUse.layers) { | 
					
						
							| 
									
										
										
										
											2021-03-29 02:53:06 +02:00
										 |  |  |                 if (self._layerDict[layer.id] === undefined) { | 
					
						
							|  |  |  |                     self._layerDict[layer.id] = layer; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-02-05 18:58:06 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |         let geoLayer = undefined; | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |         let cluster = undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         function update() { | 
					
						
							|  |  |  |             if (features.data === undefined) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (leafletMap.data === undefined) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |             self._cleanCount++ | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |             // clean all the old stuff away, if any
 | 
					
						
							|  |  |  |             if (geoLayer !== undefined) { | 
					
						
							|  |  |  |                 mp.removeLayer(geoLayer); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (cluster !== undefined) { | 
					
						
							|  |  |  |                 mp.removeLayer(cluster); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const allFeats = features.data.map(ff => ff.feature); | 
					
						
							|  |  |  |             geoLayer = self.CreateGeojsonLayer(); | 
					
						
							|  |  |  |             for (const feat of allFeats) { | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |                 // @ts-ignore
 | 
					
						
							|  |  |  |                 geoLayer.addData(feat); | 
					
						
							| 
									
										
										
										
											2021-01-04 20:09:07 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |             if (layoutToUse.data.clustering.minNeededElements <= allFeats.length) { | 
					
						
							|  |  |  |                 // Activate clustering if it wasn't already activated
 | 
					
						
							|  |  |  |                 const cl = window["L"]; // This is a dirty workaround, the clustering plugin binds to the L of the window, not of the namespace or something
 | 
					
						
							|  |  |  |                 cluster = cl.markerClusterGroup({disableClusteringAtZoom: layoutToUse.data.clustering.maxZoom}); | 
					
						
							|  |  |  |                 cluster.addLayer(geoLayer); | 
					
						
							|  |  |  |                 mp.addLayer(cluster); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 mp.addLayer(geoLayer) | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-02-15 19:06:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-14 20:36:20 +01:00
										 |  |  |             State.state.selectedElement.ping(); | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-05 18:58:06 +01:00
										 |  |  |         features.addCallback(() => update()); | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         leafletMap.addCallback(() => update()); | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |         update(); | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private createStyleFor(feature) { | 
					
						
							| 
									
										
										
										
											2021-03-25 15:19:44 +01:00
										 |  |  |         const tagsSource = State.state.allElements.addOrGetElement(feature); | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         // Every object is tied to exactly one layer
 | 
					
						
							|  |  |  |         const layer = this._layerDict[feature._matching_layer_id]; | 
					
						
							| 
									
										
										
										
											2021-02-20 01:45:51 +01:00
										 |  |  |         return layer?.GenerateLeafletStyle(tagsSource, layer._showOnPopup !== undefined); | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-15 19:06:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     private pointToLayer(feature, latLng): L.Layer { | 
					
						
							|  |  |  |         // Leaflet cannot handle geojson points natively
 | 
					
						
							|  |  |  |         // We have to convert them to the appropriate icon
 | 
					
						
							|  |  |  |         // Click handling is done in the next step
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-17 23:36:46 +02:00
										 |  |  |         const tagSource = State.state.allElements.getEventSourceById(feature.properties.id) | 
					
						
							| 
									
										
										
										
											2021-01-04 18:55:10 +01:00
										 |  |  |         const layer: LayerConfig = this._layerDict[feature._matching_layer_id]; | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  |         if (layer === undefined) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         const style = layer.GenerateLeafletStyle(tagSource, !(layer.title === undefined && (layer.tagRenderings ?? []).length === 0)); | 
					
						
							|  |  |  |         return L.marker(latLng, { | 
					
						
							|  |  |  |             icon: L.divIcon({ | 
					
						
							| 
									
										
										
										
											2021-06-12 02:58:32 +02:00
										 |  |  |                 html: style.icon.html.ConstructElement(), | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |                 className: style.icon.className, | 
					
						
							|  |  |  |                 iconAnchor: style.icon.iconAnchor, | 
					
						
							|  |  |  |                 iconUrl: style.icon.iconUrl, | 
					
						
							|  |  |  |                 popupAnchor: style.icon.popupAnchor, | 
					
						
							|  |  |  |                 iconSize: style.icon.iconSize | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-04 18:55:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private postProcessFeature(feature, leafletLayer: L.Layer) { | 
					
						
							|  |  |  |         const layer: LayerConfig = this._layerDict[feature._matching_layer_id]; | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |         if (layer === undefined) { | 
					
						
							| 
									
										
										
										
											2021-03-21 01:32:21 +01:00
										 |  |  |             console.warn("No layer found for object (probably a now disabled layer)", feature, this._layerDict) | 
					
						
							| 
									
										
										
										
											2021-02-20 01:45:51 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         if (layer.title === undefined && (layer.tagRenderings ?? []).length === 0) { | 
					
						
							|  |  |  |             // No popup action defined -> Don't do anything
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const popup = L.popup({ | 
					
						
							|  |  |  |             autoPan: true, | 
					
						
							|  |  |  |             closeOnEscapeKey: true, | 
					
						
							| 
									
										
										
										
											2021-02-05 16:32:37 +01:00
										 |  |  |             closeButton: false | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         }, leafletLayer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 16:18:58 +02:00
										 |  |  |         leafletLayer.bindPopup(popup); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let infobox: FeatureInfoBox = undefined; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |         const id = `popup-${feature.properties.id}-${this._cleanCount}` | 
					
						
							| 
									
										
										
										
											2021-06-15 16:18:58 +02:00
										 |  |  |         popup.setContent(`<div style='height: 65vh' id='${id}'>Rendering</div>`) | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-05 18:58:06 +01:00
										 |  |  |         leafletLayer.on("popupopen", () => { | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |             State.state.selectedElement.setData(feature) | 
					
						
							| 
									
										
										
										
											2021-06-15 16:18:58 +02:00
										 |  |  |             if (infobox === undefined) { | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |                 const tags = State.state.allElements.getEventSourceById(feature.properties.id); | 
					
						
							|  |  |  |                 infobox = new FeatureInfoBox(tags, layer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 infobox.isShown.addCallback(isShown => { | 
					
						
							|  |  |  |                     if (!isShown) { | 
					
						
							|  |  |  |                         State.state.selectedElement.setData(undefined); | 
					
						
							| 
									
										
										
										
											2021-06-15 16:18:58 +02:00
										 |  |  |                         leafletLayer.closePopup() | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             infobox.AttachTo(id) | 
					
						
							|  |  |  |             infobox.Activate(); | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |         const self = this; | 
					
						
							|  |  |  |         State.state.selectedElement.addCallbackAndRun(selected => { | 
					
						
							|  |  |  |             if (selected === undefined || self._leafletMap.data === undefined) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-06-16 14:23:53 +02:00
										 |  |  |             if (leafletLayer.getPopup().isOpen()) { | 
					
						
							| 
									
										
										
										
											2021-06-14 17:28:11 +02:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (selected.properties.id === feature.properties.id) { | 
					
						
							|  |  |  |                 leafletLayer.openPopup() | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-06-15 16:18:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |     private CreateGeojsonLayer(): L.Layer { | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         const self = this; | 
					
						
							|  |  |  |         const data = { | 
					
						
							|  |  |  |             type: "FeatureCollection", | 
					
						
							| 
									
										
										
										
											2021-02-06 00:05:38 +01:00
										 |  |  |             features: [] | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-21 01:36:34 +01:00
										 |  |  |         // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-01-04 04:06:21 +01:00
										 |  |  |         return L.geoJSON(data, { | 
					
						
							|  |  |  |             style: feature => self.createStyleFor(feature), | 
					
						
							|  |  |  |             pointToLayer: (feature, latLng) => self.pointToLayer(feature, latLng), | 
					
						
							|  |  |  |             onEachFeature: (feature, leafletLayer) => self.postProcessFeature(feature, leafletLayer) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |