Better compass arrow

This commit is contained in:
Pieter Vander Vennet 2023-12-18 01:30:02 +01:00
parent ba47d1bfad
commit 82409984dc
15 changed files with 219 additions and 114 deletions

View file

@ -12,11 +12,12 @@
export let arialabel: Translation = undefined
</script>
<button
on:click={(e) => dispatch("click", e)}
on:keydown
use:ariaLabel={arialabel}
class={twJoin("pointer-events-auto h-fit w-fit rounded-full", cls)}
class={twJoin("relative pointer-events-auto h-fit w-fit rounded-full", cls)}
>
<slot />
</button>

View file

@ -0,0 +1,44 @@
<script lang="ts">
import Crosshair from "../../assets/svg/Crosshair.svelte"
import Location_refused from "../../assets/svg/Location_refused.svelte"
import { Store } from "../../Logic/UIEventSource.js"
import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState.js"
import ThemeViewState from "../../Models/ThemeViewState"
import Location_locked from "../../assets/svg/Location_locked.svelte"
import Location_unlocked from "../../assets/svg/Location_unlocked.svelte"
import Location from "../../assets/svg/Location.svelte"
export let state: ThemeViewState
let geolocationstate = state.geolocation.geolocationState
let geopermission: Store<GeolocationPermissionState> = state.geolocation.geolocationState.permission
let allowMoving = geolocationstate.allowMoving
let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation
let geolocationControlState = state.geolocationControl
let lastClickWasRecent = geolocationControlState.lastClickWithinThreeSecs
</script>
{#if !$allowMoving}
<Location_locked class="h-8 w-8" />
{:else if $currentGPSLocation !== undefined }
<!-- If we have a location; this implies that the location access was granted -->
{#if $lastClickWasRecent}
<Location_unlocked class="h-8 w-8" />
{:else}
<Location class="h-8 w-8" />
{/if}
{:else if $geopermission === "prompt"}
<Location class="h-8 w-8" />
{:else if $geopermission === "requested"}
<!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup -->
<Location
class="h-8 w-8"
style="animation: 3s linear 0s infinite normal none running spin;"
/>
{:else if $geopermission === "denied"}
<Location_refused class="h-8 w-8" />
{:else}
<Location
class="h-8 w-8"
style="animation: 3s linear 0s infinite normal none running spin;"
/>
{/if}

View file

@ -1,9 +1,5 @@
import { VariableUiElement } from "../Base/VariableUIElement"
import Svg from "../../Svg"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import Hotkeys from "../Base/Hotkeys"
import Translations from "../i18n/Translations"
import Constants from "../../Models/Constants"
import { MapProperties } from "../../Models/MapProperties"
@ -11,11 +7,12 @@ import { MapProperties } from "../../Models/MapProperties"
* Displays an icon depending on the state of the geolocation.
* Will set the 'lock' if clicked twice
*/
export class GeolocationControl extends VariableUiElement {
export class GeolocationControlState {
public readonly lastClick = new UIEventSource<Date>(undefined)
public readonly lastClickWithinThreeSecs: Store<boolean>
private readonly _geolocationHandler: GeoLocationHandler
private readonly _mapProperties: MapProperties
private readonly _lastClickWithinThreeSecs: Store<boolean>
constructor(
geolocationHandler: GeoLocationHandler,
state: MapProperties,
@ -41,60 +38,12 @@ export class GeolocationControl extends VariableUiElement {
return timeDiff <= Constants.zoomToLocationTimeout
}
)
const geolocationState = geolocationHandler?.geolocationState
super(
geolocationState?.permission?.map(
(permission) => {
if (permission === "denied") {
return Svg.location_refused_svg()
}
if (!geolocationState.allowMoving.data) {
return Svg.location_locked_svg()
}
if (geolocationState.currentGPSLocation.data === undefined) {
if (permission === "prompt") {
return Svg.location_empty_svg()
}
// Position not yet found, but permission is either requested or granted: we spin to indicate activity
const icon =
!geolocationHandler.mapHasMoved.data || lastRequestWithinTimeout.data
? Svg.location_svg()
: Svg.location_empty_svg()
return icon
.SetClass("cursor-wait")
.SetStyle("animation: spin 4s linear infinite;")
}
// We have a location, so we show a dot in the center
if (lastClickWithinThreeSecs.data) {
return Svg.location_unlocked_svg()
}
// We have a location, so we show a dot in the center
return Svg.location_svg()
},
[
geolocationState.currentGPSLocation,
geolocationState.allowMoving,
geolocationHandler.mapHasMoved,
lastClickWithinThreeSecs,
lastRequestWithinTimeout,
]
)
)
this._geolocationHandler = geolocationHandler
this._mapProperties = state
this.lastClick = lastClick
this._lastClickWithinThreeSecs = lastClickWithinThreeSecs
this.onClick(() => this.handleClick())
Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () => {
this.handleClick()
})
this.lastClickWithinThreeSecs = lastClickWithinThreeSecs
lastClick.addCallbackAndRunD((_) => {
window.setTimeout(() => {
@ -148,7 +97,7 @@ export class GeolocationControl extends VariableUiElement {
state.zoom.update((z) => z + 3)
}
if (this._lastClickWithinThreeSecs.data) {
if (this.lastClickWithinThreeSecs.data) {
geolocationState.allowMoving.setData(false)
lastClick.setData(undefined)
return

View file

@ -6,7 +6,6 @@
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 SelectedElementView from "./BigComponents/SelectedElementView.svelte"
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
@ -65,6 +64,8 @@
import ImageOperations from "./Image/ImageOperations.svelte"
import VisualFeedbackPanel from "./BigComponents/VisualFeedbackPanel.svelte"
import { Orientation } from "../Logic/Web/Orientation"
import GeolocationControl from "./BigComponents/GeolocationControl.svelte"
import Compass_arrow from "../assets/svg/Compass_arrow.svelte"
export let state: ThemeViewState
let layout = state.layout
@ -111,8 +112,6 @@
)
let previewedImage = state.previewedImage
let geolocationControl = new GeolocationControl(state.geolocation, mapproperties, state.lastGeolocationRequestMoment)
function forwardEventToMap(e: KeyboardEvent) {
const mlmap = state.map.data
if (!mlmap) {
@ -262,27 +261,20 @@
<Min class="h-8 w-8" />
</MapControlButton>
<If condition={featureSwitches.featureSwitchGeolocation}>
<div class="relative m-0.5 h-12 w-12 p-0 sm:p-1 md:m-1">
<div class="relative m-0.5 md:m-1">
<MapControlButton arialabel={Translations.t.general.labels.jumpToLocation}
on:click={() => state.geolocationControl.handleClick()}
on:keydown={forwardEventToMap}
>
<GeolocationControl {state} /> <!-- h-8 w-8 + p-0.5 sm:p-1 + 2px border => 9 sm: 10 in total-->
</MapControlButton>
{#if $compassLoaded}
<div class="absolute top-1/2 left-1/2 w-0 h-0">
<div class="w-5 h-5"
style={`rotate: calc(${-$compass}deg + 225deg); transform-origin: 0% 0%; background: var(--button-background);`} />
<div class="absolute top-0 left-0 w-0 h-0 m-0.5 sm:m-1">
<Compass_arrow class="compass_arrow" style={`rotate: calc(${-$compass}deg + 225deg); transform-origin: 50% 50%;`} />
</div>
{/if}
<div class="absolute top-0 left-0 p-0.5 md:p-1">
<MapControlButton arialabel={Translations.t.general.labels.jumpToLocation}
cls="m-0 p-0.5 sm:p-1"
on:click={() => geolocationControl.handleClick()}
on:keydown={forwardEventToMap}
>
<ToSvelte
construct={geolocationControl.SetClass("block w-8 h-8")}
/>
</MapControlButton>
</div>
</div>
</If>
</div>