| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  | import ThemeConfig from "../ThemeConfig/ThemeConfig" | 
					
						
							|  |  |  | import { WithChangesState } from "./WithChangesState" | 
					
						
							|  |  |  | import FavouritesFeatureSource from "../../Logic/FeatureSource/Sources/FavouritesFeatureSource" | 
					
						
							|  |  |  | import Constants from "../Constants" | 
					
						
							|  |  |  | import { FeatureSource } from "../../Logic/FeatureSource/FeatureSource" | 
					
						
							|  |  |  | import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" | 
					
						
							|  |  |  | import { Feature } from "geojson" | 
					
						
							|  |  |  | import { BBox } from "../../Logic/BBox" | 
					
						
							|  |  |  | import ShowDataLayer from "../../UI/Map/ShowDataLayer" | 
					
						
							|  |  |  | import MetaTagging from "../../Logic/MetaTagging" | 
					
						
							|  |  |  | import FilteredLayer from "../FilteredLayer" | 
					
						
							|  |  |  | import LayerConfig from "../ThemeConfig/LayerConfig" | 
					
						
							|  |  |  | import { LayerConfigJson } from "../ThemeConfig/Json/LayerConfigJson" | 
					
						
							|  |  |  | import last_click_layerconfig from "../../assets/generated/layers/last_click.json" | 
					
						
							|  |  |  | import { GeoOperations } from "../../Logic/GeoOperations" | 
					
						
							|  |  |  | import summaryLayer from "../../assets/generated/layers/summary.json" | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  | import { Store, UIEventSource } from "../../Logic/UIEventSource" | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  | import NearbyFeatureSource from "../../Logic/FeatureSource/Sources/NearbyFeatureSource" | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |     SummaryTileSource, | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |     SummaryTileSourceRewriter, | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  | } from "../../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" | 
					
						
							|  |  |  | import { ShowDataLayerOptions } from "../../UI/Map/ShowDataLayerOptions" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class WithSpecialLayers extends WithChangesState { | 
					
						
							|  |  |  |     readonly favourites: FavouritesFeatureSource | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * When hovering (in the popup) an image, the location of the image will be revealed on the main map. | 
					
						
							|  |  |  |      * This store contains those images that should be shown, probably only the currently hovered image | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     readonly geocodedImages: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([]) | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Contains a few (<10) >features that are near the center of the map. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     readonly closestFeatures: NearbyFeatureSource | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     readonly featureSummary: SummaryTileSourceRewriter | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * When using arrow keys to move, the accessibility mode is activated, which has a small rectangle set. | 
					
						
							|  |  |  |      * This is the 'viewport' which 'closestFeatures' uses to filter wilt | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     readonly visualFeedbackViewportBounds: UIEventSource<BBox> = new UIEventSource<BBox>(undefined) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |     constructor(theme: ThemeConfig, mvtAvailableLayers: Store<Set<string>>) { | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         super(theme, mvtAvailableLayers) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.favourites = new FavouritesFeatureSource(this) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.closestFeatures = new NearbyFeatureSource( | 
					
						
							|  |  |  |             this.mapProperties.location, | 
					
						
							|  |  |  |             this.perLayerFiltered, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 currentZoom: this.mapProperties.zoom, | 
					
						
							|  |  |  |                 layerState: this.layerState, | 
					
						
							|  |  |  |                 bounds: this.visualFeedbackViewportBounds.map( | 
					
						
							|  |  |  |                     (bounds) => bounds ?? this.mapProperties.bounds?.data, | 
					
						
							|  |  |  |                     [this.mapProperties.bounds] | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         this.closestFeatures.registerSource(this.favourites, "favourite") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.featureSummary = this.setupSummaryLayer() | 
					
						
							|  |  |  |         this.initActorsSpecialLayers() | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |         this.drawSelectedElement() | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         this.drawSpecialLayers() | 
					
						
							|  |  |  |         this.drawLastClick() | 
					
						
							|  |  |  |         // Note: the lock-range is handled by UserMapFeatureSwitchState
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Activate metatagging for the 'current_view' layer
 | 
					
						
							|  |  |  |             const currentViewLayer = this.layerState.filteredLayers.get("current_view")?.layerDef | 
					
						
							|  |  |  |             if (currentViewLayer?.tagRenderings?.length > 0) { | 
					
						
							|  |  |  |                 const params = MetaTagging.createExtraFuncParams(this) | 
					
						
							|  |  |  |                 this.currentView.features.addCallbackAndRunD((features) => { | 
					
						
							|  |  |  |                     MetaTagging.addMetatags( | 
					
						
							|  |  |  |                         features, | 
					
						
							|  |  |  |                         params, | 
					
						
							|  |  |  |                         currentViewLayer, | 
					
						
							|  |  |  |                         this.theme, | 
					
						
							|  |  |  |                         this.osmObjectDownloader, | 
					
						
							|  |  |  |                         this.featureProperties | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private setupSummaryLayer(): SummaryTileSourceRewriter | undefined { | 
					
						
							|  |  |  |         /** | 
					
						
							|  |  |  |          * MaxZoom for the summary layer | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         const normalLayers = this.theme.layers.filter((l) => l.isNormal()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const maxzoom = Math.min(...normalLayers.map((l) => l.minzoom)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const layers = this.theme.layers.filter( | 
					
						
							|  |  |  |             (l) => | 
					
						
							|  |  |  |                 (<string[]>(<unknown>Constants.priviliged_layers)).indexOf(l.id) < 0 && | 
					
						
							|  |  |  |                 l.source.geojsonSource === undefined && | 
					
						
							|  |  |  |                 l.doCount | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         if (!Constants.SummaryServer || layers.length === 0) { | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const summaryTileSource = new SummaryTileSource( | 
					
						
							|  |  |  |             Constants.SummaryServer, | 
					
						
							|  |  |  |             layers.map((l) => l.id), | 
					
						
							|  |  |  |             this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)), | 
					
						
							|  |  |  |             this.mapProperties, | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |                 isActive: this.mapProperties.zoom.map((z) => z < maxzoom), | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |         const source = new SummaryTileSourceRewriter( | 
					
						
							|  |  |  |             summaryTileSource, | 
					
						
							|  |  |  |             this.layerState.filteredLayers | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         new ShowDataLayer(this.map, { | 
					
						
							|  |  |  |             features: source, | 
					
						
							|  |  |  |             layer: new LayerConfig(<LayerConfigJson>summaryLayer, "summaryLayer"), | 
					
						
							|  |  |  |             // doShowLayer: this.mapProperties.zoom.map((z) => z < maxzoom),
 | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |             selectedElement: this.selectedElement, | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         }) | 
					
						
							|  |  |  |         return source | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected registerSpecialLayer(flayer: FilteredLayer, source: FeatureSource) { | 
					
						
							|  |  |  |         if (!source?.features) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.featureProperties.trackFeatureSource(source) | 
					
						
							|  |  |  |         const options: ShowDataLayerOptions & { layer: LayerConfig } = { | 
					
						
							|  |  |  |             features: source, | 
					
						
							|  |  |  |             doShowLayer: flayer.isDisplayed, | 
					
						
							|  |  |  |             layer: flayer.layerDef, | 
					
						
							|  |  |  |             metaTags: this.userRelatedState.preferencesAsTags, | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |             selectedElement: this.selectedElement, | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         new ShowDataLayer(this.map, options) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private drawLastClick() { | 
					
						
							|  |  |  |         const source = this.lastClickObject | 
					
						
							|  |  |  |         const lastClickLayerConfig = new LayerConfig( | 
					
						
							|  |  |  |             <LayerConfigJson>last_click_layerconfig, | 
					
						
							|  |  |  |             "last_click" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         const lastClickFiltered = | 
					
						
							|  |  |  |             lastClickLayerConfig.isShown === undefined | 
					
						
							|  |  |  |                 ? source | 
					
						
							|  |  |  |                 : source.features.mapD((fs) => | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |                       fs.filter((f) => { | 
					
						
							|  |  |  |                           const matches = lastClickLayerConfig.isShown.matchesProperties( | 
					
						
							|  |  |  |                               f.properties | 
					
						
							|  |  |  |                           ) | 
					
						
							|  |  |  |                           console.debug("LastClick ", f, "matches", matches) | 
					
						
							|  |  |  |                           return matches | 
					
						
							|  |  |  |                       }) | 
					
						
							|  |  |  |                   ) | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         // show last click = new point/note marker
 | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |         const features = new StaticFeatureSource(lastClickFiltered) | 
					
						
							|  |  |  |         this.featureProperties.trackFeatureSource(features) | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         new ShowDataLayer(this.map, { | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |             features, | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |             layer: lastClickLayerConfig, | 
					
						
							|  |  |  |             onClick: (feature) => { | 
					
						
							|  |  |  |                 if (this.mapProperties.zoom.data >= Constants.minZoomLevelToAddNewPoint) { | 
					
						
							|  |  |  |                     this.selectedElement.setData(feature) | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 this.map.data.flyTo({ | 
					
						
							|  |  |  |                     zoom: Constants.minZoomLevelToAddNewPoint, | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |                     center: GeoOperations.centerpointCoordinates(feature), | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |     private drawSelectedElement() { | 
					
						
							|  |  |  |         const src = new StaticFeatureSource( | 
					
						
							|  |  |  |             this.selectedElement.map((f) => (f === undefined ? [] : [f])) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         ShowDataLayer.showMultipleLayers(this.map, src, this.theme.layers) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |     private drawSpecialLayers() { | 
					
						
							|  |  |  |         type AddedByDefaultTypes = (typeof Constants.added_by_default)[number] | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |         type LayersToAdd = | 
					
						
							|  |  |  |             | "current_view" | 
					
						
							|  |  |  |             | Exclude< | 
					
						
							|  |  |  |                   AddedByDefaultTypes, | 
					
						
							|  |  |  |                   | "search" // Handled by WithSearchState
 | 
					
						
							|  |  |  |                   | "last_click" // handled by this.drawLastClick()
 | 
					
						
							|  |  |  |                   | "summary" // handled by setupSummaryLayer
 | 
					
						
							|  |  |  |                   | "range" // handled by UserMapFeatureSwitchState
 | 
					
						
							|  |  |  |                   | "selected_element" // handled by this.drawSelectedElement
 | 
					
						
							|  |  |  |               > | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         const empty = [] | 
					
						
							|  |  |  |         /** | 
					
						
							|  |  |  |          * A listing which maps the layerId onto the featureSource | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         const specialLayers: Record<LayersToAdd, FeatureSource> = { | 
					
						
							|  |  |  |             home_location: this.userRelatedState.homeLocation, | 
					
						
							|  |  |  |             gps_location: this.geolocation.currentUserLocation, | 
					
						
							|  |  |  |             gps_location_history: this.geolocation.historicalUserLocations, | 
					
						
							|  |  |  |             gps_track: this.geolocation.historicalUserLocationsTrack, | 
					
						
							|  |  |  |             current_view: this.currentView, | 
					
						
							|  |  |  |             favourite: this.favourites, | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |             geocoded_image: new StaticFeatureSource(this.geocodedImages), | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // enumerate all 'normal' layers and match them with the appropriate 'special' layer - if applicable
 | 
					
						
							|  |  |  |         this.layerState.filteredLayers.forEach((flayer) => { | 
					
						
							|  |  |  |             this.registerSpecialLayer(flayer, specialLayers[flayer.layerDef.id]) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private initActorsSpecialLayers() { | 
					
						
							|  |  |  |         this.selectedElement.addCallback((selected) => { | 
					
						
							|  |  |  |             if (selected === undefined) { | 
					
						
							|  |  |  |                 this.focusOnMap() | 
					
						
							|  |  |  |                 this.geocodedImages.set([]) | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 this.lastClickObject.clear() | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |