forked from MapComplete/MapComplete
Better compass arrow
This commit is contained in:
parent
ba47d1bfad
commit
82409984dc
15 changed files with 219 additions and 114 deletions
|
|
@ -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>
|
||||
|
|
|
|||
44
src/UI/BigComponents/GeolocationControl.svelte
Normal file
44
src/UI/BigComponents/GeolocationControl.svelte
Normal 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}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue