Refactoring: add current view button

This commit is contained in:
Pieter Vander Vennet 2023-05-05 01:25:37 +02:00
parent dec4296204
commit 2149fc1a1d
3 changed files with 266 additions and 256 deletions

View file

@ -1,27 +1,23 @@
import LayoutConfig from "./ThemeConfig/LayoutConfig"
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
import { Changes } from "../Logic/Osm/Changes"
import { ImmutableStore, Store, UIEventSource } from "../Logic/UIEventSource"
import {
FeatureSource,
IndexedFeatureSource,
WritableFeatureSource,
} from "../Logic/FeatureSource/FeatureSource"
import { OsmConnection } from "../Logic/Osm/OsmConnection"
import { ExportableMap, MapProperties } from "./MapProperties"
import {SpecialVisualizationState} from "../UI/SpecialVisualization"
import {Changes} from "../Logic/Osm/Changes"
import {ImmutableStore, Store, UIEventSource} from "../Logic/UIEventSource"
import {FeatureSource, IndexedFeatureSource, WritableFeatureSource,} from "../Logic/FeatureSource/FeatureSource"
import {OsmConnection} from "../Logic/Osm/OsmConnection"
import {ExportableMap, MapProperties} from "./MapProperties"
import LayerState from "../Logic/State/LayerState"
import { Feature, Point } from "geojson"
import {Feature, Point, Polygon} from "geojson"
import FullNodeDatabaseSource from "../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
import { Map as MlMap } from "maplibre-gl"
import {Map as MlMap} from "maplibre-gl"
import InitialMapPositioning from "../Logic/Actors/InitialMapPositioning"
import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor"
import { GeoLocationState } from "../Logic/State/GeoLocationState"
import {MapLibreAdaptor} from "../UI/Map/MapLibreAdaptor"
import {GeoLocationState} from "../Logic/State/GeoLocationState"
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
import { QueryParameters } from "../Logic/Web/QueryParameters"
import {QueryParameters} from "../Logic/Web/QueryParameters"
import UserRelatedState from "../Logic/State/UserRelatedState"
import LayerConfig from "./ThemeConfig/LayerConfig"
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers"
import {AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils} from "./RasterLayers"
import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource"
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"
import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"
@ -32,20 +28,20 @@ import TitleHandler from "../Logic/Actors/TitleHandler"
import ChangeToElementsActor from "../Logic/Actors/ChangeToElementsActor"
import PendingChangesUploader from "../Logic/Actors/PendingChangesUploader"
import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater"
import { BBox } from "../Logic/BBox"
import {BBox} from "../Logic/BBox"
import Constants from "./Constants"
import Hotkeys from "../UI/Base/Hotkeys"
import Translations from "../UI/i18n/Translations"
import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore"
import { LastClickFeatureSource } from "../Logic/FeatureSource/Sources/LastClickFeatureSource"
import { MenuState } from "./MenuState"
import {GeoIndexedStoreForLayer} from "../Logic/FeatureSource/Actors/GeoIndexedStore"
import {LastClickFeatureSource} from "../Logic/FeatureSource/Sources/LastClickFeatureSource"
import {MenuState} from "./MenuState"
import MetaTagging from "../Logic/MetaTagging"
import ChangeGeometryApplicator from "../Logic/FeatureSource/Sources/ChangeGeometryApplicator"
import { NewGeometryFromChangesFeatureSource } from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
import {NewGeometryFromChangesFeatureSource} from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader"
import ShowOverlayRasterLayer from "../UI/Map/ShowOverlayRasterLayer"
import { Utils } from "../Utils"
import { EliCategory } from "./RasterLayerProperties"
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"
@ -80,6 +76,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
readonly currentView: FeatureSource<Feature<Polygon>>
readonly featuresInView: FeatureSource
readonly newFeatures: WritableFeatureSource
readonly layerState: LayerState
@ -169,6 +166,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
(id) => self.layerState.filteredLayers.get(id).isDisplayed
)
this.indexedFeatures = layoutSource
const empty = []
this.currentView = new StaticFeatureSource(
this.mapProperties.bounds.map((bbox) =>
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "current_view" })]
)
)
this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds)
this.dataIsLoading = layoutSource.isLoading
@ -447,11 +450,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })]
)
),
current_view: new StaticFeatureSource(
this.mapProperties.bounds.map((bbox) =>
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "current_view" })]
)
),
current_view: this.currentView
}
if (this.layout?.lockLocation) {
const bbox = new BBox(this.layout.lockLocation)

View file

@ -1,22 +1,22 @@
<script lang="ts">
import { UIEventSource } from "../Logic/UIEventSource";
import { Map as MlMap } from "maplibre-gl";
import {UIEventSource} from "../Logic/UIEventSource";
import {Map as MlMap} from "maplibre-gl";
import MaplibreMap from "./Map/MaplibreMap.svelte";
import FeatureSwitchState from "../Logic/State/FeatureSwitchState";
import MapControlButton from "./Base/MapControlButton.svelte";
import ToSvelte from "./Base/ToSvelte.svelte";
import If from "./Base/If.svelte";
import { GeolocationControl } from "./BigComponents/GeolocationControl";
import type { Feature } from "geojson";
import {GeolocationControl} from "./BigComponents/GeolocationControl";
import type {Feature} from "geojson";
import SelectedElementView from "./BigComponents/SelectedElementView.svelte";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import Filterview from "./BigComponents/Filterview.svelte";
import RasterLayerPicker from "./Map/RasterLayerPicker.svelte";
import ThemeViewState from "../Models/ThemeViewState";
import type { MapProperties } from "../Models/MapProperties";
import type {MapProperties} from "../Models/MapProperties";
import Geosearch from "./BigComponents/Geosearch.svelte";
import Translations from "./i18n/Translations";
import { CogIcon, EyeIcon, MenuIcon } from "@rgossiaux/svelte-heroicons/solid";
import {CogIcon, EyeIcon, MenuIcon} from "@rgossiaux/svelte-heroicons/solid";
import Tr from "./Base/Tr.svelte";
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte";
import FloatOver from "./Base/FloatOver.svelte";
@ -27,14 +27,15 @@
import LoginToggle from "./Base/LoginToggle.svelte";
import LoginButton from "./Base/LoginButton.svelte";
import CopyrightPanel from "./BigComponents/CopyrightPanel";
import { DownloadPanel } from "./BigComponents/DownloadPanel";
import {DownloadPanel} from "./BigComponents/DownloadPanel";
import ModalRight from "./Base/ModalRight.svelte";
import { Utils } from "../Utils";
import {Utils} from "../Utils";
import Hotkeys from "./Base/Hotkeys";
import { VariableUiElement } from "./Base/VariableUIElement";
import {VariableUiElement} from "./Base/VariableUIElement";
import SvelteUIElement from "./Base/SvelteUIElement";
import OverlayToggle from "./BigComponents/OverlayToggle.svelte";
import LevelSelector from "./BigComponents/LevelSelector.svelte";
import Svg from "../Svg";
export let state: ThemeViewState;
let layout = state.layout;
@ -53,7 +54,7 @@
}
const tags = state.featureProperties.getStore(selectedElement.properties.id);
return new SvelteUIElement(SelectedElementView, { state, layer, selectedElement, tags });
return new SvelteUIElement(SelectedElementView, {state, layer, selectedElement, tags});
}, [selectedLayer]);
@ -61,6 +62,7 @@
let featureSwitches: FeatureSwitchState = state.featureSwitches;
let availableLayers = state.availableLayers;
let userdetails = state.osmConnection.userDetails;
let currentViewLayer = layout.layers.find(l => l.id === "current_view")
</script>
@ -88,6 +90,13 @@
<MapControlButton on:click={() =>state.guistate.menuIsOpened.setData(true)}>
<MenuIcon class="w-8 h-8 cursor-pointer"></MenuIcon>
</MapControlButton>
{#if currentViewLayer?.tagRenderings}
<MapControlButton
on:click={() => {selectedLayer.setData(currentViewLayer); selectedElement.setData(state.currentView.features?.data?.[0])}}>
<ToSvelte
construct={() =>(currentViewLayer.defaultIcon() ?? Svg.checkbox_empty_svg()).SetClass("w-8 h-8 cursor-pointer")}/>
</MapControlButton>
{/if}
<If condition={state.featureSwitchIsTesting}>
<span class="alert">
Testmode
@ -108,10 +117,10 @@
</div>
</If>
<MapControlButton on:click={() => mapproperties.zoom.update(z => z+1)}>
<img src="./assets/svg/plus.svg" class="w-8 h-8"/>
<img class="w-8 h-8" src="./assets/svg/plus.svg"/>
</MapControlButton>
<MapControlButton on:click={() => mapproperties.zoom.update(z => z-1)}>
<img src="./assets/svg/min.svg" class="w-8 h-8"/>
<img class="w-8 h-8" src="./assets/svg/min.svg"/>
</MapControlButton>
<If condition={featureSwitches.featureSwitchGeolocation}>
<MapControlButton>
@ -137,15 +146,15 @@
<!-- Theme page -->
<FloatOver on:close={() => state.guistate.themeIsOpened.setData(false)}>
<TabbedGroup tab={state.guistate.themeViewTabIndex}>
<Tr slot="title0" t={layout.title} />
<Tr slot="title0" t={layout.title}/>
<div slot="content0">
<Tr t={layout.description}></Tr>
<Tr t={Translations.t.general.welcomeExplanation.general} />
<Tr t={Translations.t.general.welcomeExplanation.general}/>
{#if layout.layers.some((l) => l.presets?.length > 0)}
<If condition={state.featureSwitches.featureSwitchAddNew}>
<Tr t={Translations.t.general.welcomeExplanation.addNew} />
<Tr t={Translations.t.general.welcomeExplanation.addNew}/>
</If>
{/if}
@ -156,7 +165,7 @@
<div class="m-x-8">
<button class="subtle-background rounded w-full p-4"
on:click={() => state.guistate.themeIsOpened.setData(false)}>
<Tr t={Translations.t.general.openTheMap} />
<Tr t={Translations.t.general.openTheMap}/>
</button>
</div>
@ -165,13 +174,14 @@
<div class="flex" slot="title1">
<If condition={state.featureSwitches.featureSwitchFilter}>
<img class="w-4 h-4" src="./assets/svg/filter.svg">
<Tr t={Translations.t.general.menu.filter} />
<Tr t={Translations.t.general.menu.filter}/>
</If>
</div>
<div class="flex flex-col" slot="content1">
{#each layout.layers as layer}
<Filterview zoomlevel={state.mapProperties.zoom} filteredLayer={state.layerState.filteredLayers.get(layer.id)}
<Filterview zoomlevel={state.mapProperties.zoom}
filteredLayer={state.layerState.filteredLayers.get(layer.id)}
highlightedLayer={state.guistate.highlightedLayerInFilters}></Filterview>
{/each}
{#each layout.tileLayerSources as tilesource}
@ -188,16 +198,16 @@
</div>
<div class="flex" slot="title2">
<If condition={state.featureSwitches.featureSwitchEnableExport}>
<img class="w-4 h-4" src="./assets/svg/download.svg" />
<Tr t={Translations.t.general.download.title} />
<img class="w-4 h-4" src="./assets/svg/download.svg"/>
<Tr t={Translations.t.general.download.title}/>
</If>
</div>
<div slot="content2">
<ToSvelte construct={() => new DownloadPanel(state)} />
<ToSvelte construct={() => new DownloadPanel(state)}/>
</div>
<div slot="title3">
<Tr t={Translations.t.general.attribution.title} />
<Tr t={Translations.t.general.attribution.title}/>
</div>
<ToSvelte construct={() => new CopyrightPanel(state)} slot="content3"></ToSvelte>
@ -213,37 +223,37 @@
<FloatOver on:close={() => state.guistate.menuIsOpened.setData(false)}>
<TabbedGroup tab={state.guistate.menuViewTabIndex}>
<div class="flex" slot="title0">
<Tr t={Translations.t.general.menu.aboutMapComplete} />
<Tr t={Translations.t.general.menu.aboutMapComplete}/>
</div>
<div class="flex flex-col" slot="content0">
<Tr t={Translations.t.general.aboutMapComplete.intro} />
<Tr t={Translations.t.general.aboutMapComplete.intro}/>
<a class="flex" href={Utils.HomepageLink()}>
<img class="w-6 h-6" src="./assets/svg/add.svg">
<Tr t={Translations.t.general.backToIndex} />
<Tr t={Translations.t.general.backToIndex}/>
</a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
<img class="w-6 h-6" src="./assets/svg/bug.svg">
<Tr t={Translations.t.general.attribution.openIssueTracker} />
<Tr t={Translations.t.general.attribution.openIssueTracker}/>
</a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
<img class="w-6 h-6" src="./assets/svg/mastodon.svg">
<Tr t={Translations.t.general.attribution.followOnMastodon} />
<Tr t={Translations.t.general.attribution.followOnMastodon}/>
</a>
<a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank">
<img class="w-6 h-6" src="./assets/svg/liberapay.svg">
<Tr t={Translations.t.general.attribution.donate} />
<Tr t={Translations.t.general.attribution.donate}/>
</a>
<a class="flex" href={Utils.OsmChaLinkFor(7)} target="_blank">
<img class="w-6 h-6" src="./assets/svg/statistics.svg">
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({theme: "MapComplete"})} />
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({theme: "MapComplete"})}/>
</a>
{Constants.vNumber}
<ToSvelte construct={Hotkeys.generateDocumentationDynamic}></ToSvelte>
@ -252,8 +262,8 @@
<If condition={state.osmConnection.isLoggedIn} slot="title1">
<div class="flex">
<CogIcon class="w-6 h-6" />
<Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})} />
<CogIcon class="w-6 h-6"/>
<Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})}/>
</div>
</If>
@ -261,7 +271,7 @@
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
<LoginToggle {state}>
<div slot="not-logged-in">
<Tr class="alert" t={Translations.t.userinfo.notLoggedIn} />
<Tr class="alert" t={Translations.t.userinfo.notLoggedIn}/>
<LoginButton osmConnection={state.osmConnection}></LoginButton>
</div>
<SelectedElementView
@ -282,7 +292,7 @@
<CommunityIndexView location={state.mapProperties.location} slot="content2"></CommunityIndexView>
<div class="flex" slot="title3">
<EyeIcon class="w-6" />
<EyeIcon class="w-6"/>
<Tr t={Translations.t.privacy.title}></Tr>
</div>
<ToSvelte construct={() => new PrivacyPolicy()} slot="content3"></ToSvelte>

View file

@ -1,10 +1,11 @@
{
"id": "current_view",
"description": "A meta-layer which contains one single feature, namely the BBOX of the current map view. This can be used to trigger special actions. If a popup is defined for this layer, this popup will be accessible via an extra button on screen.\n\nThe icon on the button is the default icon of the layer, but can be customized by detecting 'button=yes'.",
"description": "A meta-layer which contains one single feature, namely the bounding box of the current map view. This can be used to trigger special actions. If a popup is defined for this layer, this popup will be accessible via an extra button on screen.\n\nThe icon on the button is the default icon of the layer, but can be customized by detecting 'button=yes'.",
"source": "special",
"shownByDefault": false,
"title": "Current View",
"tagRenderings": [],
"popupInFloatover": true,
"mapRendering": [
{
"color": "#cccc0088"