forked from MapComplete/MapComplete
		
	Add names to feature sources, fix that old, cached geometries get changed when a newer version is loaded
This commit is contained in:
		
							parent
							
								
									6234d26bac
								
							
						
					
					
						commit
						141d4db028
					
				
					 14 changed files with 60 additions and 43 deletions
				
			
		|  | @ -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; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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){ | ||||||
|  |  | ||||||
|  | @ -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>, | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| } | } | ||||||
|  | @ -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; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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)) { | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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){ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue