forked from MapComplete/MapComplete
		
	Refactoring: save ID to the hash of the URL
This commit is contained in:
		
							parent
							
								
									7d941e8a9a
								
							
						
					
					
						commit
						78c56f6fa2
					
				
					 4 changed files with 27 additions and 163 deletions
				
			
		|  | @ -1,133 +0,0 @@ | |||
| import { UIEventSource } from "../UIEventSource" | ||||
| import Loc from "../../Models/Loc" | ||||
| import { ElementStorage } from "../ElementStorage" | ||||
| import FeaturePipeline from "../FeatureSource/FeaturePipeline" | ||||
| import { GeoOperations } from "../GeoOperations" | ||||
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | ||||
| import OsmObjectDownloader from "../Osm/OsmObjectDownloader" | ||||
| 
 | ||||
| /** | ||||
|  * Makes sure the hash shows the selected element and vice-versa. | ||||
|  */ | ||||
| export default class SelectedFeatureHandler { | ||||
|     private static readonly _no_trigger_on = new Set([ | ||||
|         "welcome", | ||||
|         "copyright", | ||||
|         "layers", | ||||
|         "new", | ||||
|         "filters", | ||||
|         "location_track", | ||||
|         "", | ||||
|         undefined, | ||||
|     ]) | ||||
|     private readonly hash: UIEventSource<string> | ||||
|     private readonly state: { | ||||
|         selectedElement: UIEventSource<any> | ||||
|         allElements: ElementStorage | ||||
|         locationControl: UIEventSource<Loc> | ||||
|         layoutToUse: LayoutConfig | ||||
|         objectDownloader: OsmObjectDownloader | ||||
|     } | ||||
| 
 | ||||
|     constructor( | ||||
|         hash: UIEventSource<string>, | ||||
|         state: { | ||||
|             selectedElement: UIEventSource<any> | ||||
|             allElements: ElementStorage | ||||
|             featurePipeline: FeaturePipeline | ||||
|             locationControl: UIEventSource<Loc> | ||||
|             layoutToUse: LayoutConfig | ||||
|             objectDownloader: OsmObjectDownloader | ||||
|         } | ||||
|     ) { | ||||
|         this.hash = hash | ||||
|         this.state = state | ||||
| 
 | ||||
|         // If the hash changes, set the selected element correctly
 | ||||
| 
 | ||||
|         const self = this | ||||
|         hash.addCallback(() => self.setSelectedElementFromHash()) | ||||
|         this.initialLoad() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * On startup: check if the hash is loaded and eventually zoom to it | ||||
|      * @private | ||||
|      */ | ||||
|     private initialLoad() { | ||||
|         const hash = this.hash.data | ||||
|         if (hash === undefined || hash === "" || hash.indexOf("-") >= 0) { | ||||
|             return | ||||
|         } | ||||
|         if (SelectedFeatureHandler._no_trigger_on.has(hash)) { | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         if (!(hash.startsWith("node") || hash.startsWith("way") || hash.startsWith("relation"))) { | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         this.state.objectDownloader.DownloadObjectAsync(hash).then((obj) => { | ||||
|             try { | ||||
|                 if (obj === "deleted") { | ||||
|                     return | ||||
|                 } | ||||
|                 console.log("Downloaded selected object from OSM-API for initial load: ", hash) | ||||
|                 const geojson = obj.asGeoJson() | ||||
|                 this.state.allElements.addOrGetElement(geojson) | ||||
|                 this.state.selectedElement.setData(geojson) | ||||
|                 this.zoomToSelectedFeature() | ||||
|             } catch (e) { | ||||
|                 console.error(e) | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     private setSelectedElementFromHash() { | ||||
|         const state = this.state | ||||
|         const h = this.hash.data | ||||
|         if (h === undefined || h === "") { | ||||
|             // Hash has been cleared - we clear the selected element
 | ||||
|             state.selectedElement.setData(undefined) | ||||
|         } else { | ||||
|             // we search the element to select
 | ||||
|             const feature = state.allElements.ContainingFeatures.get(h) | ||||
|             if (feature === undefined) { | ||||
|                 return | ||||
|             } | ||||
|             const currentlySelected = state.selectedElement.data | ||||
|             if (currentlySelected === undefined) { | ||||
|                 state.selectedElement.setData(feature) | ||||
|                 return | ||||
|             } | ||||
|             if (currentlySelected.properties?.id === feature.properties.id) { | ||||
|                 // We already have the right feature
 | ||||
|                 return | ||||
|             } | ||||
|             state.selectedElement.setData(feature) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // If a feature is selected via the hash, zoom there
 | ||||
|     private zoomToSelectedFeature() { | ||||
|         const selected = this.state.selectedElement.data | ||||
|         if (selected === undefined) { | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         const centerpoint = GeoOperations.centerpointCoordinates(selected) | ||||
|         const location = this.state.locationControl | ||||
|         location.data.lon = centerpoint[0] | ||||
|         location.data.lat = centerpoint[1] | ||||
| 
 | ||||
|         const minZoom = Math.max( | ||||
|             14, | ||||
|             ...(this.state.layoutToUse?.layers?.map((l) => l.minzoomVisible) ?? []) | ||||
|         ) | ||||
|         if (location.data.zoom < minZoom) { | ||||
|             location.data.zoom = minZoom | ||||
|         } | ||||
| 
 | ||||
|         location.ping() | ||||
|     } | ||||
| } | ||||
|  | @ -286,7 +286,7 @@ export default class LayoutConfig implements LayoutInformation { | |||
| 
 | ||||
|         return { untranslated, total } | ||||
|     } | ||||
|     public getMatchingLayer(tags: any): LayerConfig | undefined { | ||||
|     public getMatchingLayer(tags: Record<string, string>): LayerConfig | undefined { | ||||
|         if (tags === undefined) { | ||||
|             return undefined | ||||
|         } | ||||
|  |  | |||
|  | @ -48,6 +48,7 @@ import { Utils } from "../Utils" | |||
| import { EliCategory } from "./RasterLayerProperties" | ||||
| import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" | ||||
| import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage" | ||||
| import Hash from "../Logic/Web/Hash" | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  | @ -429,6 +430,30 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|      * Setup various services for which no reference are needed | ||||
|      */ | ||||
|     private initActors() { | ||||
|         this.selectedElement.addCallback((selected) => { | ||||
|             Hash.hash.setData(selected?.properties?.id) | ||||
|         }) | ||||
| 
 | ||||
|         Hash.hash.mapD( | ||||
|             (hash) => { | ||||
|                 console.log("Searching for an id:", hash) | ||||
|                 if (this.selectedElement.data?.properties?.id === hash) { | ||||
|                     // We already have the correct hash
 | ||||
|                     return | ||||
|                 } | ||||
| 
 | ||||
|                 const found = this.indexedFeatures.featuresById.data?.get(hash) | ||||
|                 console.log("Found:", found) | ||||
|                 if (!found) { | ||||
|                     return | ||||
|                 } | ||||
|                 const layer = this.layout.getMatchingLayer(found.properties) | ||||
|                 this.selectedElement.setData(found) | ||||
|                 this.selectedLayer.setData(layer) | ||||
|             }, | ||||
|             [this.indexedFeatures.featuresById] | ||||
|         ) | ||||
| 
 | ||||
|         new MetaTagging(this) | ||||
|         new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this) | ||||
|         new ChangeToElementsActor(this.changes, this.featureProperties) | ||||
|  |  | |||
|  | @ -1,16 +1,12 @@ | |||
| import { Utils } from "../../../Utils" | ||||
| import UserRelatedState from "../../../Logic/State/UserRelatedState" | ||||
| import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" | ||||
| import SelectedElementTagsUpdater from "../../../Logic/Actors/SelectedElementTagsUpdater" | ||||
| 
 | ||||
| import * as bookcaseJson from "../../../assets/generated/themes/bookcases.json" | ||||
| import { UIEventSource } from "../../../Logic/UIEventSource" | ||||
| import Loc from "../../../Models/Loc" | ||||
| import SelectedFeatureHandler from "../../../Logic/Actors/SelectedFeatureHandler" | ||||
| import { OsmTags } from "../../../Models/OsmFeature" | ||||
| import { Feature, Geometry } from "geojson" | ||||
| import { expect, it } from "vitest" | ||||
| import ThemeViewState from "../../../Models/ThemeViewState"; | ||||
| import ThemeViewState from "../../../Models/ThemeViewState" | ||||
| 
 | ||||
| const latestTags = { | ||||
|     amenity: "public_bookcase", | ||||
|  | @ -86,27 +82,3 @@ it("should download the latest version", () => { | |||
|     // The fixme should be removed
 | ||||
|     expect(feature.properties.fixme).toBeUndefined() | ||||
| }) | ||||
| it("Hash without selected element should download geojson from OSM-API", async () => { | ||||
|     const hash = new UIEventSource("node/5568693115") | ||||
|     const selected = new UIEventSource(undefined) | ||||
|     const loc = new UIEventSource<Loc>({ | ||||
|         lat: 0, | ||||
|         lon: 0, | ||||
|         zoom: 0, | ||||
|     }) | ||||
| 
 | ||||
|     loc.addCallback((_) => { | ||||
|         expect(selected.data.properties.id).toEqual("node/5568693115") | ||||
|         expect(loc.data.zoom).toEqual(14) | ||||
|         expect(loc.data.lat).toEqual(51.2179199) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     new SelectedFeatureHandler(hash, { | ||||
|         selectedElement: selected, | ||||
|         allElements: new(), | ||||
|         featurePipeline: undefined, | ||||
|         locationControl: loc, | ||||
|         layoutToUse: undefined, | ||||
|     }) | ||||
| }) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue