From b6ecbe45d43c9db8a8d998daf8b658a39109c3dc Mon Sep 17 00:00:00 2001 From: uku Date: Thu, 24 Oct 2024 14:22:18 +0200 Subject: [PATCH] feat: server-side checking --- src/lib/index.ts | 31 +++++++++++++++++++- src/routes/+page.svelte | 43 ++++++++++++--------------- src/routes/api/check/+server.ts | 51 +++++++++++++++++++++++++++++++++ src/routes/api/data/+server.ts | 19 +++--------- 4 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 src/routes/api/check/+server.ts diff --git a/src/lib/index.ts b/src/lib/index.ts index b1cebb7..836fbe6 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -2,5 +2,34 @@ export interface GameData { center: [number, number]; lines: [GeoJSON.Feature, string][]; stopName: string; - stop: GeoJSON.Position; + stopId: string; +} + +export interface CheckData { + stopId: string; + latlng: [number, number]; +} + +export interface CheckResponse { + solution: [number, number]; + distance: number; + score: number; +} + +type FetchType = typeof fetch; + +const linesUrl = + "https://data.grandlyon.com/geoserver/sytral/ows?SERVICE=WFS&VERSION=2.0.0&request=GetFeature&typename=sytral:tcl_sytral.tcllignemf_2_0_0&outputFormat=application/json&SRSNAME=EPSG:4171&sortBy=gid"; +const stopsUrl = + "https://data.grandlyon.com/geoserver/sytral/ows?SERVICE=WFS&VERSION=2.0.0&request=GetFeature&typename=sytral:tcl_sytral.tclarret&outputFormat=application/json&SRSNAME=EPSG:4171&sortBy=gid"; + +let lazyLines: GeoJSON.FeatureCollection | null = null; +let lazyStops: GeoJSON.FeatureCollection | null = null; + +export async function getLines(fetch: FetchType): Promise { + return lazyLines ?? (lazyLines = await fetch(linesUrl).then((r) => r.json())); +} + +export async function getStops(fetch: FetchType): Promise { + return lazyStops ?? (lazyStops = await fetch(stopsUrl).then((r) => r.json())); } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 189b5bb..66e6ceb 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -6,6 +6,7 @@ import "leaflet/dist/leaflet.css"; import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css"; import "leaflet-defaulticon-compatibility"; + import type { CheckData, CheckResponse } from "$lib"; interface Props { data: PageData; @@ -16,7 +17,6 @@ const hidden = !$page.url.searchParams.has("debug"); const lignes = data.gameData.lines; - const point = L.latLng(data.gameData.stop[1], data.gameData.stop[0]); const center = L.latLng(data.gameData.center); const linesJson = lignes.map(([feature, color]) => { @@ -24,12 +24,10 @@ }); let latlng = $state(L.latLng(0, 0)); - let distance = $derived(latlng.distanceTo(point)); - let points = $derived(calculatePoints()); + let results: CheckResponse | null = $state(null); let lines = $state(true); let labels = $state(false); - let submitted = $state(false); let map: L.Map | null = $state(null); let playerMarker: L.Marker | null = $state(null); @@ -61,28 +59,29 @@ playerMarker = L.marker([0, 0]).addTo(map); map.on("click", (e) => { - if (map && playerMarker && !submitted) { + if (map && playerMarker && !results) { playerMarker.setLatLng(e.latlng); latlng = e.latlng; } }); } - function calculatePoints(): number { - const lenientDistance = Math.max(0, distance - 20); - const score = 5000 * Math.exp(-lenientDistance / 750); + async function checkLocation() { + const checkData: CheckData = { + stopId: data.gameData.stopId, + latlng: [latlng.lat, latlng.lng], + }; - let multiplier = 1; /* - if (lines) multiplier *= 0.5; - if (labels) multiplier *= 0.5; */ + const response = await fetch("/api/check", { + method: "POST", + body: JSON.stringify(checkData), + }); - return score * multiplier; - } + if (response.ok && map) { + const res: CheckResponse = await response.json(); - function checkLocation() { - submitted = true; - if (map) { - L.marker(point).bindPopup(data.gameData.stopName).addTo(map).openPopup(); + L.marker(res.solution).bindPopup(data.gameData.stopName).addTo(map).openPopup(); + results = res; } } @@ -90,16 +89,12 @@

{data.gameData.stopName}

-