112 lines
2.7 KiB
Svelte
112 lines
2.7 KiB
Svelte
<script lang="ts">
|
|
import type { CheckData, CheckResponse } from "$lib";
|
|
import type { PageData } from "./$types";
|
|
import L from "leaflet";
|
|
|
|
import "leaflet/dist/leaflet.css";
|
|
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
|
import "leaflet-defaulticon-compatibility";
|
|
|
|
interface Props {
|
|
data: PageData;
|
|
}
|
|
|
|
let { data }: Props = $props();
|
|
|
|
const center = L.latLng(45.742858495, 4.86163814);
|
|
|
|
let latlng = $state(L.latLng(0, 0));
|
|
let results: CheckResponse | null = $state(null);
|
|
|
|
let map: L.Map | null = $state(null);
|
|
|
|
function createMap(node: HTMLElement) {
|
|
map = L.map(node).setView(center, 13);
|
|
|
|
function setMarker(pos: L.LatLng) {
|
|
if (map && playerMarker && !results) {
|
|
playerMarker.setLatLng(pos);
|
|
latlng = pos;
|
|
}
|
|
}
|
|
|
|
L.tileLayer(`https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png`, {
|
|
attribution:
|
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
|
maxZoom: 20,
|
|
}).addTo(map);
|
|
|
|
// we know map isn't null
|
|
data.gameData.lines.forEach(([feature, color]) => {
|
|
L.geoJSON(feature, { style: { color } }).addTo(map!);
|
|
});
|
|
data.gameData.stops.forEach((coords) => {
|
|
const marker = L.marker(coords).addTo(map!);
|
|
marker.on("click", (e) => setMarker(e.latlng));
|
|
});
|
|
|
|
const playerMarker = L.marker([0, 0]).addTo(map);
|
|
|
|
map.on("click", (e) => setMarker(e.latlng));
|
|
map.on("keydown", (e) => {
|
|
if (!results && latlng.lat !== 0 && latlng.lng !== 0 && e.originalEvent.key === " ") {
|
|
checkLocation();
|
|
}
|
|
});
|
|
}
|
|
|
|
async function checkLocation() {
|
|
const checkData: CheckData = {
|
|
gameId: data.gameData.gameId,
|
|
latlng: [latlng.lat, latlng.lng],
|
|
};
|
|
|
|
const response = await fetch("/api/check", {
|
|
method: "POST",
|
|
body: JSON.stringify(checkData),
|
|
});
|
|
|
|
if (response.ok && map) {
|
|
const res: CheckResponse = await response.json();
|
|
|
|
L.marker(res.solution).bindPopup(data.gameData.stopName).addTo(map).openPopup();
|
|
results = res;
|
|
} else {
|
|
alert("you dirty little cheater");
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="container">
|
|
<h1>{data.gameData.stopName}</h1>
|
|
|
|
<div hidden={results !== null}>
|
|
<button onclick={checkLocation} disabled={latlng.lat === 0 || latlng.lng === 0}>SUBMIT</button>
|
|
</div>
|
|
|
|
<div class="results" hidden={!results}>
|
|
{Math.floor(results?.score ?? 0)} points! Vous etiez à {Math.floor(results?.distance ?? 0)}m.
|
|
</div>
|
|
|
|
<div id="map" use:createMap></div>
|
|
</div>
|
|
|
|
<style>
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
height: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.results {
|
|
color: green;
|
|
font-size: 20px;
|
|
}
|
|
|
|
#map {
|
|
flex-grow: 1;
|
|
width: 100%;
|
|
}
|
|
</style>
|