import FeatureSource, { IndexedFeatureSource } from "../FeatureSource" import { UIEventSource } from "../../UIEventSource" /** * Constructs a UIEventStore for the properties of every Feature, indexed by id */ export default class FeaturePropertiesStore { private readonly _source: FeatureSource & IndexedFeatureSource private readonly _elements = new Map>() constructor(source: FeatureSource & IndexedFeatureSource) { this._source = source const self = this source.features.addCallbackAndRunD((features) => { for (const feature of features) { const id = feature.properties.id if (id === undefined) { console.trace("Error: feature without ID:", feature) throw "Error: feature without ID" } const source = self._elements.get(id) if (source === undefined) { self._elements.set(id, new UIEventSource(feature.properties)) continue } if (source.data === feature.properties) { continue } // Update the tags in the old store and link them const changeMade = FeaturePropertiesStore.mergeTags(source.data, feature.properties) feature.properties = source.data if (changeMade) { source.ping() } } }) } public getStore(id: string): UIEventSource> { return this._elements.get(id) } public addSpecial(id: string, store: UIEventSource>) { this._elements.set(id, store) } /** * Overwrites the tags of the old properties object, returns true if a change was made. * Metatags are overriden if they are in the new properties, but not removed * @param oldProperties * @param newProperties * @private */ private static mergeTags( oldProperties: Record, newProperties: Record ): boolean { let changeMade = false for (const oldPropertiesKey in oldProperties) { // Delete properties from the old record if it is not in the new store anymore if (oldPropertiesKey.startsWith("_")) { continue } if (newProperties[oldPropertiesKey] === undefined) { changeMade = true delete oldProperties[oldPropertiesKey] } } // Copy all properties from the new record into the old for (const newPropertiesKey in newProperties) { const v = newProperties[newPropertiesKey] if (oldProperties[newPropertiesKey] !== v) { oldProperties[newPropertiesKey] = v changeMade = true } } return changeMade } addAlias(oldId: string, newId: string): void { if (newId === undefined) { // We removed the node/way/relation with type 'type' and id 'oldId' on openstreetmap! const element = this._elements.get(oldId) element.data._deleted = "yes" element.ping() return } if (oldId == newId) { return } const element = this._elements.get(oldId) if (element === undefined) { // Element to rewrite not found, probably a node or relation that is not rendered return } element.data.id = newId this._elements.set(newId, element) element.ping() } has(id: string) { return this._elements.has(id) } }