diff --git a/Logic/Actors/SelectedFeatureHandler.ts b/Logic/Actors/SelectedFeatureHandler.ts index e366a783ae..2e68a354bd 100644 --- a/Logic/Actors/SelectedFeatureHandler.ts +++ b/Logic/Actors/SelectedFeatureHandler.ts @@ -40,6 +40,10 @@ export default class SelectedFeatureHandler { if(features === undefined){ return; } + if(this._selectedFeature.data?.properties?.id === this._hash.data){ + // Feature already selected + return; + } for (const feature of features) { const id = feature.feature?.properties?.id; if(id === this._hash.data){ diff --git a/UI/Base/LazyElement.ts b/UI/Base/LazyElement.ts index 90b353a7d8..40555d1f36 100644 --- a/UI/Base/LazyElement.ts +++ b/UI/Base/LazyElement.ts @@ -1,24 +1,21 @@ import {UIElement} from "../UIElement"; -export default class LazyElement extends UIElement { +export default class LazyElement extends UIElement { - public Activate: (onElement?: (element: T) => void) => void; - private _content: T = undefined; + public Activate: () => void; + private _content: UIElement = undefined; private readonly _loadingContent: string; - constructor(content: (() => T), loadingContent = "Rendering...") { + constructor(content: (() => UIElement), loadingContent = "Rendering...") { super(); this._loadingContent = loadingContent; this.dumbMode = false; const self = this; - this.Activate = (onElement?: (element: T) => void) => { + this.Activate = () => { if (this._content === undefined) { self._content = content(); } - if (onElement) { - onElement(self._content) - } self.Update(); } } diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index d365ca25bb..965876e44d 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -12,7 +12,7 @@ import ScrollableFullScreen from "../Base/ScrollableFullScreen"; export default class FeatureInfoBox extends UIElement { private _component: ScrollableFullScreen; - constructor( + private constructor( tags: UIEventSource, layerConfig: LayerConfig, onClose: () => void @@ -75,6 +75,21 @@ export default class FeatureInfoBox extends UIElement { } - + + private static featureInfoboxCache : Map, FeatureInfoBox>> = new Map, FeatureInfoBox>>(); + static construct(tags: UIEventSource, layer: LayerConfig, onClose: () => void) { + let innerMap = FeatureInfoBox.featureInfoboxCache.get(layer); + if(innerMap === undefined){ + innerMap = new Map, FeatureInfoBox>(); + FeatureInfoBox.featureInfoboxCache.set(layer, innerMap); + } + + let featureInfoBox = innerMap.get(tags); + if(featureInfoBox === undefined){ + featureInfoBox = new FeatureInfoBox(tags, layer, onClose); + innerMap.set(tags, featureInfoBox); + } + return featureInfoBox; + } } diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index 515bbb80b5..b538858acd 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -43,7 +43,7 @@ export default class TagRenderingQuestion extends UIElement { this._tags = tags; this._configuration = configuration; this._cancelButton = cancelButton; - this._question = new SubstitutedTranslation(this._configuration.question, tags) + this._question = SubstitutedTranslation.construct(this._configuration.question, tags) .SetClass("question-text"); if (configuration === undefined) { throw "A question is needed for a question visualization" diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index ad27c64559..24c416c04b 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -7,12 +7,8 @@ import "leaflet.markercluster" import LayerConfig from "../Customizations/JSON/LayerConfig"; import State from "../State"; import LazyElement from "./Base/LazyElement"; -import Hash from "../Logic/Web/Hash"; -import {GeoOperations} from "../Logic/GeoOperations"; import FeatureInfoBox from "./Popup/FeatureInfoBox"; import LayoutConfig from "../Customizations/JSON/LayoutConfig"; -import {UIElement} from "./UIElement"; -import Combine from "./Base/Combine"; import ScrollableFullScreen from "./Base/ScrollableFullScreen"; @@ -34,6 +30,18 @@ export default class ShowDataLayer { this._layerDict[layer.id] = layer; } + + function openSelectedElementFeature(feature: any){ + if (feature === undefined) { + return; + } + const id = feature.properties.id + feature.geometry.type + feature._matching_layer_id; + const action = self._onSelectedTrigger[id]; + if (action) { + action(); + } + } + function update() { if (features.data === undefined) { return; @@ -60,21 +68,10 @@ export default class ShowDataLayer { oldGeoLayer = geoLayer; } - features.addCallbackAndRun(() => update()); + features.addCallback(() => update()); leafletMap.addCallback(() => update()); - State.state.selectedElement.addCallback(feature => { - if (feature === undefined) { - return; - } - const id = feature.properties.id + feature.geometry.type + feature._matching_layer_id; - const action = self._onSelectedTrigger[id]; - if (action) { - action(); - } - }); - update(); - + State.state.selectedElement.addCallbackAndRun(openSelectedElementFeature); } @@ -121,12 +118,14 @@ export default class ShowDataLayer { const tags = State.state.allElements.getEventSourceFor(feature); - const uiElement: LazyElement = new LazyElement(() =>new Combine([ new FeatureInfoBox(tags, layer, () => { - State.state.selectedElement.setData(undefined); - popup.remove(); - - })]), - "
Rendering
"); + const uiElement = new LazyElement(() => + FeatureInfoBox.construct(tags, layer, () => { + State.state.selectedElement.setData(undefined); + popup.remove(); + leafletLayer.closePopup(); + ScrollableFullScreen.RestoreLeaflet(); + }), + "
Rendering
"); // By setting 90vh, leaflet will attempt to fit the entire screen and move the feature down popup.setContent(uiElement.Render()); popup.on('remove', () => { ScrollableFullScreen.RestoreLeaflet(); // Just in case... @@ -139,25 +138,21 @@ export default class ShowDataLayer { // We first render the UIelement (which'll still need an update later on...) // But at least it'll be visible already - - leafletLayer.on("click", () => { - // We set the element as selected... - + leafletLayer.on("popupopen", () => { uiElement.Activate(); State.state.selectedElement.setData(feature); - }); - + }) const id = feature.properties.id + feature.geometry.type + feature._matching_layer_id; this._onSelectedTrigger[id] = () => { - if (popup.isOpen()) { + if (!popup.isOpen()) { + leafletLayer.openPopup(); + uiElement.Activate(); return; } - leafletLayer.openPopup(); - uiElement.Activate(); - State.state.selectedElement.setData(feature); } this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id]; + } private CreateGeojsonLayer(features: any[]): L.Layer {