| 
									
										
										
										
											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-03-22 00:28:21 +01:00
										 |  |  |     private readonly _popups = new Map<any, L.Layer>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-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-03-22 00:28:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         State.state.selectedElement.addCallbackAndRun(selected => { | 
					
						
							|  |  |  |             if (selected === undefined) { | 
					
						
							|  |  |  |                 mp.closePopup(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const marker = self._popups.get(selected); | 
					
						
							|  |  |  |             if (marker === undefined) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             marker.openPopup(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const popup = marker.getPopup(); | 
					
						
							| 
									
										
										
										
											2021-04-17 23:36:46 +02:00
										 |  |  |             const tags = State.state.allElements.getEventSourceById(selected.properties.id); | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |             const layer: LayerConfig = this._layerDict[selected._matching_layer_id]; | 
					
						
							|  |  |  |             const infoBox = FeatureInfoBox.construct(tags, layer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             infoBox.isShown.addCallback(isShown => { | 
					
						
							|  |  |  |                 if (!isShown) { | 
					
						
							|  |  |  |                     State.state.selectedElement.setData(undefined); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             popup.setContent(infoBox.Render()); | 
					
						
							|  |  |  |             infoBox.Activate(); | 
					
						
							|  |  |  |             infoBox.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({ | 
					
						
							|  |  |  |                 html: style.icon.html.Render(), | 
					
						
							|  |  |  |                 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-03-22 00:28:21 +01:00
										 |  |  |         // By setting 50vh, leaflet will attempt to fit the entire screen and move the feature down
 | 
					
						
							|  |  |  |         popup.setContent("<div style='height: 50vh'>Rendering</div>"); | 
					
						
							| 
									
										
										
										
											2021-02-14 19:45:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |         leafletLayer.bindPopup(popup); | 
					
						
							| 
									
										
										
										
											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-02-14 19:45:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 00:28:21 +01:00
										 |  |  |         this._popups.set(feature, leafletLayer); | 
					
						
							| 
									
										
										
										
											2021-02-05 18:58:06 +01: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) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |