| 
									
										
										
										
											2023-05-17 13:19:43 +02:00
										 |  |  | import {FeatureSource} from "./FeatureSource" | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | import FilteredLayer from "../../Models/FilteredLayer" | 
					
						
							|  |  |  | import SimpleFeatureSource from "./Sources/SimpleFeatureSource" | 
					
						
							| 
									
										
										
										
											2023-05-17 13:19:43 +02:00
										 |  |  | import {Feature} from "geojson" | 
					
						
							|  |  |  | import {UIEventSource} from "../UIEventSource" | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * In some rare cases, some elements are shown on multiple layers (when 'passthrough' is enabled) | 
					
						
							|  |  |  |  * If this is the case, multiple objects with a different _matching_layer_id are generated. | 
					
						
							|  |  |  |  * In any case, this featureSource marks the objects with _matching_layer_id | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  | export default class PerLayerFeatureSourceSplitter<T extends FeatureSource = FeatureSource> { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |     public readonly perLayer: ReadonlyMap<string, T> | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     constructor( | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         layers: FilteredLayer[], | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         upstream: FeatureSource, | 
					
						
							|  |  |  |         options?: { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             constructStore?: (features: UIEventSource<Feature[]>, layer: FilteredLayer) => T | 
					
						
							| 
									
										
										
										
											2023-03-30 04:51:56 +02:00
										 |  |  |             handleLeftovers?: (featuresWithoutLayer: Feature[]) => void | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         const knownLayers = new Map<string, T>() | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |         /** | 
					
						
							|  |  |  |          * Keeps track of the ids that are included per layer. | 
					
						
							|  |  |  |          * Used to know if the downstream feature source needs to be pinged | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         let layerIndexes: ReadonlySet<string>[] = layers.map((_) => new Set<string>()) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         this.perLayer = knownLayers | 
					
						
							|  |  |  |         const layerSources = new Map<string, UIEventSource<Feature[]>>() | 
					
						
							|  |  |  |         const constructStore = | 
					
						
							|  |  |  |             options?.constructStore ?? ((store, layer) => new SimpleFeatureSource(layer, store)) | 
					
						
							|  |  |  |         for (const layer of layers) { | 
					
						
							|  |  |  |             const src = new UIEventSource<Feature[]>([]) | 
					
						
							|  |  |  |             layerSources.set(layer.layerDef.id, src) | 
					
						
							|  |  |  |             knownLayers.set(layer.layerDef.id, <T>constructStore(src, layer)) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         upstream.features.addCallbackAndRunD((features) => { | 
					
						
							|  |  |  |             if (layers === undefined) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // We try to figure out (for each feature) in which feature store it should be saved.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 01:42:47 +01:00
										 |  |  |             const featuresPerLayer = new Map<string, Feature[]>() | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |             /** | 
					
						
							|  |  |  |              * Indexed on layer-position | 
					
						
							|  |  |  |              * Will be true if a new id pops up | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             const hasChanged: boolean[] = layers.map((_) => false) | 
					
						
							|  |  |  |             const newIndices: Set<string>[] = layers.map((_) => new Set<string>()) | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             const noLayerFound: Feature[] = [] | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |             for (const layer of layers) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |                 featuresPerLayer.set(layer.layerDef.id, []) | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const f of features) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 let foundALayer = false | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |                 for (let i = 0; i < layers.length; i++) { | 
					
						
							|  |  |  |                     const layer = layers[i] | 
					
						
							| 
									
										
										
										
											2023-05-17 13:19:43 +02:00
										 |  |  |                     if(!layer.layerDef?.source){ | 
					
						
							|  |  |  |                         console.error("PerLayerFeatureSourceSplitter got a layer without a source:", layer.layerDef.id) | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2023-03-23 01:42:47 +01:00
										 |  |  |                     if (layer.layerDef.source.osmTags.matchesProperties(f.properties)) { | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |                         const id = f.properties.id | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                         // We have found our matching layer!
 | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |                         const previousIndex = layerIndexes[i] | 
					
						
							|  |  |  |                         hasChanged[i] = hasChanged[i] || !previousIndex.has(id) | 
					
						
							|  |  |  |                         newIndices[i].add(id) | 
					
						
							| 
									
										
										
										
											2021-12-13 20:51:44 +01:00
										 |  |  |                         featuresPerLayer.get(layer.layerDef.id).push(f) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                         foundALayer = true | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                         if (!layer.layerDef.passAllFeatures) { | 
					
						
							|  |  |  |                             // If not 'passAllFeatures', we are done for this feature
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                             break | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 if (!foundALayer) { | 
					
						
							| 
									
										
										
										
											2022-04-28 11:47:54 +02:00
										 |  |  |                     noLayerFound.push(f) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // At this point, we have our features per layer as a list
 | 
					
						
							|  |  |  |             // We assign them to the correct featureSources
 | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |             for (let i = 0; i < layers.length; i++) { | 
					
						
							|  |  |  |                 const layer = layers[i] | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 const id = layer.layerDef.id | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                 const features = featuresPerLayer.get(id) | 
					
						
							|  |  |  |                 if (features === undefined) { | 
					
						
							|  |  |  |                     // No such features for this layer
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |                 if (!hasChanged[i] && layerIndexes[i].size === newIndices[i].size) { | 
					
						
							|  |  |  |                     // No new id has been added and the sizes are the same (thus: nothing has been removed as well)
 | 
					
						
							|  |  |  |                     // We can safely assume that no changes were made
 | 
					
						
							| 
									
										
										
										
											2023-03-30 04:51:56 +02:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 layerSources.get(id).setData(features) | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |             layerIndexes = newIndices | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |             // AT last, the leftovers are handled
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |             if (options?.handleLeftovers !== undefined && noLayerFound.length > 0) { | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |                 options.handleLeftovers(noLayerFound) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 02:24:38 +02:00
										 |  |  |     public forEach(f: (featureSource: T) => void) { | 
					
						
							| 
									
										
										
										
											2023-03-28 05:13:48 +02:00
										 |  |  |         for (const fs of this.perLayer.values()) { | 
					
						
							|  |  |  |             f(fs) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-20 17:14:55 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | } |