| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  | import DynamicTileSource from "./DynamicTileSource" | 
					
						
							|  |  |  | import { Store, UIEventSource } from "../../UIEventSource" | 
					
						
							|  |  |  | import { BBox } from "../../BBox" | 
					
						
							|  |  |  | import StaticFeatureSource from "../Sources/StaticFeatureSource" | 
					
						
							|  |  |  | import { Feature, Point } from "geojson" | 
					
						
							|  |  |  | import { Utils } from "../../../Utils" | 
					
						
							|  |  |  | import { Tiles } from "../../../Models/TileRange" | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  | import { FeatureSource } from "../FeatureSource" | 
					
						
							|  |  |  | import FilteredLayer from "../../../Models/FilteredLayer" | 
					
						
							|  |  |  | import Constants from "../../../Models/Constants" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class SummaryTileSourceRewriter implements FeatureSource { | 
					
						
							|  |  |  |     private readonly _features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([]) | 
					
						
							|  |  |  |     private filteredLayers: FilteredLayer[] | 
					
						
							|  |  |  |     public readonly features: Store<Feature[]> = this._features | 
					
						
							|  |  |  |     private readonly _summarySource: SummaryTileSource | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |     private readonly _totalNumberOfFeatures: UIEventSource<number> = new UIEventSource<number>( | 
					
						
							|  |  |  |         undefined | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     public readonly totalNumberOfFeatures: Store<number> = this._totalNumberOfFeatures | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  |     constructor( | 
					
						
							|  |  |  |         summarySource: SummaryTileSource, | 
					
						
							|  |  |  |         filteredLayers: ReadonlyMap<string, FilteredLayer> | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         this.filteredLayers = Array.from(filteredLayers.values()).filter( | 
					
						
							|  |  |  |             (l) => | 
					
						
							|  |  |  |                 Constants.priviliged_layers.indexOf(<any>l.layerDef.id) < 0 && | 
					
						
							|  |  |  |                 !l.layerDef.id.startsWith("note_import") | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         this._summarySource = summarySource | 
					
						
							|  |  |  |         filteredLayers.forEach((v, k) => { | 
					
						
							|  |  |  |             v.isDisplayed.addCallback((_) => this.update()) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         this._summarySource.features.addCallbackAndRunD((_) => this.update()) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private update() { | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |         let fullTotal = 0 | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  |         const newFeatures: Feature[] = [] | 
					
						
							|  |  |  |         const layersToCount = this.filteredLayers.filter((fl) => fl.isDisplayed.data) | 
					
						
							|  |  |  |         const bitmap = layersToCount.map((l) => (l.isDisplayed.data ? "1" : "0")).join("") | 
					
						
							|  |  |  |         const ids = layersToCount.map((l) => l.layerDef.id) | 
					
						
							|  |  |  |         for (const f of this._summarySource.features.data ?? []) { | 
					
						
							|  |  |  |             let newTotal = 0 | 
					
						
							|  |  |  |             for (const id of ids) { | 
					
						
							|  |  |  |                 newTotal += Number(f.properties[id] ?? 0) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             newFeatures.push({ | 
					
						
							|  |  |  |                 ...f, | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |                 properties: { | 
					
						
							|  |  |  |                     ...f.properties, | 
					
						
							|  |  |  |                     id: f.properties.id + bitmap, | 
					
						
							|  |  |  |                     total: newTotal, | 
					
						
							|  |  |  |                     total_metric: Utils.numberWithMetrixPrefix(newTotal), | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  |             }) | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |             fullTotal += newTotal | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         this._features.setData(newFeatures) | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |         this._totalNumberOfFeatures.setData(fullTotal) | 
					
						
							| 
									
										
										
										
											2024-02-20 23:15:19 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Provides features summarizing the total amount of features at a given location | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export class SummaryTileSource extends DynamicTileSource { | 
					
						
							|  |  |  |     private static readonly empty = [] | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         cacheserver: string, | 
					
						
							|  |  |  |         layers: string[], | 
					
						
							|  |  |  |         zoomRounded: Store<number>, | 
					
						
							|  |  |  |         mapProperties: { | 
					
						
							|  |  |  |             bounds: Store<BBox> | 
					
						
							|  |  |  |             zoom: Store<number> | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         options?: { | 
					
						
							|  |  |  |             isActive?: Store<boolean> | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         const layersSummed = layers.join("+") | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |         const zDiff = 2 | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |         super( | 
					
						
							|  |  |  |             zoomRounded, | 
					
						
							|  |  |  |             0, // minzoom
 | 
					
						
							|  |  |  |             (tileIndex) => { | 
					
						
							|  |  |  |                 const [z, x, y] = Tiles.tile_from_index(tileIndex) | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                 let coordinates = Tiles.centerPointOf(z, x, y) | 
					
						
							| 
									
										
										
										
											2024-02-20 02:56:23 +01:00
										 |  |  |                 const url = `${cacheserver}/${layersSummed}/${z}/${x}/${y}.json` | 
					
						
							|  |  |  |                 const count = UIEventSource.FromPromiseWithErr(Utils.downloadJson(url)) | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |                 const features: Store<Feature<Point>[]> = count.mapD((count) => { | 
					
						
							|  |  |  |                     if (count["error"] !== undefined) { | 
					
						
							|  |  |  |                         console.error( | 
					
						
							|  |  |  |                             "Could not download count for tile", | 
					
						
							|  |  |  |                             z, | 
					
						
							|  |  |  |                             x, | 
					
						
							|  |  |  |                             y, | 
					
						
							|  |  |  |                             "due to", | 
					
						
							|  |  |  |                             count["error"] | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                         return SummaryTileSource.empty | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     const counts = count["success"] | 
					
						
							|  |  |  |                     if (counts === undefined || counts["total"] === 0) { | 
					
						
							|  |  |  |                         return SummaryTileSource.empty | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                     const lat = counts["lat"] | 
					
						
							|  |  |  |                     const lon = counts["lon"] | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |                     const total = Number(counts["total"]) | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                     const tileBbox = new BBox(Tiles.tile_bounds_lon_lat(z, x, y)) | 
					
						
							|  |  |  |                     if (!tileBbox.contains([lon, lat])) { | 
					
						
							|  |  |  |                         console.error( | 
					
						
							|  |  |  |                             "Average coordinate is outside of bbox!?", | 
					
						
							|  |  |  |                             lon, | 
					
						
							|  |  |  |                             lat, | 
					
						
							|  |  |  |                             tileBbox, | 
					
						
							| 
									
										
										
										
											2024-02-20 02:56:23 +01:00
										 |  |  |                             counts, | 
					
						
							|  |  |  |                             url | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                         ) | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                         coordinates = [lon, lat] | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |                     return [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             type: "Feature", | 
					
						
							|  |  |  |                             properties: { | 
					
						
							|  |  |  |                                 id: "summary_" + tileIndex, | 
					
						
							|  |  |  |                                 summary: "yes", | 
					
						
							|  |  |  |                                 ...counts, | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                                 total, | 
					
						
							| 
									
										
										
										
											2024-02-21 16:35:49 +01:00
										 |  |  |                                 total_metric: Utils.numberWithMetrixPrefix(total), | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |                                 layers: layersSummed, | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                             geometry: { | 
					
						
							|  |  |  |                                 type: "Point", | 
					
						
							|  |  |  |                                 coordinates, | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     ] | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |                 return new StaticFeatureSource( | 
					
						
							|  |  |  |                     features.map( | 
					
						
							|  |  |  |                         (f) => { | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |                             if (z - zDiff !== zoomRounded.data) { | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |                                 return SummaryTileSource.empty | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             return f | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         [zoomRounded] | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             mapProperties, | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:46 +01:00
										 |  |  |             { ...options, zDiff } | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |