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 } |         return { untranslated, total } | ||||||
|     } |     } | ||||||
|     public getMatchingLayer(tags: any): LayerConfig | undefined { |     public getMatchingLayer(tags: Record<string, string>): LayerConfig | undefined { | ||||||
|         if (tags === undefined) { |         if (tags === undefined) { | ||||||
|             return undefined |             return undefined | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ import { Utils } from "../Utils" | ||||||
| import { EliCategory } from "./RasterLayerProperties" | import { EliCategory } from "./RasterLayerProperties" | ||||||
| import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" | import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" | ||||||
| import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage" | 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 |      * Setup various services for which no reference are needed | ||||||
|      */ |      */ | ||||||
|     private initActors() { |     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 MetaTagging(this) | ||||||
|         new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this) |         new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this) | ||||||
|         new ChangeToElementsActor(this.changes, this.featureProperties) |         new ChangeToElementsActor(this.changes, this.featureProperties) | ||||||
|  |  | ||||||
|  | @ -1,16 +1,12 @@ | ||||||
| import { Utils } from "../../../Utils" | import { Utils } from "../../../Utils" | ||||||
| import UserRelatedState from "../../../Logic/State/UserRelatedState" |  | ||||||
| import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" | import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" | ||||||
| import SelectedElementTagsUpdater from "../../../Logic/Actors/SelectedElementTagsUpdater" | import SelectedElementTagsUpdater from "../../../Logic/Actors/SelectedElementTagsUpdater" | ||||||
| 
 | 
 | ||||||
| import * as bookcaseJson from "../../../assets/generated/themes/bookcases.json" | 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 { OsmTags } from "../../../Models/OsmFeature" | ||||||
| import { Feature, Geometry } from "geojson" | import { Feature, Geometry } from "geojson" | ||||||
| import { expect, it } from "vitest" | import { expect, it } from "vitest" | ||||||
| import ThemeViewState from "../../../Models/ThemeViewState"; | import ThemeViewState from "../../../Models/ThemeViewState" | ||||||
| 
 | 
 | ||||||
| const latestTags = { | const latestTags = { | ||||||
|     amenity: "public_bookcase", |     amenity: "public_bookcase", | ||||||
|  | @ -86,27 +82,3 @@ it("should download the latest version", () => { | ||||||
|     // The fixme should be removed
 |     // The fixme should be removed
 | ||||||
|     expect(feature.properties.fixme).toBeUndefined() |     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