| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | 
					
						
							|  |  |  | import FilteringFeatureSource from "./Sources/FilteringFeatureSource" | 
					
						
							|  |  |  | import PerLayerFeatureSourceSplitter from "./PerLayerFeatureSourceSplitter" | 
					
						
							| 
									
										
										
										
											2021-09-28 18:00:44 +02:00
										 |  |  | import FeatureSource, { FeatureSourceForLayer, IndexedFeatureSource, Tiled } from "./FeatureSource" | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | import TiledFeatureSource from "./TiledFeatureSource/TiledFeatureSource" | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  | import { Store, UIEventSource } from "../UIEventSource" | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | import { TileHierarchyTools } from "./TiledFeatureSource/TileHierarchy" | 
					
						
							|  |  |  | import RememberingSource from "./Sources/RememberingSource" | 
					
						
							|  |  |  | import OverpassFeatureSource from "../Actors/OverpassFeatureSource" | 
					
						
							|  |  |  | import GeoJsonSource from "./Sources/GeoJsonSource" | 
					
						
							|  |  |  | import Loc from "../../Models/Loc" | 
					
						
							|  |  |  | import RegisteringAllFromFeatureSourceActor from "./Actors/RegisteringAllFromFeatureSourceActor" | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  | import SaveTileToLocalStorageActor from "./Actors/SaveTileToLocalStorageActor" | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | import DynamicGeoJsonTileSource from "./TiledFeatureSource/DynamicGeoJsonTileSource" | 
					
						
							|  |  |  | import { TileHierarchyMerger } from "./TiledFeatureSource/TileHierarchyMerger" | 
					
						
							|  |  |  | import RelationsTracker from "../Osm/RelationsTracker" | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  | import { NewGeometryFromChangesFeatureSource } from "./Sources/NewGeometryFromChangesFeatureSource" | 
					
						
							| 
									
										
										
										
											2021-09-22 16:07:56 +02:00
										 |  |  | import ChangeGeometryApplicator from "./Sources/ChangeGeometryApplicator" | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | import { BBox } from "../BBox" | 
					
						
							|  |  |  | import OsmFeatureSource from "./TiledFeatureSource/OsmFeatureSource" | 
					
						
							|  |  |  | import { Tiles } from "../../Models/TileRange" | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  | import TileFreshnessCalculator from "./TileFreshnessCalculator" | 
					
						
							| 
									
										
										
										
											2021-10-31 02:08:39 +01:00
										 |  |  | import FullNodeDatabaseSource from "./TiledFeatureSource/FullNodeDatabaseSource" | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  | import MapState from "../State/MapState" | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  | import { ElementStorage } from "../ElementStorage" | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  | import { OsmFeature } from "../../Models/OsmFeature" | 
					
						
							| 
									
										
										
										
											2022-07-25 18:55:15 +02:00
										 |  |  | import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | 
					
						
							|  |  |  | import { FilterState } from "../../Models/FilteredLayer" | 
					
						
							|  |  |  | import { GeoOperations } from "../GeoOperations" | 
					
						
							|  |  |  | import { Utils } from "../../Utils" | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * The features pipeline ties together a myriad of various datasources: | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |  * - The Overpass-API | 
					
						
							|  |  |  |  * - The OSM-API | 
					
						
							|  |  |  |  * - Third-party geojson files, either sliced or directly. | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |  * In order to truly understand this class, please have a look at the following diagram: https://cdn-images-1.medium.com/fit/c/800/618/1*qTK1iCtyJUr4zOyw4IFD7A.jpeg
 | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | export default class FeaturePipeline { | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     public readonly sufficientlyZoomed: Store<boolean> | 
					
						
							|  |  |  |     public readonly runningQuery: Store<boolean> | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |     public readonly timeout: UIEventSource<number> | 
					
						
							|  |  |  |     public readonly somethingLoaded: UIEventSource<boolean> = new UIEventSource<boolean>(false) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |     public readonly newDataLoadedSignal: UIEventSource<FeatureSource> = | 
					
						
							|  |  |  |         new UIEventSource<FeatureSource>(undefined) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     public readonly relationTracker: RelationsTracker | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Keeps track of all raw OSM-nodes. | 
					
						
							|  |  |  |      * Only initialized if 'type_node' is defined as layer | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly fullNodeDatabase?: FullNodeDatabaseSource | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |     private readonly overpassUpdater: OverpassFeatureSource | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |     private state: MapState | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |     private readonly perLayerHierarchy: Map<string, TileHierarchyMerger> | 
					
						
							| 
									
										
										
										
											2022-01-15 02:44:11 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Keeps track of the age of the loaded data. | 
					
						
							|  |  |  |      * Has one freshness-Calculator for every layer | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |     private readonly freshnesses = new Map<string, TileFreshnessCalculator>() | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |     private readonly oldestAllowedDate: Date | 
					
						
							| 
									
										
										
										
											2021-10-15 18:48:33 +02:00
										 |  |  |     private readonly osmSourceZoomLevel | 
					
						
							| 
									
										
										
										
											2021-11-15 11:51:32 +01:00
										 |  |  |     private readonly localStorageSavers = new Map<string, SaveTileToLocalStorageActor>() | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 00:44:51 +01:00
										 |  |  |     private readonly newGeometryHandler: NewGeometryFromChangesFeatureSource | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |     constructor( | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void, | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |         state: MapState, | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         options?: { | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |             /*Used for metatagging - will receive all the sources with changeGeometry applied but without filtering*/ | 
					
						
							|  |  |  |             handleRawFeatureSource: (source: FeatureSourceForLayer) => void | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         this.state = state | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const self = this | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         const expiryInSeconds = Math.min( | 
					
						
							|  |  |  |             ...(state.layoutToUse?.layers?.map((l) => l.maxAgeOfCache) ?? []) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-10-25 21:08:44 +02:00
										 |  |  |         this.oldestAllowedDate = new Date(new Date().getTime() - expiryInSeconds) | 
					
						
							| 
									
										
										
										
											2021-10-15 18:48:33 +02:00
										 |  |  |         this.osmSourceZoomLevel = state.osmApiTileSize.data | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |         const useOsmApi = state.locationControl.map( | 
					
						
							|  |  |  |             (l) => l.zoom > (state.overpassMaxZoom.data ?? 12) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |         this.relationTracker = new RelationsTracker() | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-25 21:08:44 +02:00
										 |  |  |         state.changes.allChanges.addCallbackAndRun((allChanges) => { | 
					
						
							| 
									
										
										
										
											2021-10-26 01:14:22 +02:00
										 |  |  |             allChanges | 
					
						
							|  |  |  |                 .filter((ch) => ch.id < 0 && ch.changes !== undefined) | 
					
						
							| 
									
										
										
										
											2021-10-25 21:08:44 +02:00
										 |  |  |                 .map((ch) => ch.changes) | 
					
						
							|  |  |  |                 .filter((coor) => coor["lat"] !== undefined && coor["lon"] !== undefined) | 
					
						
							|  |  |  |                 .forEach((coor) => { | 
					
						
							| 
									
										
										
										
											2021-11-22 03:49:17 +01:00
										 |  |  |                     state.layoutToUse.layers.forEach((l) => | 
					
						
							|  |  |  |                         self.localStorageSavers.get(l.id)?.poison(coor["lon"], coor["lat"]) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2021-10-25 21:08:44 +02:00
										 |  |  |                 }) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.sufficientlyZoomed = state.locationControl.map((location) => { | 
					
						
							|  |  |  |             if (location?.zoom === undefined) { | 
					
						
							|  |  |  |                 return false | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-30 20:41:45 +01:00
										 |  |  |             let minzoom = Math.min( | 
					
						
							|  |  |  |                 ...state.filteredLayers.data.map((layer) => layer.layerDef.minzoom ?? 18) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |             ) | 
					
						
							|  |  |  |             return location.zoom >= minzoom | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 01:34:59 +02:00
										 |  |  |         const neededTilesFromOsm = this.getNeededTilesFromOsm(this.sufficientlyZoomed) | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const perLayerHierarchy = new Map<string, TileHierarchyMerger>() | 
					
						
							|  |  |  |         this.perLayerHierarchy = perLayerHierarchy | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-06 03:24:33 +01:00
										 |  |  |         // Given a tile, wraps it and passes it on to render (handled by 'handleFeatureSource'
 | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |         function patchedHandleFeatureSource( | 
					
						
							|  |  |  |             src: FeatureSourceForLayer & IndexedFeatureSource & Tiled | 
					
						
							|  |  |  |         ) { | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             // This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile
 | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |             const withChanges = new ChangeGeometryApplicator(src, state.changes) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             const srcFiltered = new FilteringFeatureSource(state, src.tileIndex, withChanges) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             handleFeatureSource(srcFiltered) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (options?.handleRawFeatureSource) { | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |                 options.handleRawFeatureSource(withChanges) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             self.somethingLoaded.setData(true) | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |             // We do not mark as visited here, this is the responsability of the code near the actual loader (e.g. overpassLoader and OSMApiFeatureLoader)
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |         function handlePriviligedFeatureSource(src: FeatureSourceForLayer & Tiled) { | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |             // Passthrough to passed function, except that it registers as well
 | 
					
						
							|  |  |  |             handleFeatureSource(src) | 
					
						
							|  |  |  |             src.features.addCallbackAndRunD((fs) => { | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |                 fs.forEach((ff) => state.allElements.addOrGetElement(ff.feature)) | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |         for (const filteredLayer of state.filteredLayers.data) { | 
					
						
							|  |  |  |             const id = filteredLayer.layerDef.id | 
					
						
							|  |  |  |             const source = filteredLayer.layerDef.source | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             const hierarchy = new TileHierarchyMerger(filteredLayer, (tile, _) => | 
					
						
							|  |  |  |                 patchedHandleFeatureSource(tile) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             perLayerHierarchy.set(id, hierarchy) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.freshnesses.set(id, new TileFreshnessCalculator()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |             if (id === "type_node") { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |                 this.fullNodeDatabase = new FullNodeDatabaseSource(filteredLayer, (tile) => { | 
					
						
							|  |  |  |                     new RegisteringAllFromFeatureSourceActor(tile, state.allElements) | 
					
						
							|  |  |  |                     perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                     tile.features.addCallbackAndRunD((_) => self.onNewDataLoaded(tile)) | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2021-10-31 02:08:39 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:58:41 +01:00
										 |  |  |             if (id === "selected_element") { | 
					
						
							|  |  |  |                 handlePriviligedFeatureSource(state.selectedElementsLayer) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |             if (id === "gps_location") { | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |                 handlePriviligedFeatureSource(state.currentUserLocation) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             if (id === "gps_location_history") { | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |                 handlePriviligedFeatureSource(state.historicalUserLocations) | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             if (id === "gps_track") { | 
					
						
							|  |  |  |                 handlePriviligedFeatureSource(state.historicalUserLocationsTrack) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |             if (id === "home_location") { | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |                 handlePriviligedFeatureSource(state.homeLocation) | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (id === "current_view") { | 
					
						
							|  |  |  |                 handlePriviligedFeatureSource(state.currentView) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const localTileSaver = new SaveTileToLocalStorageActor(filteredLayer) | 
					
						
							| 
									
										
										
										
											2021-11-16 02:57:26 +01:00
										 |  |  |             this.localStorageSavers.set(filteredLayer.layerDef.id, localTileSaver) | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             if (source.geojsonSource === undefined) { | 
					
						
							|  |  |  |                 // This is an OSM layer
 | 
					
						
							|  |  |  |                 // We load the cached values and register them
 | 
					
						
							|  |  |  |                 // Getting data from upstream happens a bit lower
 | 
					
						
							| 
									
										
										
										
											2021-11-16 02:57:26 +01:00
										 |  |  |                 localTileSaver.LoadTilesFromDisk( | 
					
						
							| 
									
										
										
										
											2021-11-21 02:44:35 +01:00
										 |  |  |                     state.currentBounds, | 
					
						
							|  |  |  |                     state.locationControl, | 
					
						
							| 
									
										
										
										
											2021-11-16 02:57:26 +01:00
										 |  |  |                     (tileIndex, freshness) => | 
					
						
							|  |  |  |                         self.freshnesses.get(id).addTileLoad(tileIndex, freshness), | 
					
						
							|  |  |  |                     (tile) => { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                         console.debug("Loaded tile ", id, tile.tileIndex, "from local cache") | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |                         new RegisteringAllFromFeatureSourceActor(tile, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-11-16 02:57:26 +01:00
										 |  |  |                         hierarchy.registerTile(tile) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                         tile.features.addCallbackAndRunD((_) => self.onNewDataLoaded(tile)) | 
					
						
							| 
									
										
										
										
											2021-11-16 02:57:26 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (source.geojsonZoomLevel === undefined) { | 
					
						
							|  |  |  |                 // This is a 'load everything at once' geojson layer
 | 
					
						
							|  |  |  |                 const src = new GeoJsonSource(filteredLayer) | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if (source.isOsmCacheLayer) { | 
					
						
							|  |  |  |                     // We split them up into tiles anyway as it is an OSM source
 | 
					
						
							|  |  |  |                     TiledFeatureSource.createHierarchy(src, { | 
					
						
							|  |  |  |                         layer: src.layer, | 
					
						
							| 
									
										
										
										
											2021-10-11 21:23:14 +02:00
										 |  |  |                         minZoomLevel: this.osmSourceZoomLevel, | 
					
						
							| 
									
										
										
										
											2022-02-11 03:57:39 +01:00
										 |  |  |                         noDuplicates: true, | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  |                         registerTile: (tile) => { | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |                             new RegisteringAllFromFeatureSourceActor(tile, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  |                             perLayerHierarchy.get(id).registerTile(tile) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                             tile.features.addCallbackAndRunD((_) => self.onNewDataLoaded(tile)) | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  |                         }, | 
					
						
							|  |  |  |                     }) | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |                     new RegisteringAllFromFeatureSourceActor(src, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  |                     perLayerHierarchy.get(id).registerTile(src) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                     src.features.addCallbackAndRunD((_) => self.onNewDataLoaded(src)) | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 new DynamicGeoJsonTileSource( | 
					
						
							|  |  |  |                     filteredLayer, | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |                     (tile) => { | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |                         new RegisteringAllFromFeatureSourceActor(tile, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                         perLayerHierarchy.get(id).registerTile(tile) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                         tile.features.addCallbackAndRunD((_) => self.onNewDataLoaded(tile)) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |                     state | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 16:55:05 +02:00
										 |  |  |         const osmFeatureSource = new OsmFeatureSource({ | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |             isActive: useOsmApi, | 
					
						
							|  |  |  |             neededTiles: neededTilesFromOsm, | 
					
						
							|  |  |  |             handleTile: (tile) => { | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |                 new RegisteringAllFromFeatureSourceActor(tile, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |                 if (tile.layer.layerDef.maxAgeOfCache > 0) { | 
					
						
							| 
									
										
										
										
											2021-11-22 00:50:29 +01:00
										 |  |  |                     const saver = self.localStorageSavers.get(tile.layer.layerDef.id) | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |                     if (saver === undefined) { | 
					
						
							|  |  |  |                         console.error( | 
					
						
							|  |  |  |                             "No localStorageSaver found for layer ", | 
					
						
							|  |  |  |                             tile.layer.layerDef.id | 
					
						
							|  |  |  |                         ) | 
					
						
							| 
									
										
										
										
											2021-11-22 00:50:29 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     saver?.addTile(tile) | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 perLayerHierarchy.get(tile.layer.layerDef.id).registerTile(tile) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                 tile.features.addCallbackAndRunD((_) => self.onNewDataLoaded(tile)) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             state: state, | 
					
						
							|  |  |  |             markTileVisited: (tileId) => | 
					
						
							|  |  |  |                 state.filteredLayers.data.forEach((flayer) => { | 
					
						
							| 
									
										
										
										
											2021-11-15 11:51:32 +01:00
										 |  |  |                     const layer = flayer.layerDef | 
					
						
							|  |  |  |                     if (layer.maxAgeOfCache > 0) { | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |                         const saver = self.localStorageSavers.get(layer.id) | 
					
						
							|  |  |  |                         if (saver === undefined) { | 
					
						
							|  |  |  |                             console.error("No local storage saver found for ", layer.id) | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                             saver.MarkVisited(tileId, new Date()) | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2021-10-27 03:52:19 +02:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-11-15 11:51:32 +01:00
										 |  |  |                     self.freshnesses.get(layer.id).addTileLoad(tileId, new Date()) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 }), | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         if (this.fullNodeDatabase !== undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-23 03:36:03 +01:00
										 |  |  |             osmFeatureSource.rawDataHandlers.push((osmJson, tileId) => | 
					
						
							|  |  |  |                 this.fullNodeDatabase.handleOsmJson(osmJson, tileId) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2021-10-31 02:08:39 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         const updater = this.initOverpassUpdater(state, useOsmApi) | 
					
						
							|  |  |  |         this.overpassUpdater = updater | 
					
						
							|  |  |  |         this.timeout = updater.timeout | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |         // Actually load data from the overpass source
 | 
					
						
							|  |  |  |         new PerLayerFeatureSourceSplitter( | 
					
						
							|  |  |  |             state.filteredLayers, | 
					
						
							|  |  |  |             (source) => | 
					
						
							|  |  |  |                 TiledFeatureSource.createHierarchy(source, { | 
					
						
							|  |  |  |                     layer: source.layer, | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                     minZoomLevel: source.layer.layerDef.minzoom, | 
					
						
							| 
									
										
										
										
											2022-02-11 03:57:39 +01:00
										 |  |  |                     noDuplicates: true, | 
					
						
							| 
									
										
										
										
											2021-09-28 18:00:44 +02:00
										 |  |  |                     maxFeatureCount: state.layoutToUse.clustering.minNeededElements, | 
					
						
							|  |  |  |                     maxZoomLevel: state.layoutToUse.clustering.maxZoom, | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |                     registerTile: (tile) => { | 
					
						
							| 
									
										
										
										
											2021-11-15 11:51:32 +01:00
										 |  |  |                         // We save the tile data for the given layer to local storage - data sourced from overpass
 | 
					
						
							| 
									
										
										
										
											2021-11-22 03:49:17 +01:00
										 |  |  |                         self.localStorageSavers.get(tile.layer.layerDef.id)?.addTile(tile) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                         perLayerHierarchy | 
					
						
							|  |  |  |                             .get(source.layer.layerDef.id) | 
					
						
							|  |  |  |                             .registerTile(new RememberingSource(tile)) | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                         tile.features.addCallbackAndRunD((f) => { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |                             if (f.length === 0) { | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |                                 return | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             self.onNewDataLoaded(tile) | 
					
						
							|  |  |  |                         }) | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |                 }), | 
					
						
							| 
									
										
										
										
											2022-01-17 23:50:50 +01:00
										 |  |  |             updater, | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             { | 
					
						
							|  |  |  |                 handleLeftovers: (leftOvers) => { | 
					
						
							|  |  |  |                     console.warn("Overpass returned a few non-matched features:", leftOvers) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Also load points/lines that are newly added.
 | 
					
						
							| 
									
										
										
										
											2022-01-21 03:57:49 +01:00
										 |  |  |         const newGeometry = new NewGeometryFromChangesFeatureSource( | 
					
						
							|  |  |  |             state.changes, | 
					
						
							|  |  |  |             state.allElements, | 
					
						
							|  |  |  |             state.osmConnection._oauth_config.url | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2022-02-04 00:44:51 +01:00
										 |  |  |         this.newGeometryHandler = newGeometry | 
					
						
							| 
									
										
										
										
											2021-12-14 17:29:21 +01:00
										 |  |  |         newGeometry.features.addCallbackAndRun((geometries) => { | 
					
						
							|  |  |  |             console.debug("New geometries are:", geometries) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |         new RegisteringAllFromFeatureSourceActor(newGeometry, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |         // A NewGeometryFromChangesFeatureSource does not split per layer, so we do this next
 | 
					
						
							|  |  |  |         new PerLayerFeatureSourceSplitter( | 
					
						
							|  |  |  |             state.filteredLayers, | 
					
						
							|  |  |  |             (perLayer) => { | 
					
						
							|  |  |  |                 // We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this
 | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |                 // AT last, we always apply the metatags whenever possible
 | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |                 perLayer.features.addCallbackAndRunD((_) => { | 
					
						
							| 
									
										
										
										
											2022-01-21 03:57:49 +01:00
										 |  |  |                     self.onNewDataLoaded(perLayer) | 
					
						
							|  |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2022-01-17 23:50:50 +01:00
										 |  |  |             newGeometry, | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             { | 
					
						
							|  |  |  |                 handleLeftovers: (leftOvers) => { | 
					
						
							|  |  |  |                     console.warn("Got some leftovers from the filteredLayers: ", leftOvers) | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |         this.runningQuery = updater.runningQuery.map( | 
					
						
							| 
									
										
										
										
											2021-10-08 15:11:20 +02:00
										 |  |  |             (overpass) => { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 console.log( | 
					
						
							|  |  |  |                     "FeaturePipeline: runningQuery state changed: Overpass", | 
					
						
							|  |  |  |                     overpass ? "is querying," : "is idle,", | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |                     "osmFeatureSource is", | 
					
						
							|  |  |  |                     osmFeatureSource.isRunning | 
					
						
							|  |  |  |                         ? "is running and needs " + | 
					
						
							|  |  |  |                               neededTilesFromOsm.data?.length + | 
					
						
							|  |  |  |                               " tiles (already got " + | 
					
						
							|  |  |  |                               osmFeatureSource.downloadedTiles.size + | 
					
						
							|  |  |  |                               " tiles )" | 
					
						
							|  |  |  |                         : "is idle" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-10-08 15:11:20 +02:00
										 |  |  |                 return overpass || osmFeatureSource.isRunning.data | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             [osmFeatureSource.isRunning] | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  |     public GetAllFeaturesWithin(bbox: BBox): OsmFeature[][] { | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         const self = this | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  |         const tiles: OsmFeature[][] = [] | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         Array.from(this.perLayerHierarchy.keys()).forEach((key) => { | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  |             const fetched: OsmFeature[][] = self.GetFeaturesWithin(key, bbox) | 
					
						
							|  |  |  |             tiles.push(...fetched) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         return tiles | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  |     public GetAllFeaturesAndMetaWithin( | 
					
						
							|  |  |  |         bbox: BBox, | 
					
						
							|  |  |  |         layerIdWhitelist?: Set<string> | 
					
						
							|  |  |  |     ): { features: OsmFeature[]; layer: string }[] { | 
					
						
							| 
									
										
										
										
											2022-02-16 01:34:28 +01:00
										 |  |  |         const self = this | 
					
						
							|  |  |  |         const tiles: { features: any[]; layer: string }[] = [] | 
					
						
							|  |  |  |         Array.from(this.perLayerHierarchy.keys()).forEach((key) => { | 
					
						
							|  |  |  |             if (layerIdWhitelist !== undefined && !layerIdWhitelist.has(key)) { | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return tiles.push({ | 
					
						
							|  |  |  |                 layer: key, | 
					
						
							|  |  |  |                 features: [].concat(...self.GetFeaturesWithin(key, bbox)), | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-02-16 01:34:28 +01:00
										 |  |  |         return tiles | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-13 17:56:10 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Gets all the tiles which overlap with the given BBOX. | 
					
						
							|  |  |  |      * This might imply that extra features might be shown | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public GetFeaturesWithin(layerId: string, bbox: BBox): OsmFeature[][] { | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (layerId === "*") { | 
					
						
							|  |  |  |             return this.GetAllFeaturesWithin(bbox) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const requestedHierarchy = this.perLayerHierarchy.get(layerId) | 
					
						
							|  |  |  |         if (requestedHierarchy === undefined) { | 
					
						
							|  |  |  |             console.warn( | 
					
						
							|  |  |  |                 "Layer ", | 
					
						
							|  |  |  |                 layerId, | 
					
						
							|  |  |  |                 "is not defined. Try one of ", | 
					
						
							|  |  |  |                 Array.from(this.perLayerHierarchy.keys()) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return TileHierarchyTools.getTiles(requestedHierarchy, bbox) | 
					
						
							|  |  |  |             .filter((featureSource) => featureSource.features?.data !== undefined) | 
					
						
							|  |  |  |             .map((featureSource) => featureSource.features.data.map((fs) => fs.feature)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public GetTilesPerLayerWithin( | 
					
						
							|  |  |  |         bbox: BBox, | 
					
						
							|  |  |  |         handleTile: (tile: FeatureSourceForLayer & Tiled) => void | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         Array.from(this.perLayerHierarchy.values()).forEach((hierarchy) => { | 
					
						
							|  |  |  |             TileHierarchyTools.getTiles(hierarchy, bbox).forEach(handleTile) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |     private onNewDataLoaded(src: FeatureSource) { | 
					
						
							|  |  |  |         this.newDataLoadedSignal.setData(src) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |     private freshnessForVisibleLayers(z: number, x: number, y: number): Date { | 
					
						
							|  |  |  |         let oldestDate = undefined | 
					
						
							|  |  |  |         for (const flayer of this.state.filteredLayers.data) { | 
					
						
							| 
									
										
										
										
											2022-02-07 01:59:07 +01:00
										 |  |  |             if (!flayer.isDisplayed.data && !flayer.layerDef.forceLoad) { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (this.state.locationControl.data.zoom < flayer.layerDef.minzoom) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (flayer.layerDef.maxAgeOfCache === 0) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 return undefined | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const freshnessCalc = this.freshnesses.get(flayer.layerDef.id) | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (freshnessCalc === undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 console.warn("No freshness tracker found for ", flayer.layerDef.id) | 
					
						
							|  |  |  |                 return undefined | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const freshness = freshnessCalc.freshnessFor(z, x, y) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             if (freshness === undefined) { | 
					
						
							|  |  |  |                 // SOmething is undefined --> we return undefined as we have to download
 | 
					
						
							|  |  |  |                 return undefined | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (oldestDate === undefined || oldestDate > freshness) { | 
					
						
							|  |  |  |                 oldestDate = freshness | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return oldestDate | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-07 01:59:07 +01:00
										 |  |  |     /* | 
					
						
							|  |  |  |      * Gives an UIEventSource containing the tileIndexes of the tiles that should be loaded from OSM | 
					
						
							|  |  |  |      * */ | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     private getNeededTilesFromOsm(isSufficientlyZoomed: Store<boolean>): Store<number[]> { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         const self = this | 
					
						
							|  |  |  |         return this.state.currentBounds.map( | 
					
						
							|  |  |  |             (bbox) => { | 
					
						
							|  |  |  |                 if (bbox === undefined) { | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                     return [] | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-10-01 01:34:59 +02:00
										 |  |  |                 if (!isSufficientlyZoomed.data) { | 
					
						
							| 
									
										
										
										
											2021-10-15 18:48:33 +02:00
										 |  |  |                     return [] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 const osmSourceZoomLevel = self.osmSourceZoomLevel | 
					
						
							|  |  |  |                 const range = bbox.containingTileRange(osmSourceZoomLevel) | 
					
						
							|  |  |  |                 const tileIndexes = [] | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                 if (range.total >= 100) { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                     // Too much tiles!
 | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |                     return undefined | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 Tiles.MapRange(range, (x, y) => { | 
					
						
							|  |  |  |                     const i = Tiles.tile_index(osmSourceZoomLevel, x, y) | 
					
						
							|  |  |  |                     const oldestDate = self.freshnessForVisibleLayers(osmSourceZoomLevel, x, y) | 
					
						
							|  |  |  |                     if (oldestDate !== undefined && oldestDate > this.oldestAllowedDate) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                         console.debug( | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                             "Skipping tile", | 
					
						
							|  |  |  |                             osmSourceZoomLevel, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                             x, | 
					
						
							|  |  |  |                             y, | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                             "as a decently fresh one is available" | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         ) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                         // The cached tiles contain decently fresh data
 | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |                         return undefined | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                     tileIndexes.push(i) | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |                 return tileIndexes | 
					
						
							| 
									
										
										
										
											2021-10-15 18:48:33 +02:00
										 |  |  |             }, | 
					
						
							|  |  |  |             [isSufficientlyZoomed] | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private initOverpassUpdater( | 
					
						
							|  |  |  |         state: { | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |             allElements: ElementStorage | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             layoutToUse: LayoutConfig | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |             currentBounds: Store<BBox> | 
					
						
							|  |  |  |             locationControl: Store<Loc> | 
					
						
							|  |  |  |             readonly overpassUrl: Store<string[]> | 
					
						
							|  |  |  |             readonly overpassTimeout: Store<number> | 
					
						
							|  |  |  |             readonly overpassMaxZoom: Store<number> | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         useOsmApi: Store<boolean> | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |     ): OverpassFeatureSource { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         const minzoom = Math.min(...state.layoutToUse.layers.map((layer) => layer.minzoom)) | 
					
						
							|  |  |  |         const overpassIsActive = state.currentBounds.map( | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |             (bbox) => { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 if (bbox === undefined) { | 
					
						
							|  |  |  |                     console.debug("Disabling overpass source: no bbox") | 
					
						
							|  |  |  |                     return false | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                 let zoom = state.locationControl.data.zoom | 
					
						
							|  |  |  |                 if (zoom < minzoom) { | 
					
						
							|  |  |  |                     // We are zoomed out over the zoomlevel of any layer
 | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |                     console.debug("Disabling overpass source: zoom < minzoom") | 
					
						
							| 
									
										
										
										
											2021-11-22 03:49:17 +01:00
										 |  |  |                     return false | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const range = bbox.containingTileRange(zoom) | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                 if (range.total >= 5000) { | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |                     // Let's assume we don't have so much data cached
 | 
					
						
							|  |  |  |                     return true | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                 const self = this | 
					
						
							|  |  |  |                 const allFreshnesses = Tiles.MapRange(range, (x, y) => | 
					
						
							|  |  |  |                     self.freshnessForVisibleLayers(zoom, x, y) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |                 return allFreshnesses.some( | 
					
						
							|  |  |  |                     (freshness) => freshness === undefined || freshness < this.oldestAllowedDate | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             }, | 
					
						
							|  |  |  |             [state.locationControl] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const self = this | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         const updater = new OverpassFeatureSource(state, { | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |             padToTiles: state.locationControl.map((l) => Math.min(15, l.zoom + 1)), | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             relationTracker: this.relationTracker, | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |             isActive: useOsmApi.map((b) => !b && overpassIsActive.data, [overpassIsActive]), | 
					
						
							| 
									
										
										
										
											2022-01-15 02:44:11 +01:00
										 |  |  |             freshnesses: this.freshnesses, | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |             onBboxLoaded: (bbox, date, downloadedLayers, paddedToZoomLevel) => { | 
					
						
							|  |  |  |                 Tiles.MapRange(bbox.containingTileRange(paddedToZoomLevel), (x, y) => { | 
					
						
							| 
									
										
										
										
											2021-10-25 20:38:57 +02:00
										 |  |  |                     const tileIndex = Tiles.tile_index(paddedToZoomLevel, x, y) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                     downloadedLayers.forEach((layer) => { | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                         self.freshnesses.get(layer.id).addTileLoad(tileIndex, date) | 
					
						
							| 
									
										
										
										
											2021-11-22 03:49:17 +01:00
										 |  |  |                         self.localStorageSavers.get(layer.id)?.MarkVisited(tileIndex, date) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     }) | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Register everything in the state' 'AllElements'
 | 
					
						
							| 
									
										
										
										
											2021-12-05 05:20:33 +01:00
										 |  |  |         new RegisteringAllFromFeatureSourceActor(updater, state.allElements) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         return updater | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-25 18:55:15 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Builds upon 'GetAllFeaturesAndMetaWithin', but does stricter BBOX-checking and applies the filters | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public getAllVisibleElementsWithmeta( | 
					
						
							|  |  |  |         bbox: BBox | 
					
						
							|  |  |  |     ): { center: [number, number]; element: OsmFeature; layer: LayerConfig }[] { | 
					
						
							|  |  |  |         if (bbox === undefined) { | 
					
						
							|  |  |  |             console.warn("No bbox") | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const layers = Utils.toIdRecord(this.state.layoutToUse.layers) | 
					
						
							|  |  |  |         const elementsWithMeta: { features: OsmFeature[]; layer: string }[] = | 
					
						
							|  |  |  |             this.GetAllFeaturesAndMetaWithin(bbox) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let elements: { center: [number, number]; element: OsmFeature; layer: LayerConfig }[] = [] | 
					
						
							|  |  |  |         let seenElements = new Set<string>() | 
					
						
							|  |  |  |         for (const elementsWithMetaElement of elementsWithMeta) { | 
					
						
							|  |  |  |             const layer = layers[elementsWithMetaElement.layer] | 
					
						
							|  |  |  |             if (layer.title === undefined) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const filtered = this.state.filteredLayers.data.find((fl) => fl.layerDef == layer) | 
					
						
							|  |  |  |             for (let i = 0; i < elementsWithMetaElement.features.length; i++) { | 
					
						
							|  |  |  |                 const element = elementsWithMetaElement.features[i] | 
					
						
							|  |  |  |                 if (!filtered.isDisplayed.data) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (seenElements.has(element.properties.id)) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 seenElements.add(element.properties.id) | 
					
						
							|  |  |  |                 if (!bbox.overlapsWith(BBox.get(element))) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (layer?.isShown !== undefined && !layer.isShown.matchesProperties(element)) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const activeFilters: FilterState[] = Array.from( | 
					
						
							|  |  |  |                     filtered.appliedFilters.data.values() | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2022-07-25 18:55:15 +02:00
										 |  |  |                 if ( | 
					
						
							|  |  |  |                     !activeFilters.every( | 
					
						
							|  |  |  |                         (filter) => | 
					
						
							|  |  |  |                             filter?.currentFilter === undefined || | 
					
						
							|  |  |  |                             filter?.currentFilter?.matchesProperties(element.properties) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2022-07-25 18:55:15 +02:00
										 |  |  |                 ) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const center = GeoOperations.centerpointCoordinates(element) | 
					
						
							|  |  |  |                 elements.push({ | 
					
						
							|  |  |  |                     element, | 
					
						
							|  |  |  |                     center, | 
					
						
							|  |  |  |                     layer: layers[elementsWithMetaElement.layer], | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return elements | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 00:44:51 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Inject a new point | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     InjectNewPoint(geojson) { | 
					
						
							|  |  |  |         this.newGeometryHandler.features.data.push({ | 
					
						
							|  |  |  |             feature: geojson, | 
					
						
							|  |  |  |             freshness: new Date(), | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         this.newGeometryHandler.features.ping() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  | } |