diff --git a/frontend/assets/JetBrainsMono-Bold.woff2 b/frontend/assets/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000..4917f43 Binary files /dev/null and b/frontend/assets/JetBrainsMono-Bold.woff2 differ diff --git a/frontend/index.html b/frontend/index.html index 4173382..297be81 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -22,6 +22,7 @@
+

diff --git a/frontend/src/coordinates.ts b/frontend/src/coordinates.ts new file mode 100644 index 0000000..54392b8 --- /dev/null +++ b/frontend/src/coordinates.ts @@ -0,0 +1,30 @@ +import { Size } from "./size"; + +export type Coordinate = { + longitude: number; + latitude: number; +}; + +export type Position = { + x: number; + y: number; +}; + +const scalar = { x: 8.26, y: 3.6 } as const; +const offset = { x: 6, y: 57.92 } as const; + + +export function convertPixelsToCoordinate(mouse: Position, map: Size): Coordinate { + return { + longitude: offset.x + mouse.x * (scalar.x / map.width), + latitude: offset.y - mouse.y * (scalar.y / map.height), + }; +} + +export function convertCoordinateToPixels(coords: Coordinate, map: Size): Position { + return { + x: map.width * (coords.longitude - offset.x) / scalar.x, + y: map.height * (offset.y - coords.latitude) / scalar.y, + }; +} + diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 6c9e492..aef62cb 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,20 +1,11 @@ import { Throttler } from "./Throttler"; - -type Position = { - x: number; - y: number; -}; - -type Size = { width: number; height: number }; - -type Coordinate = { - longitude: number; - latitude: number; -}; +import { Coordinate, Position, convertPixelsToCoordinate, convertCoordinateToPixels } from "./coordinates"; +import { Size } from "./size"; type ZipCodeReverseResponse = { nr: number | null; navn: string; + visueltcenter: number[]; }; async function fetchZipCode({ @@ -35,15 +26,6 @@ async function fetchZipCode({ .catch(() => null as never); } -function convertPixelsToCoordinate(mouse: Position, map: Size): Coordinate { - const scalar = { x: 8, y: 3.6 }; - const offset = { x: 6.2, y: 57.93 }; - return { - longitude: (mouse.x / map.width) * scalar.x + offset.x, - latitude: Math.abs((mouse.y / map.height) * scalar.y - offset.y), - }; -} - function displayMousePosition(element: HTMLParagraphElement, mouse: Position) { element.innerHTML = `Mouse position: (${mouse.x}px, ${mouse.y}px)`; } @@ -57,12 +39,34 @@ function displayCoords(element: HTMLParagraphElement, coords: Coordinate) { function displayZipCode( element: HTMLParagraphElement, zipCode: number | null, - name: string, + 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( @@ -84,7 +88,12 @@ function setupMap( displayCoords(coordsElement, coords); fetcher.call(async () => { const response = await fetchZipCode(coords); - displayZipCode(zipCodeElement, response.nr, response.navn); + displayZipCode( + zipCodeElement, + response.nr, + response.navn, + response.visueltcenter ? { longitude: response.visueltcenter[0], latitude: response.visueltcenter[1] } : null, + ); }); }; @@ -99,13 +108,18 @@ function setupMap( displayCoords(coordsElement, coords); fetcher.call(async () => { const response = await fetchZipCode(coords); - displayZipCode(zipCodeElement, response.nr, response.navn); - console.log("test") + 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 = ""), ); @@ -119,10 +133,11 @@ function setupSearchBar(zipCodeElement: HTMLParagraphElement) { document.querySelector("#search-input")!; // Prevent typing letters - searchBar.onkeypress = (event: KeyboardEvent) => {console.log(event); - event.key !== "Enter" || !isNaN(parseInt(event.key));} + searchBar.onkeypress = event => { + event.key !== "Enter" || !isNaN(parseInt(event.key)); + } - searchBar.addEventListener("submit", async (event: SubmitEvent) => { + searchBar.addEventListener("submit", async (event: Event) => { event.preventDefault(); const inputValue = searchInput.value; @@ -137,6 +152,7 @@ function setupSearchBar(zipCodeElement: HTMLParagraphElement) { 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, ); }); diff --git a/frontend/src/size.ts b/frontend/src/size.ts new file mode 100644 index 0000000..e2dbad5 --- /dev/null +++ b/frontend/src/size.ts @@ -0,0 +1,5 @@ +export type Size = { + width: number; + height: number +}; + diff --git a/frontend/style.css b/frontend/style.css index c5c998b..f7bc917 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -1,6 +1,11 @@ @font-face { - font-family: "Jetbrains Mono"; - src: url("assets/JetbrainsMono-Regular.woff2"); + font-family: "JetBrains Mono"; + src: url("assets/JetBrainsMono-Regular.woff2"); +} + +@font-face { + font-family: "JetBrains Mono Bold"; + src: url("assets/JetBrainsMono-Bold.woff2"); } * { @@ -40,8 +45,7 @@ main > * { } code { - font-family: "Jetbrains Mono", monospace; - font-weight: bold; + font-family: "JetBrains Mono Bold", monospace; } #search-bar { @@ -109,6 +113,17 @@ code { font-size: 0.9em; } +#dot { + width: 15px; + height: 15px; + border-radius: 50%; + border: 2px solid black; + filter: drop-shadow(1px 1px 2px black); + background-color: red; + position: absolute; + display: none; +} + @media screen and (max-width: 1000px) { main { width: 100%;