forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			133 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Store, UIEventSource } from "../UIEventSource"
 | |
| import FilteredLayer from "../../Models/FilteredLayer"
 | |
| import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig"
 | |
| import { QueryParameters } from "../Web/QueryParameters"
 | |
| import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer"
 | |
| import { FeatureSource, FeatureSourceForLayer, Tiled } from "../FeatureSource/FeatureSource"
 | |
| import StaticFeatureSource, {
 | |
|     TiledStaticFeatureSource,
 | |
| } from "../FeatureSource/Sources/StaticFeatureSource"
 | |
| import { Feature } from "geojson"
 | |
| import { MapProperties } from "../../Models/MapProperties"
 | |
| 
 | |
| /**
 | |
|  * Contains all the leaflet-map related state
 | |
|  */
 | |
| export default class MapState {
 | |
|     /**
 | |
|      * Last location where a click was registered
 | |
|      */
 | |
|     public readonly LastClickLocation: UIEventSource<{
 | |
|         lat: number
 | |
|         lon: number
 | |
|     }> = new UIEventSource<{ lat: number; lon: number }>(undefined)
 | |
| 
 | |
|     /**
 | |
|      * The bounds of the current map view
 | |
|      */
 | |
|     public currentView: FeatureSourceForLayer & Tiled
 | |
| 
 | |
|     /**
 | |
|      * A builtin layer which contains the selected element.
 | |
|      * Loads 'selected_element.json'
 | |
|      * This _might_ contain multiple points, e.g. every center of a multipolygon
 | |
|      */
 | |
|     public selectedElementsLayer: FeatureSourceForLayer & Tiled
 | |
| 
 | |
|     /**
 | |
|      * Which overlays are shown
 | |
|      */
 | |
|     public overlayToggles: { config: TilesourceConfig; isDisplayed: UIEventSource<boolean> }[]
 | |
| 
 | |
|     constructor() {
 | |
|         this.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(this.locationControl)
 | |
| 
 | |
|         let defaultLayer = AvailableBaseLayers.osmCarto
 | |
|         const available = this.availableBackgroundLayers.data
 | |
|         for (const layer of available) {
 | |
|             if (this.backgroundLayerId.data === layer.id) {
 | |
|                 defaultLayer = layer
 | |
|             }
 | |
|         }
 | |
|         const self = this
 | |
|         this.backgroundLayer = new UIEventSource<BaseLayer>(defaultLayer)
 | |
|         this.backgroundLayer.addCallbackAndRunD((layer) => self.backgroundLayerId.setData(layer.id))
 | |
| 
 | |
|         this.overlayToggles =
 | |
|             this.layoutToUse?.tileLayerSources
 | |
|                 ?.filter((c) => c.name !== undefined)
 | |
|                 ?.map((c) => ({
 | |
|                     config: c,
 | |
|                     isDisplayed: QueryParameters.GetBooleanQueryParameter(
 | |
|                         "overlay-" + c.id,
 | |
|                         c.defaultState,
 | |
|                         "Wether or not the overlay " + c.id + " is shown"
 | |
|                     ),
 | |
|                 })) ?? []
 | |
| 
 | |
|         this.AddAllOverlaysToMap(this.leafletMap)
 | |
| 
 | |
|         this.initCurrentView()
 | |
|         this.initSelectedElement()
 | |
|     }
 | |
| 
 | |
|     public AddAllOverlaysToMap(leafletMap: UIEventSource<any>) {
 | |
|         const initialized = new Set()
 | |
|         for (const overlayToggle of this.overlayToggles) {
 | |
|             new ShowOverlayLayer(overlayToggle.config, leafletMap, overlayToggle.isDisplayed)
 | |
|             initialized.add(overlayToggle.config)
 | |
|         }
 | |
| 
 | |
|         for (const tileLayerSource of this.layoutToUse?.tileLayerSources ?? []) {
 | |
|             if (initialized.has(tileLayerSource)) {
 | |
|                 continue
 | |
|             }
 | |
|             new ShowOverlayLayer(tileLayerSource, leafletMap)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private static initCurrentView(mapproperties: MapProperties): FeatureSource {
 | |
|         let i = 0
 | |
|         const features: Store<Feature[]> = mapproperties.bounds.map((bounds) => {
 | |
|             if (bounds === undefined) {
 | |
|                 return []
 | |
|             }
 | |
|             i++
 | |
|             return [
 | |
|                 bounds.asGeoJson({
 | |
|                     id: "current_view-" + i,
 | |
|                     current_view: "yes",
 | |
|                     zoom: "" + mapproperties.zoom.data,
 | |
|                 }),
 | |
|             ]
 | |
|         })
 | |
| 
 | |
|         return new StaticFeatureSource(features)
 | |
|     }
 | |
| 
 | |
|     private initSelectedElement() {
 | |
|         const layerDef: FilteredLayer = this.filteredLayers.data.filter(
 | |
|             (l) => l.layerDef.id === "selected_element"
 | |
|         )[0]
 | |
|         const empty = []
 | |
|         const store = this.selectedElement.map((feature) => {
 | |
|             if (feature === undefined || feature === null) {
 | |
|                 return empty
 | |
|             }
 | |
|             return [
 | |
|                 {
 | |
|                     feature: {
 | |
|                         type: "Feature",
 | |
|                         properties: {
 | |
|                             selected: "yes",
 | |
|                             id: "selected" + feature.properties.id,
 | |
|                         },
 | |
|                         geometry: feature.geometry,
 | |
|                     },
 | |
|                     freshness: new Date(),
 | |
|                 },
 | |
|             ]
 | |
|         })
 | |
|         this.selectedElementsLayer = new TiledStaticFeatureSource(store, layerDef)
 | |
|     }
 | |
| }
 |