mapcomplete/Logic/FeatureSource/Sources/ChangeGeometryApplicator.ts
2021-11-07 16:34:51 +01:00

84 lines
No EOL
3.3 KiB
TypeScript

/**
* Applies geometry changes from 'Changes' onto every feature of a featureSource
*/
import {Changes} from "../../Osm/Changes";
import {UIEventSource} from "../../UIEventSource";
import {FeatureSourceForLayer, IndexedFeatureSource} from "../FeatureSource";
import FilteredLayer from "../../../Models/FilteredLayer";
import {ChangeDescription, ChangeDescriptionTools} from "../../Osm/Actions/ChangeDescription";
export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name: string;
public readonly layer: FilteredLayer
private readonly source: IndexedFeatureSource;
private readonly changes: Changes;
constructor(source: (IndexedFeatureSource & FeatureSourceForLayer), changes: Changes) {
this.source = source;
this.changes = changes;
this.layer = source.layer
this.name = "ChangesApplied(" + source.name + ")"
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined)
const self = this;
source.features.addCallbackAndRunD(_ => self.update())
changes.allChanges.addCallbackAndRunD(_ => self.update())
}
private update() {
const upstreamFeatures = this.source.features.data
const upstreamIds = this.source.containedIds.data
const changesToApply = this.changes.allChanges.data
?.filter(ch =>
// Does upsteram have this element? If not, we skip
upstreamIds.has(ch.type + "/" + ch.id) &&
// Are any (geometry) changes defined?
ch.changes !== undefined &&
// Ignore new elements, they are handled by the NewGeometryFromChangesFeatureSource
ch.id > 0)
if (changesToApply === undefined || changesToApply.length === 0) {
// No changes to apply!
// Pass the original feature and lets continue our day
this.features.setData(upstreamFeatures);
return;
}
const changesPerId = new Map<string, ChangeDescription[]>()
for (const ch of changesToApply) {
const key = ch.type + "/" + ch.id
if (changesPerId.has(key)) {
changesPerId.get(key).push(ch)
} else {
changesPerId.set(key, [ch])
}
}
const newFeatures: { feature: any, freshness: Date }[] = []
for (const feature of upstreamFeatures) {
const changesForFeature = changesPerId.get(feature.feature.properties.id)
if (changesForFeature === undefined) {
// No changes for this element
newFeatures.push(feature)
continue;
}
// Allright! We have a feature to rewrite!
const copy = {
...feature
}
// We only apply the last change as that one'll have the latest geometry
const change = changesForFeature[changesForFeature.length - 1]
copy.feature.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
console.log("Applying a geometry change onto ", feature, change, copy)
newFeatures.push(copy)
}
this.features.setData(newFeatures)
}
}