adds routing engine

This commit is contained in:
Christian Beutel
2024-04-21 00:34:57 +02:00
parent 13f0f5ca8a
commit 9af7ddeffd
15 changed files with 237 additions and 25 deletions

View File

@@ -14,14 +14,15 @@
export let map: Map | null = null;
export let options = {};
export let graticule: AutoGraticule | null = null;
export let crosshair: boolean = false;
const dispatch = createEventDispatcher();
let L: any;
let controlElevation: any;
$: if (trail?.expand.gpx_data && controlElevation) {
controlElevation.clear();
$: if (trail?.expand.gpx_data !== undefined && controlElevation) {
controlElevation.clear();
controlElevation.load(trail.expand.gpx_data);
}
@@ -31,7 +32,9 @@
await import("leaflet.awesome-markers");
//@ts-ignore
await import("$lib/vendor/leaflet-elevation/src/index.js");
const AutoGraticule = (await import("$lib/vendor/leaflet-graticule/leaflet-auto-graticule")).default;
const AutoGraticule = (
await import("$lib/vendor/leaflet-graticule/leaflet-auto-graticule")
).default;
map = L.map("map", { preferCanvas: true }).setView(
[trail?.lat ?? 0, trail?.lon ?? 0],
@@ -43,6 +46,10 @@
dispatch("zoomend", map);
});
map!.on("click", function (e) {
dispatch("click", e);
});
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap contributors",
}).addTo(map);
@@ -99,7 +106,7 @@
iconColor: "white",
}),
},
graticule: false
graticule: false,
};
const elevation_options = Object.assign(
@@ -115,16 +122,21 @@
markers.push(marker);
}
if(elevation_options.graticule) {
if (elevation_options.graticule) {
graticule = new AutoGraticule();
graticule.addTo(map!);
}
});
</script>
<div id="map-container" class="flex flex-col">
<div id="map" class="rounded-xl z-0 basis-full"></div>
<div
id="map"
class="rounded-xl z-0 basis-full"
style={crosshair
? "position: relative; outline-style: none;cursor: crosshair !important"
: "position: relative; outline-style: none;"}
></div>
<div class="flex items-center justify-between">
<slot />
<div class="basis-[300px] flex-grow flex-shrink-0" id="elevation"></div>

View File

@@ -38,7 +38,7 @@
const tabs = [
$_("description"),
$_("waypoints"),
$_("waypoints", { values: { n: 2 } }),
$_("photos"),
$_("summit-book"),
...($currentUser ? [$_("comment", { values: { n: 2 } })] : []),

View File

@@ -40,6 +40,7 @@
"distance": "Distanz",
"documentation": "Dokumentation",
"download-gpx": "GPX herunterladen",
"draw-on-map": "",
"dutch": "Niederländisch",
"easy": "Einfach",
"edit": "Bearbeiten",
@@ -128,6 +129,7 @@
"show-on-map": "Auf der Karte anzeigen",
"slogan": "Speichere deine Abenteuer!",
"sort": "Sortieren",
"stop-drawing": "",
"summit-book": "Gipfelbuch",
"text": "Text",
"trail": "{n, plural, =1 {Route} other {Routen}}",
@@ -136,7 +138,7 @@
"upload-file": "Datei hochladen",
"upload-gpx": "GPX hochladen",
"username": "Nutzername",
"waypoints": "Wegpunkte",
"waypoints": "{n, plural, =1 {Wegpunkt} other {Wegpunkte}}",
"welcome_to": "Willkommen bei",
"wrong-username-or-password": "Falscher Nutzername oder falsches Passwort"
}

View File

@@ -40,6 +40,7 @@
"distance": "Distance",
"documentation": "Documentation",
"download-gpx": "Download GPX",
"draw-on-map": "Draw on map",
"dutch": "Dutch",
"easy": "Easy",
"edit": "Edit",
@@ -128,6 +129,7 @@
"show-on-map": "Show on map",
"slogan": "Save your adventures!",
"sort": "Sort",
"stop-drawing": "Stop drawing",
"summit-book": "Summit Book",
"text": "Text",
"trail": "{n, plural, =1 {Trail} other {Trails}}",
@@ -136,7 +138,7 @@
"upload-file": "Upload file",
"upload-gpx": "Upload GPX",
"username": "Username",
"waypoints": "Waypoints",
"waypoints": "{n, plural, =1 {Waypoint} other {Waypoints}}",
"welcome_to": "Welcome to",
"wrong-username-or-password": "Wrong username or password"
}

View File

@@ -40,6 +40,7 @@
"distance": "Distance",
"documentation": "Documentation",
"download-gpx": "Télécharger le GPX",
"draw-on-map": "",
"dutch": "Néerlandais",
"easy": "Facile",
"edit": "Editer",
@@ -128,6 +129,7 @@
"show-on-map": "Voir sur la carte",
"slogan": "Sauvegarder vos aventures !",
"sort": "Trier",
"stop-drawing": "",
"summit-book": "Livre du sommet",
"text": "Texte",
"trail": "{n, plural, =1 {Itinéraire} other {Itinéraires}}",

View File

@@ -40,6 +40,7 @@
"distance": "Távolság",
"documentation": "Dokumentáció",
"download-gpx": "GPX letöltése",
"draw-on-map": "",
"dutch": "Holland",
"easy": "Könnyű",
"edit": "Szerkesztés",
@@ -128,6 +129,7 @@
"show-on-map": "Mutatás térképen",
"slogan": "Mentse el a kalandjait!",
"sort": "Rendezés",
"stop-drawing": "",
"summit-book": "Csúcspont könyv",
"text": "Szöveg",
"trail": "{n, plural, =1 {Útvonal} other {Útvonalak}}",

View File

@@ -40,6 +40,7 @@
"distance": "Afstand",
"documentation": "Documentatie",
"download-gpx": "GPX-bestand downloaden",
"draw-on-map": "",
"dutch": "Nederlands",
"easy": "Makkelijk",
"edit": "Bewerken",
@@ -128,6 +129,7 @@
"show-on-map": "Tonen op kaart",
"slogan": "Bewaar je avonturen!",
"sort": "Sorteren",
"stop-drawing": "",
"summit-book": "Bergtopboek",
"text": "Tekst",
"trail": "{n, plural, =1 {wandelroute} other {wandelroutes}}",

View File

@@ -40,6 +40,7 @@
"distance": "Dystans",
"documentation": "Dokumentacja",
"download-gpx": "Popierz GPX",
"draw-on-map": "",
"dutch": "Niderlandzki",
"easy": "Łatwy",
"edit": "Edytuj",
@@ -128,6 +129,7 @@
"show-on-map": "Pokaż na mapie",
"slogan": "Zapisz swoją wyprawę!",
"sort": "Sortowanie",
"stop-drawing": "",
"summit-book": "Logbook",
"text": "Tekst",
"trail": "{n, plural, =1 {Szlak} other {Szlaki}}",

View File

@@ -40,6 +40,7 @@
"distance": "Distância",
"documentation": "Documentação",
"download-gpx": "Baixar GPX",
"draw-on-map": "",
"dutch": "Holandês",
"easy": "Fácil",
"edit": "Editar",
@@ -128,6 +129,7 @@
"show-on-map": "Mostrar no mapa",
"slogan": "Guarde as suas aventuras!",
"sort": "Ordenar",
"stop-drawing": "",
"summit-book": "Livro da cimeira",
"text": "Texto",
"trail": "{n, plural, =1 {Percurso} other {Percursos}}",

View File

@@ -40,6 +40,7 @@
"distance": "距离",
"documentation": "文档",
"download-gpx": "下载 GPX",
"draw-on-map": "",
"dutch": "荷兰语",
"easy": "简单",
"edit": "编辑",
@@ -128,6 +129,7 @@
"show-on-map": "地图中展示",
"slogan": "保存你的冒险!",
"sort": "排序",
"stop-drawing": "",
"summit-book": "详细日程",
"text": "文本",
"trail": "{n, plural, =1 {路线} other {路线}}",

View File

@@ -0,0 +1,31 @@
interface ValhallaResponse {
trip: {
legs: {
shape: string[];
}[];
};
}
class ValhallaRoute {
type: "Feature";
properties: {};
geometry: {
type: "LineString";
coordinates: number[][];
};
constructor() {
this.type = "Feature"
this.properties = {}
this.geometry = {
type: "LineString",
coordinates: []
}
}
toString() {
return JSON.stringify(this);
}
}
export {type ValhallaResponse, ValhallaRoute}

View File

@@ -0,0 +1,79 @@
import { ValhallaRoute, type ValhallaResponse } from "$lib/models/valhalla";
import { ClientResponseError } from "pocketbase";
export const route: ValhallaRoute = new ValhallaRoute();
export function clearRoute() {
route.geometry.coordinates = [];
}
export async function calculateRouteBetween(startLat: number, startLon: number, endLat: number, endLon: number) {
const requestBody = {
"directions_type": "none",
"locations": [{ "lat": startLat, "lon": startLon }, { "lat": endLat, "lon": endLon }],
"costing": "pedestrian", "costing_options": { "pedestrian": { "max_hiking_difficulty": 6, "use_ferry": 0 } }
}
const r = await fetch("/api/v1/valhalla", { method: "POST", body: JSON.stringify(requestBody) })
if (!r.ok) {
throw new ClientResponseError(await r.json())
}
const response: ValhallaResponse = await r.json();
appendToRoute(response);
}
function appendToRoute(valhallaResponse: any) {
const routeGeometry = decodeShape(valhallaResponse.trip.legs[0].shape);
for (const point of routeGeometry) {
route.geometry.coordinates.push([point[1], point[0]])
}
}
function decodeShape(shape: string, precision: number = 6) {
var index = 0,
lat = 0,
lng = 0,
coordinates = [],
shift = 0,
result = 0,
byte = null,
latitude_change,
longitude_change,
factor = Math.pow(10, precision);
while (index < shape.length) {
byte = null;
shift = 0;
result = 0;
do {
byte = shape.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
shift = result = 0;
do {
byte = shape.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += latitude_change;
lng += longitude_change;
coordinates.push([lat / factor, lng / factor]);
}
return coordinates;
};