mapcomplete/UI/InputElement/Helpers/DirectionInput.svelte

68 lines
2.2 KiB
Svelte

<script lang="ts">
import { UIEventSource } from "../../../Logic/UIEventSource"
import type { MapProperties } from "../../../Models/MapProperties"
import { Map as MlMap } from "maplibre-gl"
import { MapLibreAdaptor } from "../../Map/MapLibreAdaptor"
import MaplibreMap from "../../Map/MaplibreMap.svelte"
import ToSvelte from "../../Base/ToSvelte.svelte"
import Svg from "../../../Svg.js"
/**
* A visualisation to pick a direction on a map background.
*/
export let value: UIEventSource<undefined | string>
export let mapProperties: Partial<MapProperties> & {
readonly location: UIEventSource<{ lon: number; lat: number }>
}
let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
let mla = new MapLibreAdaptor(map, mapProperties)
mla.allowMoving.setData(false)
mla.allowZooming.setData(false)
let directionElem: HTMLElement | undefined
$: value.addCallbackAndRunD((degrees) => {
if (directionElem === undefined) {
return
}
directionElem.style.rotate = degrees + "deg"
})
let mainElem: HTMLElement
function onPosChange(x: number, y: number) {
const rect = mainElem.getBoundingClientRect()
const dx = -(rect.left + rect.right) / 2 + x
const dy = (rect.top + rect.bottom) / 2 - y
const angle = (180 * Math.atan2(dy, dx)) / Math.PI
const angleGeo = Math.floor((450 - angle) % 360)
value.setData("" + angleGeo)
}
let isDown = false
</script>
<div
bind:this={mainElem}
class="relative h-48 w-48 cursor-pointer overflow-hidden"
on:click={(e) => onPosChange(e.x, e.y)}
on:mousedown={(e) => {
isDown = true
onPosChange(e.clientX, e.clientY)
}}
on:mousemove={(e) => {
if (isDown) {
onPosChange(e.clientX, e.clientY)
}
}}
on:mouseup={() => {
isDown = false
}}
on:touchmove={(e) => onPosChange(e.touches[0].clientX, e.touches[0].clientY)}
on:touchstart={(e) => onPosChange(e.touches[0].clientX, e.touches[0].clientY)}
>
<div class="absolute top-0 left-0 h-full w-full cursor-pointer">
<MaplibreMap {map} attribution={false} />
</div>
<div bind:this={directionElem} class="absolute top-0 left-0 h-full w-full">
<ToSvelte construct={Svg.direction_stroke_svg} />
</div>
</div>