From 78c56f6fa2745fd57baae183420aa2fc36919df1 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 24 Apr 2023 02:54:15 +0200 Subject: [PATCH] Refactoring: save ID to the hash of the URL --- Logic/Actors/SelectedFeatureHandler.ts | 133 ------------------------- Models/ThemeConfig/LayoutConfig.ts | 2 +- Models/ThemeViewState.ts | 25 +++++ test/Logic/Actors/Actors.spec.ts | 30 +----- 4 files changed, 27 insertions(+), 163 deletions(-) delete mode 100644 Logic/Actors/SelectedFeatureHandler.ts diff --git a/Logic/Actors/SelectedFeatureHandler.ts b/Logic/Actors/SelectedFeatureHandler.ts deleted file mode 100644 index 3d30a9ca1..000000000 --- a/Logic/Actors/SelectedFeatureHandler.ts +++ /dev/null @@ -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 - private readonly state: { - selectedElement: UIEventSource - allElements: ElementStorage - locationControl: UIEventSource - layoutToUse: LayoutConfig - objectDownloader: OsmObjectDownloader - } - - constructor( - hash: UIEventSource, - state: { - selectedElement: UIEventSource - allElements: ElementStorage - featurePipeline: FeaturePipeline - locationControl: UIEventSource - 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() - } -} diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index c55eb9536..840ef60ee 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -286,7 +286,7 @@ export default class LayoutConfig implements LayoutInformation { return { untranslated, total } } - public getMatchingLayer(tags: any): LayerConfig | undefined { + public getMatchingLayer(tags: Record): LayerConfig | undefined { if (tags === undefined) { return undefined } diff --git a/Models/ThemeViewState.ts b/Models/ThemeViewState.ts index de712afd0..bad56a3bb 100644 --- a/Models/ThemeViewState.ts +++ b/Models/ThemeViewState.ts @@ -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) diff --git a/test/Logic/Actors/Actors.spec.ts b/test/Logic/Actors/Actors.spec.ts index a1a435426..419dd0be1 100644 --- a/test/Logic/Actors/Actors.spec.ts +++ b/test/Logic/Actors/Actors.spec.ts @@ -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({ - 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, - }) -})