| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  | import {InputElement} from "./InputElement"; | 
					
						
							|  |  |  | import {UIEventSource} from "../../Logic/UIEventSource"; | 
					
						
							|  |  |  | import Combine from "../Base/Combine"; | 
					
						
							|  |  |  | import Svg from "../../Svg"; | 
					
						
							|  |  |  | import {Utils} from "../../Utils"; | 
					
						
							|  |  |  | import Loc from "../../Models/Loc"; | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  | import {GeoOperations} from "../../Logic/GeoOperations"; | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | import Minimap from "../Base/Minimap"; | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Selects a length after clicking on the minimap, in meters | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export default class LengthInput extends InputElement<string> { | 
					
						
							|  |  |  |     public readonly IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false); | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |     private readonly _location: UIEventSource<Loc>; | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |     private readonly value: UIEventSource<string>; | 
					
						
							|  |  |  |     private background; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |     constructor(mapBackground: UIEventSource<any>, | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |                 location: UIEventSource<Loc>, | 
					
						
							|  |  |  |                 value?: UIEventSource<string>) { | 
					
						
							|  |  |  |         super(); | 
					
						
							|  |  |  |         this._location = location; | 
					
						
							|  |  |  |         this.value = value ?? new UIEventSource<string>(undefined); | 
					
						
							|  |  |  |         this.background = mapBackground; | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         this.SetClass("block") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GetValue(): UIEventSource<string> { | 
					
						
							|  |  |  |         return this.value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     IsValid(str: string): boolean { | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         const t = Number(str) | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         return !isNaN(t) && t >= 0 && t <= 360; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected InnerConstructElement(): HTMLElement { | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         // @ts-ignore
 | 
					
						
							|  |  |  |         let map = undefined | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         if (!Utils.runningFromConsole) { | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |             map = Minimap.createMiniMap({ | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |                 background: this.background, | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |                 allowMoving: false, | 
					
						
							|  |  |  |                 location: this._location, | 
					
						
							|  |  |  |                 leafletOptions: { | 
					
						
							|  |  |  |                     tap: true | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const element = new Combine([ | 
					
						
							| 
									
										
										
										
											2021-07-20 01:59:19 +02:00
										 |  |  |             new Combine([Svg.length_crosshair_svg().SetStyle( | 
					
						
							|  |  |  |                 `position: absolute;top: 0;left: 0;transform:rotate(${this.value.data ?? 0}deg);`) | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             ]) | 
					
						
							|  |  |  |                 .SetClass("block length-crosshair-svg relative") | 
					
						
							| 
									
										
										
										
											2021-07-20 01:59:19 +02:00
										 |  |  |                 .SetStyle("z-index: 1000; visibility: hidden"), | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             map?.SetClass("w-full h-full block absolute top-0 left-O overflow-hidden"), | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         ]) | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             .SetClass("relative block bg-white border border-black rounded-3xl overflow-hidden") | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             .ConstructElement() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         this.RegisterTriggers(element, map?.leafletMap) | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         element.style.overflow = "hidden" | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         element.style.display = "block" | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return element | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |     private RegisterTriggers(htmlElement: HTMLElement, leafletMap: UIEventSource<L.Map>) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let firstClickXY: [number, number] = undefined | 
					
						
							|  |  |  |         let lastClickXY: [number, number] = undefined | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         function onPosChange(x: number, y: number, isDown: boolean, isUp?: boolean) { | 
					
						
							|  |  |  |             if (x === undefined || y === undefined) { | 
					
						
							|  |  |  |                 // Touch end
 | 
					
						
							|  |  |  |                 firstClickXY = undefined; | 
					
						
							|  |  |  |                 lastClickXY = undefined; | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const rect = htmlElement.getBoundingClientRect(); | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             // From the central part of location
 | 
					
						
							|  |  |  |             const dx = x - rect.left; | 
					
						
							|  |  |  |             const dy = y - rect.top; | 
					
						
							|  |  |  |             if (isDown) { | 
					
						
							|  |  |  |                 if (lastClickXY === undefined && firstClickXY === undefined) { | 
					
						
							|  |  |  |                     firstClickXY = [dx, dy]; | 
					
						
							|  |  |  |                 } else if (firstClickXY !== undefined && lastClickXY === undefined) { | 
					
						
							|  |  |  |                     lastClickXY = [dx, dy] | 
					
						
							|  |  |  |                 } else if (firstClickXY !== undefined && lastClickXY !== undefined) { | 
					
						
							|  |  |  |                     // we measure again
 | 
					
						
							|  |  |  |                     firstClickXY = [dx, dy] | 
					
						
							|  |  |  |                     lastClickXY = undefined; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (isUp) { | 
					
						
							|  |  |  |                 const distance = Math.sqrt((dy - firstClickXY[1]) * (dy - firstClickXY[1]) + (dx - firstClickXY[0]) * (dx - firstClickXY[0])) | 
					
						
							|  |  |  |                 if (distance > 15) { | 
					
						
							|  |  |  |                     lastClickXY = [dx, dy] | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             } else if (lastClickXY !== undefined) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const measurementCrosshair = htmlElement.getElementsByClassName("length-crosshair-svg")[0] as HTMLElement | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             const measurementCrosshairInner: HTMLElement = <HTMLElement>measurementCrosshair.firstChild | 
					
						
							|  |  |  |             if (firstClickXY === undefined) { | 
					
						
							|  |  |  |                 measurementCrosshair.style.visibility = "hidden" | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 measurementCrosshair.style.visibility = "unset" | 
					
						
							|  |  |  |                 measurementCrosshair.style.left = firstClickXY[0] + "px"; | 
					
						
							|  |  |  |                 measurementCrosshair.style.top = firstClickXY[1] + "px" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const angle = 180 * Math.atan2(firstClickXY[1] - dy, firstClickXY[0] - dx) / Math.PI; | 
					
						
							|  |  |  |                 const angleGeo = (angle + 270) % 360 | 
					
						
							|  |  |  |                 measurementCrosshairInner.style.transform = `rotate(${angleGeo}deg)`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const distance = Math.sqrt((dy - firstClickXY[1]) * (dy - firstClickXY[1]) + (dx - firstClickXY[0]) * (dx - firstClickXY[0])) | 
					
						
							|  |  |  |                 measurementCrosshairInner.style.width = (distance * 2) + "px" | 
					
						
							|  |  |  |                 measurementCrosshairInner.style.marginLeft = -distance + "px" | 
					
						
							|  |  |  |                 measurementCrosshairInner.style.marginTop = -distance + "px" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const leaflet = leafletMap?.data | 
					
						
							|  |  |  |                 if (leaflet) { | 
					
						
							|  |  |  |                     const first = leaflet.layerPointToLatLng(firstClickXY) | 
					
						
							|  |  |  |                     const last = leaflet.layerPointToLatLng([dx, dy]) | 
					
						
							| 
									
										
										
										
											2021-07-29 00:29:29 +02:00
										 |  |  |                     const geoDist = Math.floor(GeoOperations.distanceBetween([first.lng, first.lat], [last.lng, last.lat]) * 10000) / 10 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |                     self.value.setData("" + geoDist) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         htmlElement.ontouchstart = (ev: TouchEvent) => { | 
					
						
							|  |  |  |             onPosChange(ev.touches[0].clientX, ev.touches[0].clientY, true); | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             ev.preventDefault(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         htmlElement.ontouchmove = (ev: TouchEvent) => { | 
					
						
							|  |  |  |             onPosChange(ev.touches[0].clientX, ev.touches[0].clientY, false); | 
					
						
							|  |  |  |             ev.preventDefault(); | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |         htmlElement.ontouchend = (ev: TouchEvent) => { | 
					
						
							|  |  |  |             onPosChange(undefined, undefined, false, true); | 
					
						
							|  |  |  |             ev.preventDefault(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         htmlElement.onmousedown = (ev: MouseEvent) => { | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             onPosChange(ev.clientX, ev.clientY, true); | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             ev.preventDefault(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         htmlElement.onmouseup = (ev) => { | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             onPosChange(ev.clientX, ev.clientY, false, true); | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             ev.preventDefault(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         htmlElement.onmousemove = (ev: MouseEvent) => { | 
					
						
							| 
									
										
										
										
											2021-07-20 01:33:58 +02:00
										 |  |  |             onPosChange(ev.clientX, ev.clientY, false); | 
					
						
							| 
									
										
										
										
											2021-07-14 16:06:34 +02:00
										 |  |  |             ev.preventDefault(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |