forked from MapComplete/MapComplete
		
	
		
			
	
	
		
			90 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			90 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import {Changes} from "../../Osm/Changes"; | ||
|  | import {OsmNode, OsmRelation, OsmWay} from "../../Osm/OsmObject"; | ||
|  | import FeatureSource from "../FeatureSource"; | ||
|  | import {UIEventSource} from "../../UIEventSource"; | ||
|  | import {ChangeDescription} from "../../Osm/Actions/ChangeDescription"; | ||
|  | 
 | ||
|  | export class NewGeometryFromChangesFeatureSource implements FeatureSource { | ||
|  |     // This class name truly puts the 'Java' into 'Javascript'
 | ||
|  |      | ||
|  |     /** | ||
|  |      * A feature source containing exclusively new elements | ||
|  |      */ | ||
|  |     public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]); | ||
|  |     public readonly name: string = "newFeatures"; | ||
|  | 
 | ||
|  |     constructor(changes: Changes) { | ||
|  | 
 | ||
|  |         const seenChanges = new Set<ChangeDescription>(); | ||
|  |         const features = this.features.data; | ||
|  |         const self = this; | ||
|  | 
 | ||
|  |         changes.pendingChanges | ||
|  |             .map(changes => changes.filter(ch => | ||
|  |                 // only new objects allowed
 | ||
|  |                 ch.id < 0 && | ||
|  |                 // The change is an update to the object (e.g. tags or geometry) - not the actual create
 | ||
|  |                 ch.changes !== undefined && | ||
|  |                 // If tags is undefined, this is probably a new point that is part of a split road
 | ||
|  |                 ch.tags !== undefined && | ||
|  |                 // Already handled
 | ||
|  |                 !seenChanges.has(ch))) | ||
|  |             .addCallbackAndRunD(changes => { | ||
|  | 
 | ||
|  |                 if (changes.length === 0) { | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 const now = new Date(); | ||
|  | 
 | ||
|  |                 function add(feature) { | ||
|  |                     feature.id = feature.properties.id | ||
|  |                     features.push({ | ||
|  |                         feature: feature, | ||
|  |                         freshness: now | ||
|  |                     }) | ||
|  |                     console.warn("Added a new feature: ", JSON.stringify(feature)) | ||
|  |                 } | ||
|  | 
 | ||
|  |                 for (const change of changes) { | ||
|  |                     seenChanges.add(change) | ||
|  |                     try { | ||
|  |                         const tags = {} | ||
|  |                         for (const kv of change.tags) { | ||
|  |                             tags[kv.k] = kv.v | ||
|  |                         } | ||
|  |                         tags["id"] = change.type+"/"+change.id | ||
|  |                         switch (change.type) { | ||
|  |                             case "node": | ||
|  |                                 const n = new OsmNode(change.id) | ||
|  |                                 n.tags = tags | ||
|  |                                 n.lat = change.changes["lat"] | ||
|  |                                 n.lon = change.changes["lon"] | ||
|  |                                 const geojson = n.asGeoJson() | ||
|  |                                 add(geojson) | ||
|  |                                 break; | ||
|  |                             case "way": | ||
|  |                                 const w = new OsmWay(change.id) | ||
|  |                                 w.tags = tags | ||
|  |                                 w.nodes = change.changes["nodes"] | ||
|  |                                 w.coordinates = change.changes["coordinates"].map(coor => coor.reverse()) | ||
|  |                                 add(w.asGeoJson()) | ||
|  |                                 break; | ||
|  |                             case "relation": | ||
|  |                                 const r = new OsmRelation(change.id) | ||
|  |                                 r.tags = tags | ||
|  |                                 r.members = change.changes["members"] | ||
|  |                                 add(r.asGeoJson()) | ||
|  |                                 break; | ||
|  |                         } | ||
|  |                     } catch (e) { | ||
|  |                         console.error("Could not generate a new geometry to render on screen for:", e) | ||
|  |                     } | ||
|  | 
 | ||
|  |                 } | ||
|  |                  | ||
|  |                 self.features.ping() | ||
|  |             }) | ||
|  |     } | ||
|  | 
 | ||
|  | } |