| 
									
										
										
										
											2021-01-03 03:09:52 +01:00
										 |  |  | import {UIEventSource} from "../UIEventSource"; | 
					
						
							|  |  |  | import Loc from "../../Models/Loc"; | 
					
						
							|  |  |  | import {Or, TagsFilter} from "../Tags"; | 
					
						
							|  |  |  | import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; | 
					
						
							|  |  |  | import {Overpass} from "../Osm/Overpass"; | 
					
						
							|  |  |  | import Bounds from "../../Models/Bounds"; | 
					
						
							|  |  |  | import FeatureSource from "../FeatureSource/FeatureSource"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  | export default class UpdateFromOverpass implements FeatureSource{ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The last loaded features of the geojson | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-01-03 03:09:52 +01:00
										 |  |  |     public readonly features: UIEventSource<{feature:any, freshness: Date}[]> = new UIEventSource<any[]>(undefined); | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-02 16:04:16 +01:00
										 |  |  |     public readonly sufficientlyZoomed: UIEventSource<boolean>; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     public readonly runningQuery: UIEventSource<boolean> = new UIEventSource<boolean>(false); | 
					
						
							| 
									
										
										
										
											2020-07-30 11:30:04 +02:00
										 |  |  |     public readonly retries: UIEventSource<number> = new UIEventSource<number>(0); | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-08-27 18:44:16 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |      * The previous bounds for which the query has been run at the given zoom level | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Note that some layers only activate on a certain zoom level. | 
					
						
							|  |  |  |      * If the map location changes, we check for each layer if it is loaded: | 
					
						
							|  |  |  |      * we start checking the bounds at the first zoom level the layer might operate. If in bounds - no reload needed, otherwise we continue walking down | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |     private readonly _previousBounds: Map<number, Bounds[]> = new Map<number, Bounds[]>(); | 
					
						
							|  |  |  |     private readonly _location: UIEventSource<Loc>; | 
					
						
							|  |  |  |     private readonly _layoutToUse: UIEventSource<LayoutConfig>; | 
					
						
							|  |  |  |     private readonly _leafletMap: UIEventSource<L.Map>; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The most important layer should go first, as that one gets first pick for the questions | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |     constructor( | 
					
						
							|  |  |  |         location: UIEventSource<Loc>, | 
					
						
							|  |  |  |         layoutToUse: UIEventSource<LayoutConfig>, | 
					
						
							|  |  |  |         leafletMap: UIEventSource<L.Map>) { | 
					
						
							|  |  |  |         this._location = location; | 
					
						
							|  |  |  |         this._layoutToUse = layoutToUse; | 
					
						
							|  |  |  |         this._leafletMap = leafletMap; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         this.sufficientlyZoomed = location.map(location => { | 
					
						
							| 
									
										
										
										
											2020-09-18 00:31:54 +02:00
										 |  |  |                 if(location?.zoom === undefined){ | 
					
						
							|  |  |  |                     return false; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |                 let minzoom = Math.min(...layoutToUse.data.layers.map(layer => layer.minzoom ?? 18)); | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |                 return location.zoom >= minzoom; | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |             }, [layoutToUse] | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         for (let i = 0; i < 25; i++) { | 
					
						
							|  |  |  |             // This update removes all data on all layers -> erase the map on lower levels too
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |             this._previousBounds.set(i, []); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         | 
					
						
							|  |  |  |         layoutToUse.addCallback(() => { | 
					
						
							|  |  |  |             self.update() | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         location.addCallbackAndRun(() => { | 
					
						
							|  |  |  |             self.update() | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-01-02 16:04:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public ForceRefresh() { | 
					
						
							|  |  |  |         for (let i = 0; i < 25; i++) { | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |             this._previousBounds.set(i, []); | 
					
						
							| 
									
										
										
										
											2021-01-02 16:04:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         this.update(); | 
					
						
							| 
									
										
										
										
											2021-01-02 16:04:16 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |     private GetFilter() { | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         const filters: TagsFilter[] = []; | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         for (const layer of this._layoutToUse.data.layers) { | 
					
						
							| 
									
										
										
										
											2020-09-02 11:37:34 +02:00
										 |  |  |             if(typeof(layer) === "string"){ | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |             if (this._location.data.zoom < layer.minzoom) { | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |             if(layer.doNotDownload){ | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                  | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |             // Check if data for this layer has already been loaded
 | 
					
						
							|  |  |  |             let previouslyLoaded = false; | 
					
						
							|  |  |  |             for (let z = layer.minzoom; z < 25 && !previouslyLoaded; z++) { | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |                 const previousLoadedBounds = this._previousBounds.get(z); | 
					
						
							| 
									
										
										
										
											2020-08-31 02:59:47 +02:00
										 |  |  |                 if (previousLoadedBounds === undefined) { | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 for (const previousLoadedBound of previousLoadedBounds) { | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |                     previouslyLoaded = previouslyLoaded || this.IsInBounds(previousLoadedBound); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |                     if(previouslyLoaded){ | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (previouslyLoaded) { | 
					
						
							| 
									
										
										
										
											2020-08-26 20:11:43 +02:00
										 |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-10-27 01:01:34 +01:00
										 |  |  |             filters.push(layer.overpassTags); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (filters.length === 0) { | 
					
						
							|  |  |  |             return undefined; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return new Or(filters); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |     private update(): void { | 
					
						
							|  |  |  |         const filter = this.GetFilter(); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         if (filter === undefined) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this.runningQuery.data) { | 
					
						
							|  |  |  |             console.log("Still running a query, skip"); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         const bounds = this._leafletMap.data.getBounds(); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         const diff = this._layoutToUse.data.widenFactor; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 20:11:43 +02:00
										 |  |  |         const n = Math.min(90, bounds.getNorth() + diff); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         const e = Math.min(180, bounds.getEast() + diff); | 
					
						
							| 
									
										
										
										
											2020-08-26 20:11:43 +02:00
										 |  |  |         const s = Math.max(-90, bounds.getSouth() - diff); | 
					
						
							|  |  |  |         const w = Math.max(-180, bounds.getWest() - diff); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         const queryBounds = {north: n, east: e, south: s, west: w}; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 00:29:07 +01:00
										 |  |  |         const z = Math.floor(this._location.data.zoom ?? 0); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this.runningQuery.setData(true); | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         const overpass = new Overpass(filter); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |         overpass.queryGeoJson(queryBounds, | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |             function (data, date) { | 
					
						
							|  |  |  |                 self._previousBounds.get(z).push(queryBounds); | 
					
						
							|  |  |  |                 self.retries.setData(0); | 
					
						
							| 
									
										
										
										
											2021-01-03 03:09:52 +01:00
										 |  |  |                 self.features.setData(data.features.map(f => ({feature: f, freshness: date}))); | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |                 self.runningQuery.setData(false); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             }, | 
					
						
							|  |  |  |             function (reason) { | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |                 self.retries.data++; | 
					
						
							|  |  |  |                 self.ForceRefresh(); | 
					
						
							|  |  |  |                 console.log(`QUERY FAILED (retrying in ${5 * self.retries.data} sec)`, undefined); | 
					
						
							|  |  |  |                 self.retries.ping(); | 
					
						
							|  |  |  |                 self.runningQuery.setData(false) | 
					
						
							|  |  |  |                 window?.setTimeout( | 
					
						
							|  |  |  |                     function () { | 
					
						
							|  |  |  |                         self.update() | 
					
						
							|  |  |  |                     }, self.retries.data * 5000 | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-10-12 01:47:46 +02:00
										 |  |  |          | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |     private IsInBounds(bounds: Bounds): boolean { | 
					
						
							|  |  |  |         if (this._previousBounds === undefined) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 00:19:42 +01:00
										 |  |  |         const b = this._leafletMap.data.getBounds(); | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         return b.getSouth() >= bounds.south && | 
					
						
							|  |  |  |             b.getNorth() <= bounds.north && | 
					
						
							|  |  |  |             b.getEast() <= bounds.east && | 
					
						
							|  |  |  |             b.getWest() >= bounds.west; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2021-01-02 16:04:16 +01:00
										 |  |  |      | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | } |