forked from MapComplete/MapComplete
		
	More refactoring, stabilizing rotation and direction_gradient
This commit is contained in:
		
							parent
							
								
									5fec108ba2
								
							
						
					
					
						commit
						778044d0fb
					
				
					 45 changed files with 656 additions and 640 deletions
				
			
		
							
								
								
									
										141
									
								
								UI/ShowDataLayer.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								UI/ShowDataLayer.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,141 @@ | |||
| /** | ||||
|  * The data layer shows all the given geojson elements with the appropriate icon etc | ||||
|  */ | ||||
| import {UIEventSource} from "../Logic/UIEventSource"; | ||||
| import * as L from "leaflet" | ||||
| import LayerConfig from "../Customizations/JSON/LayerConfig"; | ||||
| import State from "../State"; | ||||
| import LazyElement from "./Base/LazyElement"; | ||||
| import Hash from "../Logic/Web/Hash"; | ||||
| import {GeoOperations} from "../Logic/GeoOperations"; | ||||
| import FeatureInfoBox from "./Popup/FeatureInfoBox"; | ||||
| 
 | ||||
| export default class ShowDataLayer { | ||||
| 
 | ||||
|     private readonly _layerDict; | ||||
|     private readonly _leafletMap: UIEventSource<L.Map>; | ||||
| 
 | ||||
|     constructor(features: UIEventSource<{ feature: any, freshness: Date }[]>, | ||||
|                 leafletMap: UIEventSource<L.Map>, | ||||
|                 layers: { layerDef: LayerConfig, isDisplayed: UIEventSource<boolean> }[]) { | ||||
|         this._leafletMap = leafletMap; | ||||
|         const self = this; | ||||
| 
 | ||||
|         let oldGeoLayer: L.Layer = undefined; | ||||
| 
 | ||||
|         this._layerDict = {}; | ||||
|         for (const layer of layers) { | ||||
|             this._layerDict[layer.layerDef.id] = layer.layerDef; | ||||
|         } | ||||
| 
 | ||||
|         function update() { | ||||
|             if (features.data === undefined) { | ||||
|                 return; | ||||
|             } | ||||
|             if (leafletMap.data === undefined) { | ||||
|                 return; | ||||
|             } | ||||
|             const mp = leafletMap.data; | ||||
| 
 | ||||
|             const feats = features.data.map(ff => ff.feature); | ||||
|             const geoLayer = self.CreateGeojsonLayer(feats); | ||||
| 
 | ||||
|             if (oldGeoLayer) { | ||||
|                 mp.removeLayer(oldGeoLayer); | ||||
|             } | ||||
| 
 | ||||
|             geoLayer.addTo(mp); | ||||
|             oldGeoLayer = geoLayer; | ||||
|         } | ||||
| 
 | ||||
|         features.addCallbackAndRun(() => update()); | ||||
|         leafletMap.addCallback(() => update()); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private createStyleFor(feature) { | ||||
|         const tagsSource = State.state.allElements.getEventSourceFor(feature); | ||||
|         // Every object is tied to exactly one layer
 | ||||
|         const layer = this._layerDict[feature._matching_layer_id]; | ||||
|         return layer.GenerateLeafletStyle(tagsSource, layer._showOnPopup !== undefined); | ||||
|     } | ||||
| 
 | ||||
|     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
 | ||||
| 
 | ||||
|         const tagSource = State.state.allElements.getEventSourceFor(feature); | ||||
|         const layer : LayerConfig = this._layerDict[feature._matching_layer_id]; | ||||
| 
 | ||||
|         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 | ||||
|             }) | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     private postProcessFeature(feature, leafletLayer: L.Layer){ | ||||
|         const layer : LayerConfig = this._layerDict[feature._matching_layer_id]; | ||||
|         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, | ||||
|         }, leafletLayer); | ||||
| 
 | ||||
| 
 | ||||
|         const tags = State.state.allElements.getEventSourceFor(feature); | ||||
|         let uiElement: LazyElement = new LazyElement(() => new FeatureInfoBox(tags, layer)); | ||||
|         popup.setContent(uiElement.Render()); | ||||
|         leafletLayer.bindPopup(popup); | ||||
|         // We first render the UIelement (which'll still need an update later on...)
 | ||||
|         // But at least it'll be visible already
 | ||||
| 
 | ||||
| 
 | ||||
|         leafletLayer.on("click", (e) => { | ||||
|             // We set the element as selected...
 | ||||
|             uiElement.Activate(); | ||||
|             State.state.selectedElement.setData(feature); | ||||
|         }); | ||||
|          | ||||
| 
 | ||||
|         if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) { | ||||
|             // This element is in the URL, so this is a share link
 | ||||
|             // We already open it
 | ||||
|             uiElement.Activate(); | ||||
|             popup.setContent(uiElement.Render()); | ||||
| 
 | ||||
|             const center = GeoOperations.centerpoint(feature).geometry.coordinates; | ||||
|             popup.setLatLng({lat: center[1], lng: center[0]}); | ||||
|             popup.openOn(State.state.leafletMap.data); | ||||
|             State.state.selectedElement.setData(feature); | ||||
|             uiElement.Update(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private CreateGeojsonLayer(features: any[]): L.Layer { | ||||
|         const self = this; | ||||
|         const data = { | ||||
|             type: "FeatureCollection", | ||||
|             features: features | ||||
|         } | ||||
|         return L.geoJSON(data, { | ||||
|             style: feature => self.createStyleFor(feature), | ||||
|             pointToLayer: (feature, latLng) => self.pointToLayer(feature, latLng), | ||||
|             onEachFeature: (feature, leafletLayer) => self.postProcessFeature(feature, leafletLayer) | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue