import { Store, UIEventSource } from "../../UIEventSource" import FeatureSource, { IndexedFeatureSource } from "../FeatureSource" import { Feature } from "geojson" /** * */ export default class FeatureSourceMerger implements IndexedFeatureSource { public features: UIEventSource = new UIEventSource([]) public readonly featuresById: Store> private readonly _featuresById: UIEventSource> private readonly _sources: FeatureSource[] = [] /** * Merges features from different featureSources. * In case that multiple features have the same id, the latest `_version_number` will be used. Otherwise, we will take the last one */ constructor(...sources: FeatureSource[]) { this._featuresById = new UIEventSource>(undefined) this.featuresById = this._featuresById const self = this for (let source of sources) { source.features.addCallback(() => { self.addData(sources.map((s) => s.features.data)) }) } this.addData(sources.map((s) => s.features.data)) this._sources = sources } protected addSource(source: FeatureSource) { this._sources.push(source) source.features.addCallbackAndRun(() => { this.addData(this._sources.map((s) => s.features.data)) }) } protected addData(featuress: Feature[][]) { let somethingChanged = false const all: Map = new Map() // We seed the dictionary with the previously loaded features const oldValues = this.features.data ?? [] for (const oldValue of oldValues) { all.set(oldValue.properties.id, oldValue) } for (const features of featuress) { if (features === undefined) { continue } for (const f of features) { const id = f.properties.id if (!all.has(id)) { // This is a new feature somethingChanged = true all.set(id, f) continue } // This value has been seen already, either in a previous run or by a previous datasource // Let's figure out if something changed const oldV = all.get(id) if (oldV == f) { continue } all.set(id, f) somethingChanged = true } } if (!somethingChanged) { // We don't bother triggering an update return } const newList = [] all.forEach((value, key) => { newList.push(value) }) this.features.setData(newList) this._featuresById.setData(all) } }