Add names to feature sources, fix that old, cached geometries get changed when a newer version is loaded

This commit is contained in:
pietervdvn 2021-04-23 12:55:38 +02:00
parent 6234d26bac
commit 141d4db028
14 changed files with 60 additions and 43 deletions

View file

@ -11,6 +11,8 @@ import {TagsFilter} from "../Tags/TagsFilter";
export default class UpdateFromOverpass implements FeatureSource { export default class UpdateFromOverpass implements FeatureSource {
public readonly name = "UpdateFromOverpass"
/** /**
* The last loaded features of the geojson * The last loaded features of the geojson
*/ */
@ -86,7 +88,7 @@ export default class UpdateFromOverpass implements FeatureSource {
if (layer.doNotDownload) { if (layer.doNotDownload) {
continue; continue;
} }
if(layer.source.geojsonSource !== undefined){ if (layer.source.geojsonSource !== undefined) {
// Not our responsibility to download this layer! // Not our responsibility to download this layer!
continue; continue;
} }
@ -129,7 +131,7 @@ export default class UpdateFromOverpass implements FeatureSource {
return; return;
} }
if(this.timeout.data > 0){ if (this.timeout.data > 0) {
console.log("Still in timeout - not updating") console.log("Still in timeout - not updating")
return; return;
} }

View file

@ -13,7 +13,7 @@ export default class UpdateTagsFromOsmAPI {
"_last_edit:timestamp", "_last_edit:timestamp",
"_version_number"], "_version_number"],
"Information about the last edit of this object. \n\nIMPORTANT: this data is _only_ loaded when the popup is added. This means it should _not_ be used to render icons!", "Information about the last edit of this object. \n\nIMPORTANT: this data is _only_ loaded when the popup is added. This means it should _not_ be used to render icons!",
(feature: any, index: number, freshness: Date) => {/*Do nothing - this is only added for documentation reasons*/ () => {/*Do nothing - this is only added for documentation reasons*/
} }
) )
@ -28,7 +28,7 @@ export default class UpdateTagsFromOsmAPI {
} }
OsmObject.DownloadObject(id, (element: OsmObject, meta: OsmObjectMeta) => { OsmObject.DownloadObject(id, (element: OsmObject, meta: OsmObjectMeta) => {
console.log("Updating element from OSM-API: ", element) console.debug("Updating tags from the OSM-API: ", element)
const tags = element.tags; const tags = element.tags;

View file

@ -11,12 +11,10 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig";
export default class FeatureDuplicatorPerLayer implements FeatureSource { export default class FeatureDuplicatorPerLayer implements FeatureSource {
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>; public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name;
public static GetMatchingLayerId(){
}
constructor(layers: UIEventSource<{ layerDef: LayerConfig }[]>, upstream: FeatureSource) { constructor(layers: UIEventSource<{ layerDef: LayerConfig }[]>, upstream: FeatureSource) {
this.name = "FeatureDuplicator of "+upstream.name;
this.features = upstream.features.map(features => { this.features = upstream.features.map(features => {
const newFeatures: { feature: any, freshness: Date }[] = []; const newFeatures: { feature: any, freshness: Date }[] = [];
if(features === undefined){ if(features === undefined){

View file

@ -18,6 +18,8 @@ export default class FeaturePipeline implements FeatureSource {
public features: UIEventSource<{ feature: any; freshness: Date }[]>; public features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name = "FeaturePipeline"
constructor(flayers: UIEventSource<{ isDisplayed: UIEventSource<boolean>, layerDef: LayerConfig }[]>, constructor(flayers: UIEventSource<{ isDisplayed: UIEventSource<boolean>, layerDef: LayerConfig }[]>,
updater: FeatureSource, updater: FeatureSource,
layout: UIEventSource<LayoutConfig>, layout: UIEventSource<LayoutConfig>,

View file

@ -2,4 +2,8 @@ import {UIEventSource} from "../UIEventSource";
export default interface FeatureSource { export default interface FeatureSource {
features: UIEventSource<{feature: any, freshness: Date}[]>; features: UIEventSource<{feature: any, freshness: Date}[]>;
/**
* Mainly used for debuging
*/
name: string;
} }

View file

@ -3,13 +3,15 @@ import {UIEventSource} from "../UIEventSource";
export default class FeatureSourceMerger implements FeatureSource { export default class FeatureSourceMerger implements FeatureSource {
public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{feature: any; freshness: Date}[]>([]); public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name;
private readonly _sources: FeatureSource[]; private readonly _sources: FeatureSource[];
constructor(sources: FeatureSource[]) { constructor(sources: FeatureSource[]) {
this._sources = sources; this._sources = sources;
this.name = "SourceMerger of (" + sources.map(s => s.name).join(", ") + ")"
const self = this; const self = this;
for (let i = 0; i < sources.length; i++){ for (let i = 0; i < sources.length; i++) {
let source = sources[i]; let source = sources[i];
source.features.addCallback(() => { source.features.addCallback(() => {
self.Update(); self.Update();
@ -21,17 +23,17 @@ export default class FeatureSourceMerger implements FeatureSource {
private Update() { private Update() {
let all = {}; // Mapping 'id' -> {feature, freshness} let all = {}; // Mapping 'id' -> {feature, freshness}
for (const source of this._sources) { for (const source of this._sources) {
if(source?.features?.data === undefined){ if (source?.features?.data === undefined) {
continue; continue;
} }
for (const f of source.features.data) { for (const f of source.features.data) {
const id = f.feature.properties.id+f.feature.geometry.type+f.feature._matching_layer_id; const id = f.feature.properties.id;
const oldV = all[id]; const oldV = all[id];
if(oldV === undefined){ if (oldV === undefined) {
all[id] = f; all[id] = f;
}else{ } else {
if(oldV.freshness < f.freshness){ if (oldV.freshness < f.freshness) {
all[id]=f; all[id] = f;
} }
} }
} }

View file

@ -5,7 +5,7 @@ import Loc from "../../Models/Loc";
export default class FilteringFeatureSource implements FeatureSource { export default class FilteringFeatureSource implements FeatureSource {
public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]); public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
public readonly name = "FilteringFeatureSource"
constructor(layers: UIEventSource<{ constructor(layers: UIEventSource<{
isDisplayed: UIEventSource<boolean>, isDisplayed: UIEventSource<boolean>,
layerDef: LayerConfig layerDef: LayerConfig
@ -23,7 +23,6 @@ export default class FilteringFeatureSource implements FeatureSource {
layerDict[layer.layerDef.id] = layer; layerDict[layer.layerDef.id] = layer;
} }
console.log("Updating the filtering layer, input ", upstream.features.data.length, "features")
const features: { feature: any, freshness: Date }[] = upstream.features.data; const features: { feature: any, freshness: Date }[] = upstream.features.data;
@ -65,8 +64,6 @@ export default class FilteringFeatureSource implements FeatureSource {
return false; return false;
}); });
console.log("Updating the filtering layer, output ", newFeatures.length, "features")
self.features.setData(newFeatures); self.features.setData(newFeatures);
} }

View file

@ -14,12 +14,10 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig";
*/ */
export default class GeoJsonSource implements FeatureSource { export default class GeoJsonSource implements FeatureSource {
features: UIEventSource<{ feature: any; freshness: Date }[]>; public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name;
private readonly onFail: ((errorMsg: any, url: string) => void) = undefined; private readonly onFail: ((errorMsg: any, url: string) => void) = undefined;
private readonly layerId: string; private readonly layerId: string;
private readonly seenids: Set<string> = new Set<string>() private readonly seenids: Set<string> = new Set<string>()
constructor(locationControl: UIEventSource<Loc>, constructor(locationControl: UIEventSource<Loc>,
@ -27,6 +25,7 @@ export default class GeoJsonSource implements FeatureSource {
onFail?: ((errorMsg: any) => void)) { onFail?: ((errorMsg: any) => void)) {
this.layerId = flayer.layerDef.id; this.layerId = flayer.layerDef.id;
let url = flayer.layerDef.source.geojsonSource; let url = flayer.layerDef.source.geojsonSource;
this.name = "GeoJsonSource of " + url;
const zoomLevel = flayer.layerDef.source.geojsonZoomLevel; const zoomLevel = flayer.layerDef.source.geojsonZoomLevel;
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([]) this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
@ -110,8 +109,6 @@ export default class GeoJsonSource implements FeatureSource {
flayersPerSource.get(url).push(flayer) flayersPerSource.get(url).push(flayer)
} }
console.log("SOURCES", flayersPerSource)
const sources: GeoJsonSource[] = [] const sources: GeoJsonSource[] = []
flayersPerSource.forEach((flayers, key) => { flayersPerSource.forEach((flayers, key) => {
@ -153,13 +150,11 @@ export default class GeoJsonSource implements FeatureSource {
const self = this; const self = this;
$.getJSON(url, function (json, status) { $.getJSON(url, function (json, status) {
if (status !== "success") { if (status !== "success") {
console.log("Fetching geojson failed failed")
self.onFail(status, url); self.onFail(status, url);
return; return;
} }
if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) { if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) {
console.log("Timeout or other runtime error");
self.onFail("Runtime error (timeout)", url) self.onFail("Runtime error (timeout)", url)
return; return;
} }
@ -179,16 +174,16 @@ export default class GeoJsonSource implements FeatureSource {
} }
self.seenids.add(feature.properties.id) self.seenids.add(feature.properties.id)
let freshness : Date = time; let freshness: Date = time;
if(feature["_timestamp"] !== undefined){ if (feature["_timestamp"] !== undefined) {
freshness = new Date(feature["_timestamp"]) freshness = new Date(feature["_timestamp"])
} }
newFeatures.push({feature: feature, freshness: freshness}) newFeatures.push({feature: feature, freshness: freshness})
} }
console.log("Downloaded "+newFeatures.length+" new features and "+skipped+" already seen features from "+ url); console.debug("Downloaded " + newFeatures.length + " new features and " + skipped + " already seen features from " + url);
if(newFeatures.length == 0){ if (newFeatures.length == 0) {
return; return;
} }

View file

@ -11,6 +11,8 @@ export default class LocalStorageSaver implements FeatureSource {
public static readonly storageKey: string = "cached-features"; public static readonly storageKey: string = "cached-features";
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>; public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name = "LocalStorageSaver";
constructor(source: FeatureSource, layout: UIEventSource<LayoutConfig>) { constructor(source: FeatureSource, layout: UIEventSource<LayoutConfig>) {
this.features = source.features; this.features = source.features;

View file

@ -5,6 +5,7 @@ import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
export default class LocalStorageSource implements FeatureSource { export default class LocalStorageSource implements FeatureSource {
public features: UIEventSource<{ feature: any; freshness: Date }[]>; public features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name = "LocalStorageSource";
constructor(layout: UIEventSource<LayoutConfig>) { constructor(layout: UIEventSource<LayoutConfig>) {
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([]) this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
@ -17,8 +18,15 @@ export default class LocalStorageSource implements FeatureSource {
if (fromStorage == null) { if (fromStorage == null) {
return; return;
} }
const loaded = JSON.parse(fromStorage); const loaded : { feature: any; freshness: Date | string }[]=
this.features.setData(loaded); JSON.parse(fromStorage);
const parsed : { feature: any; freshness: Date }[]= loaded.map(ff => ({
feature: ff.feature,
freshness : typeof ff.freshness == "string" ? new Date(ff.freshness) : ff.freshness
}))
this.features.setData(parsed);
console.log("Loaded ", loaded.length, " features from localstorage as cache") console.log("Loaded ", loaded.length, " features from localstorage as cache")
} catch (e) { } catch (e) {
console.log("Could not load features from localStorage:", e) console.log("Could not load features from localStorage:", e)

View file

@ -6,10 +6,13 @@ import MetaTagging from "../MetaTagging";
import ExtractRelations from "../Osm/ExtractRelations"; import ExtractRelations from "../Osm/ExtractRelations";
export default class MetaTaggingFeatureSource implements FeatureSource { export default class MetaTaggingFeatureSource implements FeatureSource {
features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{feature: any; freshness: Date}[]>(undefined); public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{feature: any; freshness: Date}[]>(undefined);
public readonly name;
constructor(source: FeatureSource) { constructor(source: FeatureSource) {
const self = this; const self = this;
this.name = "MetaTagging of "+source.name
source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => { source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => {
if (featuresFreshness === undefined) { if (featuresFreshness === undefined) {
return; return;

View file

@ -3,10 +3,11 @@ import {UIEventSource} from "../UIEventSource";
import State from "../../State"; import State from "../../State";
export default class RegisteringFeatureSource implements FeatureSource { export default class RegisteringFeatureSource implements FeatureSource {
features: UIEventSource<{ feature: any; freshness: Date }[]>; public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
public readonly name;
constructor(source: FeatureSource) { constructor(source: FeatureSource) {
this.features = source.features; this.features = source.features;
this.name = "RegisteringSource of "+source.name;
this.features.addCallbackAndRun(features => { this.features.addCallbackAndRun(features => {
for (const feature of features ?? []) { for (const feature of features ?? []) {
if (!State.state.allElements.has(feature.feature.properties.id)) { if (!State.state.allElements.has(feature.feature.properties.id)) {

View file

@ -5,10 +5,13 @@ import FeatureSource from "./FeatureSource";
import {UIEventSource} from "../UIEventSource"; import {UIEventSource} from "../UIEventSource";
export default class RememberingSource implements FeatureSource { export default class RememberingSource implements FeatureSource {
features: UIEventSource<{ feature: any, freshness: Date }[]>; public readonly features: UIEventSource<{ feature: any, freshness: Date }[]>;
public readonly name;
constructor(source: FeatureSource) { constructor(source: FeatureSource) {
const self = this; const self = this;
this.name = "RememberingSource of "+source.name;
const empty = []; const empty = [];
this.features = source.features.map(features => { this.features = source.features.map(features => {
const oldFeatures = self.features?.data ?? empty; const oldFeatures = self.features?.data ?? empty;

View file

@ -51,7 +51,7 @@ export default class WayHandlingApplyingFeatureSource implements FeatureSource {
// Create the copy // Create the copy
const centerPoint = GeoOperations.centerpoint(feat); const centerPoint = GeoOperations.centerpoint(feat);
centerPoint._matching_layer_id = feat._matching_layer_id; centerPoint["_matching_layer_id"] = feat._matching_layer_id;
newFeatures.push({feature: centerPoint, freshness: f.freshness}); newFeatures.push({feature: centerPoint, freshness: f.freshness});
if(layer.wayHandling === LayerConfig.WAYHANDLING_CENTER_AND_WAY){ if(layer.wayHandling === LayerConfig.WAYHANDLING_CENTER_AND_WAY){