| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  | import { FeatureSource } from "../FeatureSource" | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | import { Feature } from "geojson" | 
					
						
							|  |  |  | import TileLocalStorage from "./TileLocalStorage" | 
					
						
							|  |  |  | import { GeoOperations } from "../../GeoOperations" | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  | import FeaturePropertiesStore from "./FeaturePropertiesStore" | 
					
						
							|  |  |  | import { UIEventSource } from "../../UIEventSource" | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | import { Utils } from "../../../Utils" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  | class SingleTileSaver { | 
					
						
							|  |  |  |     private readonly _storage: UIEventSource<Feature[]> | 
					
						
							|  |  |  |     private readonly _registeredIds = new Set<string>() | 
					
						
							|  |  |  |     private readonly _featureProperties: FeaturePropertiesStore | 
					
						
							|  |  |  |     private readonly _isDirty = new UIEventSource(false) | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         storage: UIEventSource<Feature[]> & { flush: () => void }, | 
					
						
							|  |  |  |         featureProperties: FeaturePropertiesStore | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         this._storage = storage | 
					
						
							|  |  |  |         this._featureProperties = featureProperties | 
					
						
							|  |  |  |         this._isDirty.stabilized(1000).addCallbackD((isDirty) => { | 
					
						
							|  |  |  |             if (!isDirty) { | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // 'isDirty' is set when tags of some object have changed
 | 
					
						
							|  |  |  |             storage.flush() | 
					
						
							|  |  |  |             this._isDirty.setData(false) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public saveFeatures(features: Feature[]) { | 
					
						
							|  |  |  |         if (Utils.sameList(features, this._storage.data)) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (const feature of features) { | 
					
						
							|  |  |  |             const id = feature.properties.id | 
					
						
							|  |  |  |             if (this._registeredIds.has(id)) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             this._featureProperties.getStore(id)?.addCallbackAndRunD(() => { | 
					
						
							|  |  |  |                 this._isDirty.setData(true) | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             this._registeredIds.add(id) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this._storage.setData(features) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  | /*** | 
					
						
							|  |  |  |  * Saves all the features that are passed in to localstorage, so they can be retrieved on the next run | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The data is saved in a tiled way on a fixed zoomlevel and is retrievable per layer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Also see the sibling class | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export default class SaveFeatureSourceToLocalStorage { | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |     constructor( | 
					
						
							| 
									
										
										
										
											2023-04-20 01:52:23 +02:00
										 |  |  |         backend: string, | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |         layername: string, | 
					
						
							|  |  |  |         zoomlevel: number, | 
					
						
							|  |  |  |         features: FeatureSource, | 
					
						
							| 
									
										
										
										
											2023-06-01 11:37:40 +02:00
										 |  |  |         featureProperties: FeaturePropertiesStore, | 
					
						
							|  |  |  |         maxCacheAge: number | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-06-01 11:37:40 +02:00
										 |  |  |         const storage = TileLocalStorage.construct<Feature[]>(backend, layername, maxCacheAge) | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |         const singleTileSavers: Map<number, SingleTileSaver> = new Map<number, SingleTileSaver>() | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         features.features.addCallbackAndRunD((features) => { | 
					
						
							|  |  |  |             const sliced = GeoOperations.slice(zoomlevel, features) | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             sliced.forEach((features, tileIndex) => { | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |                 let tileSaver = singleTileSavers.get(tileIndex) | 
					
						
							|  |  |  |                 if (tileSaver === undefined) { | 
					
						
							|  |  |  |                     const src = storage.getTileSource(tileIndex) | 
					
						
							|  |  |  |                     tileSaver = new SingleTileSaver(src, featureProperties) | 
					
						
							|  |  |  |                     singleTileSavers.set(tileIndex, tileSaver) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-04-18 23:44:49 +02:00
										 |  |  |                 // Don't cache not-uploaded features yet - they'll be cached when the receive their id
 | 
					
						
							|  |  |  |                 features = features.filter((f) => !f.properties.id.match(/(node|way)\/-[0-9]+/)) | 
					
						
							|  |  |  |                 tileSaver.saveFeatures(features) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             }) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |