import { Throttler } from "./Throttler"; import { Coordinate, Position, convertPixelsToCoordinate, convertCoordinateToPixels } from "./coordinates"; import { Size } from "./size"; type ZipCodeReverseResponse = { nr: number | null; navn: string; visueltcenter: number[]; }; async function fetchZipCode({ longitude, latitude, }: Coordinate): Promise { return fetch( `https://api.dataforsyningen.dk/postnumre/reverse?x=${longitude}&y=${latitude}`, ) .then((request) => request.json()) .then((data) => { let zipCode = parseInt(data.nr); return { ...data, nr: isNaN(zipCode) ? null : zipCode, } as ZipCodeReverseResponse; }) .catch(() => null as never); } function displayMousePosition(element: HTMLParagraphElement, mouse: Position) { element.innerHTML = `Mouse position: (${mouse.x}px, ${mouse.y}px)`; } function displayCoords(element: HTMLParagraphElement, coords: Coordinate) { const longitude = coords.longitude.toFixed(3); const latitude = coords.latitude.toFixed(3); element.innerHTML = `Coords: ${longitude}, ${latitude}`; } function displayZipCode( element: HTMLParagraphElement, zipCode: number | null, name: string | null, center: Coordinate | null, ) { element.innerHTML = zipCode === null ? `Postnummer ikke fundet` : `Postnummer: ${zipCode}, ${name}`; if (center == null) return; const dot = document.getElementById("dot")!; if (!zipCode) { dot.style.display = "none"; return; } const mapImg = document.getElementById("map")!; const mapSize: Size = { width: mapImg.clientWidth, height: mapImg.clientHeight, }; const position = convertCoordinateToPixels(center, mapSize); const rect = document.getElementById("map")!.getBoundingClientRect(); dot.style.display = "block"; dot.style.left = (position.x + rect.left) + "px"; dot.style.top = (position.y + rect.top) + "px"; } function setupMap( mousePositionElement: HTMLParagraphElement, coordsElement: HTMLParagraphElement, zipCodeElement: HTMLParagraphElement, ) { const mapImg = document.querySelector("#map")!; const fetcher = new Throttler(500); mapImg.onmousemove = async (event: MouseEvent) => { const mousePosition: Position = { x: event.offsetX, y: event.offsetY }; displayMousePosition(mousePositionElement, mousePosition); const mapSize: Size = { width: mapImg.clientWidth, height: mapImg.clientHeight, }; const coords = convertPixelsToCoordinate(mousePosition, mapSize); displayCoords(coordsElement, coords); fetcher.call(async () => { const response = await fetchZipCode(coords); displayZipCode( zipCodeElement, response.nr, response.navn, response.visueltcenter ? { longitude: response.visueltcenter[0], latitude: response.visueltcenter[1] } : null, ); }); }; mapImg.onmouseup = async (event: MouseEvent) => { const mousePosition: Position = { x: event.offsetX, y: event.offsetY }; displayMousePosition(mousePositionElement, mousePosition); const mapSize: Size = { width: mapImg.clientWidth, height: mapImg.clientHeight, }; const coords = convertPixelsToCoordinate(mousePosition, mapSize); displayCoords(coordsElement, coords); fetcher.call(async () => { const response = await fetchZipCode(coords); displayZipCode( zipCodeElement, response.nr, response.navn, response.visueltcenter ? { longitude: response.visueltcenter[0], latitude: response.visueltcenter[1] } : null, ); }); } mapImg.onmouseleave = (_event: MouseEvent) => { document.getElementById("dot")!.style.display = "none"; [mousePositionElement, coordsElement, zipCodeElement].forEach( (e) => (e.innerHTML = ""), ); }; } function setupSearchBar(zipCodeElement: HTMLParagraphElement) { const searchBar = document.querySelector("#search-bar")!; const searchInput = document.querySelector("#search-input")!; // Prevent typing letters searchBar.onkeypress = event => { event.key !== "Enter" || !isNaN(parseInt(event.key)); } searchBar.addEventListener("submit", async (event: Event) => { event.preventDefault(); const inputValue = searchInput.value; if (!/^\d+$/.test(inputValue)) return; const data = await ( await fetch( `https://api.dataforsyningen.dk/postnumre?nr=${inputValue}`, ) ).json(); displayZipCode( zipCodeElement, data.length ? parseInt(data[0]["nr"]) : null, data.length ? data[0]["navn"] : null, data.length ? { longitude: data[0]["visueltcenter"][0], latitude: data[0]["visueltcenter"][1] } : null, ); }); } function main() { const [mousePositionElement, coordsElement, zipCodeElement] = [ "#mouse-position", "#coords", "#zip-code", ].map((id) => document.querySelector(id)!); setupSearchBar(zipCodeElement); setupMap(mousePositionElement, coordsElement, zipCodeElement); } main();