import FeatureSource, { FeatureSourceForLayer, Tiled } from "./FeatureSource" import { Store } from "../UIEventSource" import FilteredLayer from "../../Models/FilteredLayer" import SimpleFeatureSource from "./Sources/SimpleFeatureSource" /** * 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 */ export default class PerLayerFeatureSourceSplitter { constructor( layers: Store, handleLayerData: (source: FeatureSourceForLayer & Tiled) => void, upstream: FeatureSource, options?: { tileIndex?: number handleLeftovers?: (featuresWithoutLayer: any[]) => void } ) { const knownLayers = new Map() function update() { const features = upstream.features?.data if (features === undefined) { return } if (layers.data === undefined || layers.data.length === 0) { return } // We try to figure out (for each feature) in which feature store it should be saved. // Note that this splitter is only run when it is invoked by the overpass feature source, so we can't be sure in which layer it should go const featuresPerLayer = new Map() const noLayerFound = [] for (const layer of layers.data) { featuresPerLayer.set(layer.layerDef.id, []) } for (const f of features) { let foundALayer = false for (const layer of layers.data) { if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) { // We have found our matching layer! featuresPerLayer.get(layer.layerDef.id).push(f) foundALayer = true if (!layer.layerDef.passAllFeatures) { // If not 'passAllFeatures', we are done for this feature break } } } if (!foundALayer) { noLayerFound.push(f) } } // At this point, we have our features per layer as a list // We assign them to the correct featureSources for (const layer of layers.data) { const id = layer.layerDef.id const features = featuresPerLayer.get(id) if (features === undefined) { // No such features for this layer continue } let featureSource = knownLayers.get(id) if (featureSource === undefined) { // Not yet initialized - now is a good time featureSource = new SimpleFeatureSource(layer, options?.tileIndex) featureSource.features.setData(features) knownLayers.set(id, featureSource) handleLayerData(featureSource) } else { featureSource.features.setData(features) } } // AT last, the leftovers are handled if (options?.handleLeftovers !== undefined && noLayerFound.length > 0) { options.handleLeftovers(noLayerFound) } } layers.addCallback((_) => update()) upstream.features.addCallbackAndRunD((_) => update()) } }