Editing waypoints represent where the user clicked, not the actual route. Exporting them causes reimported routes to look different because BRouter re-routes without no-go areas. Now both GPX export and Save to Journal only include the computed track. On reimport, Douglas-Peucker extracts waypoints from the track shape, preserving the route including no-go detours. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import * as Y from "yjs";
|
|
import type { YjsState } from "~/lib/use-yjs";
|
|
import { generateGpx } from "@trails-cool/gpx";
|
|
import type { TrackPoint } from "@trails-cool/gpx";
|
|
|
|
export function ExportButton({ yjs }: { yjs: YjsState }) {
|
|
const { t } = useTranslation("planner");
|
|
|
|
const handleExport = useCallback(() => {
|
|
// Export only the computed track, not editing waypoints.
|
|
// The track already reflects no-go area avoidance and BRouter's routing.
|
|
// On reimport, waypoints are extracted from the track shape.
|
|
let tracks: TrackPoint[][] = [];
|
|
const geojsonStr = yjs.routeData.get("geojson") as string | undefined;
|
|
if (geojsonStr) {
|
|
try {
|
|
const geojson = JSON.parse(geojsonStr);
|
|
const coords: number[][] = geojson.features?.[0]?.geometry?.coordinates ?? [];
|
|
if (coords.length > 0) {
|
|
tracks = [
|
|
coords.map((c) => ({
|
|
lat: c[1]!,
|
|
lon: c[0]!,
|
|
ele: c[2],
|
|
})),
|
|
];
|
|
}
|
|
} catch {
|
|
// Invalid GeoJSON
|
|
}
|
|
}
|
|
|
|
const gpx = generateGpx({ name: "trails.cool route", waypoints: [], tracks });
|
|
|
|
// Download
|
|
const blob = new Blob([gpx], { type: "application/gpx+xml" });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = "route.gpx";
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}, [yjs.waypoints, yjs.routeData]);
|
|
|
|
return (
|
|
<button
|
|
onClick={handleExport}
|
|
className="rounded bg-gray-100 px-3 py-1 text-sm text-gray-700 hover:bg-gray-200"
|
|
>
|
|
{t("exportGpx")}
|
|
</button>
|
|
);
|
|
}
|