import { InputElement } from "./InputElement" import { UIEventSource } from "../../Logic/UIEventSource" import Combine from "../Base/Combine" import Svg from "../../Svg" import BaseUIElement from "../BaseUIElement" import { FixedUiElement } from "../Base/FixedUiElement" import { Utils } from "../../Utils" import Loc from "../../Models/Loc" import Minimap from "../Base/Minimap" /** * Selects a direction in degrees */ export default class DirectionInput extends InputElement { public readonly IsSelected: UIEventSource = new UIEventSource(false) private readonly _location: UIEventSource private readonly value: UIEventSource private background constructor( mapBackground: UIEventSource, location: UIEventSource, value?: UIEventSource ) { super() this._location = location this.value = value ?? new UIEventSource(undefined) this.background = mapBackground } GetValue(): UIEventSource { return this.value } IsValid(str: string): boolean { const t = Number(str) return !isNaN(t) && t >= 0 && t <= 360 } protected InnerConstructElement(): HTMLElement { let map: BaseUIElement = new FixedUiElement("") if (!Utils.runningFromConsole) { map = Minimap.createMiniMap({ background: this.background, allowMoving: false, location: this._location, }) } const element = new Combine([ Svg.direction_stroke_svg() .SetStyle( `position: absolute;top: 0;left: 0;width: 100%;height: 100%;transform:rotate(${ this.value.data ?? 0 }deg);` ) .SetClass("direction-svg relative") .SetStyle("z-index: 1000"), map.SetStyle(`position: absolute;top: 0;left: 0;width: 100%;height: 100%;`), ]) .SetStyle("width: min(100%, 25em); height: 0; padding-bottom: 100%") // A bit a weird CSS , see https://stackoverflow.com/questions/13851940/pure-css-solution-square-elements#19448481 .SetClass("relative block bg-white border border-black overflow-hidden rounded-full") .ConstructElement() this.value.addCallbackAndRunD((rotation) => { const cone = element.getElementsByClassName("direction-svg")[0] as HTMLElement cone.style.transform = `rotate(${rotation}deg)` }) this.RegisterTriggers(element) element.style.overflow = "hidden" element.style.display = "block" return element } private RegisterTriggers(htmlElement: HTMLElement) { const self = this function onPosChange(x: number, y: number) { const rect = htmlElement.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) self.value.setData("" + angleGeo) } htmlElement.ontouchmove = (ev: TouchEvent) => { onPosChange(ev.touches[0].clientX, ev.touches[0].clientY) ev.preventDefault() } htmlElement.ontouchstart = (ev: TouchEvent) => { onPosChange(ev.touches[0].clientX, ev.touches[0].clientY) } let isDown = false htmlElement.onmousedown = (ev: MouseEvent) => { isDown = true onPosChange(ev.clientX, ev.clientY) ev.preventDefault() } htmlElement.onmouseup = (ev) => { isDown = false ev.preventDefault() } htmlElement.onmousemove = (ev: MouseEvent) => { if (isDown) { onPosChange(ev.clientX, ev.clientY) } ev.preventDefault() } } }