| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | import {Or, TagsFilter} from "./TagsFilter"; | 
					
						
							| 
									
										
										
										
											2020-08-17 17:23:15 +02:00
										 |  |  | import {UIEventSource} from "./UIEventSource"; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | import {FilteredLayer} from "./FilteredLayer"; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | import {Bounds} from "./Bounds"; | 
					
						
							|  |  |  | import {Overpass} from "./Osm/Overpass"; | 
					
						
							|  |  |  | import {Basemap} from "./Leaflet/Basemap"; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | import {State} from "../State"; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class LayerUpdater { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     public readonly sufficentlyZoomed: UIEventSource<boolean> = new UIEventSource<boolean>(false); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  |      /** | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |      * The previous bounds for which the query has been run | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  |     private previousBounds: Bounds; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The most important layer should go first, as that one gets first pick for the questions | 
					
						
							|  |  |  |      * @param map | 
					
						
							|  |  |  |      * @param minzoom | 
					
						
							|  |  |  |      * @param layers | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     constructor(state: State) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         state.locationControl.addCallback(() => { | 
					
						
							|  |  |  |             self.update(state) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         state.layoutToUse.addCallback(() => { | 
					
						
							|  |  |  |             self.update(state) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         | 
					
						
							|  |  |  |         self.update(state); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     private GetFilter(state: State) { | 
					
						
							|  |  |  |         var filters: TagsFilter[] = []; | 
					
						
							|  |  |  |         state = state ?? State.state; | 
					
						
							|  |  |  |         for (const layer of state.layoutToUse.data.layers) { | 
					
						
							|  |  |  |             if (state.locationControl.data.zoom < layer.minzoom) { | 
					
						
							|  |  |  |                 return undefined; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             filters.push(layer.overpassFilter); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (filters.length === 0) { | 
					
						
							|  |  |  |             return undefined; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return new Or(filters); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private handleData(geojson: any) { | 
					
						
							| 
									
										
										
										
											2020-07-27 00:14:34 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.retries.setData(0); | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2020-07-27 00:14:34 +02:00
										 |  |  |         function renderLayers(layers: FilteredLayer[]) { | 
					
						
							|  |  |  |             if (layers.length === 0) { | 
					
						
							|  |  |  |                 self.runningQuery.setData(false); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-27 00:14:34 +02:00
										 |  |  |                 if (geojson.features.length > 0) { | 
					
						
							|  |  |  |                     console.log("Got some leftovers: ", geojson) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             window.setTimeout(() => { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-27 00:14:34 +02:00
										 |  |  |                 const layer = layers[0]; | 
					
						
							|  |  |  |                 const rest = layers.slice(1, layers.length); | 
					
						
							|  |  |  |                 geojson = layer.SetApplicableData(geojson); | 
					
						
							|  |  |  |                 renderLayers(rest); | 
					
						
							|  |  |  |             }, 50) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         renderLayers(State.state.filteredLayers.data); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     private handleFail(state: State, reason: any) { | 
					
						
							|  |  |  |         this.retries.data++; | 
					
						
							|  |  |  |         this.ForceRefresh(); | 
					
						
							| 
									
										
										
										
											2020-07-30 11:30:04 +02:00
										 |  |  |         console.log(`QUERY FAILED (retrying in ${5 * this.retries.data} sec)`, reason); | 
					
						
							|  |  |  |         this.retries.ping(); | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-07-25 18:00:08 +02:00
										 |  |  |         window?.setTimeout( | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |             function () { | 
					
						
							|  |  |  |                 self.update(state) | 
					
						
							|  |  |  |             }, this.retries.data * 5000 | 
					
						
							| 
									
										
										
										
											2020-06-27 03:06:51 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     private update(state: State): void { | 
					
						
							|  |  |  |         if (this.IsInBounds(state)) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const filter = this.GetFilter(state); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.sufficentlyZoomed.setData(filter !== undefined); | 
					
						
							|  |  |  |         if (filter === undefined) { | 
					
						
							|  |  |  |             console.log("Zoom insufficient to run query") | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         const bounds = state.bm.map.getBounds(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const diff = state.layoutToUse.data.widenFactor; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const n = bounds.getNorth() + diff; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         const e = bounds.getEast() + diff; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  |         const s = bounds.getSouth() - diff; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         const w = bounds.getWest() - diff; | 
					
						
							| 
									
										
										
										
											2020-07-30 00:59:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.previousBounds = {north: n, east: e, south: s, west: w}; | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  |         overpass.queryGeoJson(this.previousBounds, | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             function (data) { | 
					
						
							|  |  |  |                 self.handleData(data) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             function (reason) { | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |                 self.handleFail(state, reason) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |     private IsInBounds(state: State): boolean { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (this.previousBounds === undefined) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         const b = state.bm.map.getBounds(); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         if (b.getSouth() < this.previousBounds.south) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (b.getNorth() > this.previousBounds.north) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (b.getEast() > this.previousBounds.east) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (b.getWest() < this.previousBounds.west) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     public ForceRefresh(){ | 
					
						
							|  |  |  |         this.previousBounds = undefined; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |