From 2255355f21c706e2fabda8e95ddbec017a65188e Mon Sep 17 00:00:00 2001 From: uku Date: Fri, 25 Oct 2024 11:56:53 +0200 Subject: [PATCH] fix: make stop data consistent --- src/lib/index.ts | 29 ++++++++++++++++++++++++++--- src/routes/+page.svelte | 7 ++++--- src/routes/api/check/+server.ts | 2 +- src/routes/api/data/+server.ts | 9 +++------ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index 836fbe6..e0768de 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,6 +1,7 @@ export interface GameData { center: [number, number]; lines: [GeoJSON.Feature, string][]; + stops: GeoJSON.Feature[]; stopName: string; stopId: string; } @@ -24,12 +25,34 @@ 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; +let lazyStops: GeoJSON.Feature[] | 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())); +export async function getStops(fetch: FetchType): Promise { + if (!lazyStops) { + const stops: GeoJSON.FeatureCollection = await fetch(stopsUrl).then((r) => r.json()); + + lazyStops = Array.from(new Set(stops.features.map((f) => f.properties?.nom))).map((nom) => { + const matching = stops.features.filter((f) => f.properties?.nom === nom); + + const longs = matching.map((f) => (f.geometry as GeoJSON.Point).coordinates[0]); + const lonAvg = longs.reduce((a, b) => a + b) / longs.length; + + const lats = matching.map((f) => (f.geometry as GeoJSON.Point).coordinates[1]); + const latAvg = lats.reduce((a, b) => a + b) / lats.length; + + const desserte = matching.map((f) => f.properties?.desserte).join(","); + + const feature = matching[0]; + feature.geometry = { type: "Point", coordinates: [lonAvg, latAvg] }; + if (feature.properties) feature.properties.desserte = desserte; + + return feature; + }); + } + + return lazyStops; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 835024f..cd13152 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -15,13 +15,12 @@ let { data }: Props = $props(); const hidden = !$page.url.searchParams.has("debug"); - - const lignes = data.gameData.lines; const center = L.latLng(data.gameData.center); - const linesJson = lignes.map(([feature, color]) => { + const linesJson = data.gameData.lines.map(([feature, color]) => { return L.geoJSON(feature, { style: { color } }); }); + const pointsJson = data.gameData.stops.map((f) => L.geoJSON(f)); let latlng = $state(L.latLng(0, 0)); let results: CheckResponse | null = $state(null); @@ -49,8 +48,10 @@ if (lines) { linesJson.forEach((line) => line.addTo(map!)); + pointsJson.forEach((p) => p.addTo(map!)); } else { linesJson.forEach((line) => line.removeFrom(map!)); + pointsJson.forEach((p) => p.removeFrom(map!)); } }); diff --git a/src/routes/api/check/+server.ts b/src/routes/api/check/+server.ts index 21dee65..27b4483 100644 --- a/src/routes/api/check/+server.ts +++ b/src/routes/api/check/+server.ts @@ -5,7 +5,7 @@ export const POST: RequestHandler = async ({ fetch, request }) => { const stops = await getStops(fetch); const data: CheckData = await request.json(); - const stop = stops.features.find((f) => f.id === data.stopId); + const stop = stops.find((f) => f.id === data.stopId); if (stop) { // GeoJSON data is LonLat, not LatLon diff --git a/src/routes/api/data/+server.ts b/src/routes/api/data/+server.ts index 3424cfd..0b5070e 100644 --- a/src/routes/api/data/+server.ts +++ b/src/routes/api/data/+server.ts @@ -16,7 +16,7 @@ export const GET: RequestHandler = async ({ fetch }) => { const lineCodes = new Set(lines.features.map((f) => f.properties!.code_ligne)); - const crossingStops = stops.features.filter((f) => { + const crossingStops = stops.filter((f) => { if (f.properties?.desserte) { return f.properties.desserte .split(",") @@ -27,15 +27,12 @@ export const GET: RequestHandler = async ({ fetch }) => { } }); - const uniqueStops = crossingStops.filter( - (f1, i, arr) => arr.findIndex((f2) => f2.properties?.nom === f1.properties?.nom) === i, - ); - - const randomStop = uniqueStops[Math.floor(Math.random() * uniqueStops.length)]; + const randomStop = crossingStops[Math.floor(Math.random() * crossingStops.length)]; const data: GameData = { center: [centerLat, centerLon], lines: lineColors, + stops: crossingStops, stopName: randomStop.properties!.nom, stopId: randomStop.id!.toString(), };