| 
									
										
										
										
											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"; | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  | import {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"; | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public readonly sufficientlyZoomed: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly runningQuery: UIEventSource<boolean>; | 
					
						
							|  |  |  |     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-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) ?? []) | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							|  |  |  |         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"])) | 
					
						
							| 
									
										
										
										
											2021-10-25 21:08:44 +02:00
										 |  |  |                 }) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-09-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 16:55:05 +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-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-28 17:30:48 +02: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)) | 
					
						
							|  |  |  |             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; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-28 17:30:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							| 
									
										
										
										
											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-26 17:36:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											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-01-21 03:57:49 +01:00
										 |  |  |                 perLayer.features.addCallbackAndRunD(feats => { | 
					
						
							|  |  |  |                     self.onNewDataLoaded(perLayer); | 
					
						
							|  |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     public GetAllFeaturesWithin(bbox: BBox): any[][] { | 
					
						
							|  |  |  |         const self = this | 
					
						
							|  |  |  |         const tiles = [] | 
					
						
							|  |  |  |         Array.from(this.perLayerHierarchy.keys()) | 
					
						
							|  |  |  |             .forEach(key => tiles.push(...self.GetFeaturesWithin(key, bbox))) | 
					
						
							|  |  |  |         return tiles; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 01:34:28 +01:00
										 |  |  |     public GetAllFeaturesAndMetaWithin(bbox: BBox, layerIdWhitelist?: Set<string>): {features: any[], layer: string}[] { | 
					
						
							|  |  |  |         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)) | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         return tiles; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] { | 
					
						
							|  |  |  |         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())) | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  |     * */ | 
					
						
							| 
									
										
										
										
											2021-10-01 01:34:59 +02:00
										 |  |  |     private getNeededTilesFromOsm(isSufficientlyZoomed: UIEventSource<boolean>): UIEventSource<number[]> { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         const self = this | 
					
						
							|  |  |  |         return this.state.currentBounds.map(bbox => { | 
					
						
							|  |  |  |             if (bbox === undefined) { | 
					
						
							| 
									
										
										
										
											2021-10-15 18:48:33 +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 []; | 
					
						
							| 
									
										
										
										
											2021-10-01 01:34:59 +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-15 18:48:33 +02:00
										 |  |  |                 return undefined | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  |                     console.debug("Skipping tile", osmSourceZoomLevel, x, y, "as a decently fresh one is available") | 
					
						
							|  |  |  |                     // The cached tiles contain decently fresh data
 | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +02:00
										 |  |  |                     return undefined; | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  |         currentBounds: UIEventSource<BBox>, | 
					
						
							|  |  |  |         locationControl: UIEventSource<Loc>, | 
					
						
							|  |  |  |         readonly overpassUrl: UIEventSource<string[]>; | 
					
						
							|  |  |  |         readonly overpassTimeout: UIEventSource<number>; | 
					
						
							|  |  |  |         readonly overpassMaxZoom: UIEventSource<number>, | 
					
						
							|  |  |  |     }, useOsmApi: UIEventSource<boolean>): OverpassFeatureSource { | 
					
						
							|  |  |  |         const minzoom = Math.min(...state.layoutToUse.layers.map(layer => layer.minzoom)) | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |         const overpassIsActive = state.currentBounds.map(bbox => { | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             if (bbox === undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 console.debug("Disabling overpass source: no bbox") | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |                 return false | 
					
						
							| 
									
										
										
										
											2021-10-01 01:34:59 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             let zoom = state.locationControl.data.zoom | 
					
						
							|  |  |  |             if (zoom < minzoom) { | 
					
						
							| 
									
										
										
										
											2021-10-18 18:54:36 +02:00
										 |  |  |                 // We are zoomed out over the zoomlevel of any layer
 | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 console.debug("Disabling overpass source: zoom < minzoom") | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |                 return false; | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-10-02 15:16:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-01 04:49:40 +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)) | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |             return allFreshnesses.some(freshness => freshness === undefined || freshness < this.oldestAllowedDate) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |         }, [state.locationControl]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const self = this; | 
					
						
							|  |  |  |         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) | 
					
						
							| 
									
										
										
										
											2021-09-30 04:13:23 +02:00
										 |  |  |                         }) | 
					
						
							|  |  |  |                     }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-11 22:30:22 +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-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
										 |  |  | } |