adds italian && fit support
This commit is contained in:
6
web/package-lock.json
generated
6
web/package-lock.json
generated
@@ -16,6 +16,7 @@
|
||||
"@types/three": "^0.161.2",
|
||||
"canvg": "^4.0.1",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"easy-fit": "^0.0.8",
|
||||
"instead": "^1.0.3",
|
||||
"isomorphic-xml2js": "^0.1.3",
|
||||
"jspdf": "^2.5.1",
|
||||
@@ -2234,6 +2235,11 @@
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/easy-fit": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/easy-fit/-/easy-fit-0.0.8.tgz",
|
||||
"integrity": "sha512-59BXYGsiteuFG7qfkOccPz2ioXH9RTWcO4ffY/m3niYdAyzYSsSkgqOB6vKncLcbIBZU9cC8V12dCbeAlPBeew=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.647",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.647.tgz",
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"@types/three": "^0.161.2",
|
||||
"canvg": "^4.0.1",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"easy-fit": "^0.0.8",
|
||||
"instead": "^1.0.3",
|
||||
"isomorphic-xml2js": "^0.1.3",
|
||||
"jspdf": "^2.5.1",
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
import Dropdown, { type DropdownItem } from "../base/dropdown.svelte";
|
||||
import Dropdown from "../base/dropdown.svelte";
|
||||
|
||||
export let trail: Trail | null;
|
||||
export let markers: Marker[] = [];
|
||||
export let map: Map | null = null;
|
||||
export let options = {};
|
||||
export let options: any = {};
|
||||
export let graticule: AutoGraticule | null = null;
|
||||
export let crosshair: boolean = false;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
$: gpxData = trail?.expand.gpx_data;
|
||||
$: if (gpxData && controlElevation) {
|
||||
controlElevation.updateOptions({
|
||||
autofitBounds: true,
|
||||
autofitBounds: options.autofitBounds ?? true,
|
||||
});
|
||||
controlElevation.clear();
|
||||
controlElevation.load(gpxData);
|
||||
|
||||
@@ -9,6 +9,7 @@ register('en', () => import('./locales/en.json'))
|
||||
register('de', () => import('./locales/de.json'))
|
||||
register('fr', () => import('./locales/fr.json'))
|
||||
register('hu', () => import('./locales/hu.json'))
|
||||
register('it', () => import('./locales/it.json'))
|
||||
register('nl', () => import('./locales/nl.json'))
|
||||
register('pl', () => import('./locales/pl.json'))
|
||||
register('pt', () => import('./locales/pt.json'))
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
class Settings {
|
||||
id?: string;
|
||||
unit?: "metric" | "imperial";
|
||||
language?: "en" | "de" | "fr" | "hu" | "nl" | "pl" | "pt" | "zh";
|
||||
language?: "en" | "de" | "fr" | "hu"| "it" | "nl" | "pl" | "pt" | "zh";
|
||||
mapFocus?: "trails" | "location";
|
||||
location?: { name: string, lat: number, lon: number };
|
||||
user?: string;
|
||||
|
||||
constructor(
|
||||
unit: "metric" | "imperial",
|
||||
language: "en" | "de" | "fr" | "hu" | "nl" | "pl" | "pt" | "zh",
|
||||
language: "en" | "de" | "fr" | "hu"| "it" | "nl" | "pl" | "pt" | "zh",
|
||||
mapFocus: "trails" | "location",
|
||||
user: string,
|
||||
params?: {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import GPX from "$lib/models/gpx/gpx";
|
||||
import { Trail } from "$lib/models/trail";
|
||||
import { Waypoint } from "$lib/models/waypoint";
|
||||
import { Waypoint, waypointSchema } from "$lib/models/waypoint";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import GeoJsonToGpx from "$lib/vendor/geoJSONToGPX";
|
||||
import { kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import cryptoRandomString from "crypto-random-string";
|
||||
import { get } from "svelte/store";
|
||||
//@ts-ignore
|
||||
import EasyFit from "easy-fit"
|
||||
import Track from "$lib/models/gpx/track";
|
||||
import TrackSegment from "$lib/models/gpx/track-segment";
|
||||
import GPXWaypoint from "$lib/models/gpx/waypoint";
|
||||
|
||||
export async function gpx2trail(gpxString: string) {
|
||||
const gpx = await GPX.parse(gpxString);
|
||||
@@ -16,7 +21,7 @@ export async function gpx2trail(gpxString: string) {
|
||||
|
||||
const trail = new Trail("");
|
||||
|
||||
trail.name = gpx.metadata?.name || gpx.trk?.at(0)?.name || gpx.rte?.at(0)?.name || `trail-${new Date().toISOString()}`;
|
||||
trail.name = gpx.metadata?.name || gpx.trk?.at(0)?.name || gpx.rte?.at(0)?.name || `trail-${new Date().toISOString()}`;
|
||||
|
||||
trail.description = gpx.metadata?.desc;
|
||||
|
||||
@@ -72,13 +77,13 @@ export async function trail2gpx(trail: Trail) {
|
||||
author: { name: trail.author ?? "", email: get(currentUser)?.email ?? "" }
|
||||
}
|
||||
|
||||
if(!gpx.wpt) {
|
||||
if (!gpx.wpt) {
|
||||
gpx.wpt = [];
|
||||
}
|
||||
|
||||
for (const wp of trail.expand.waypoints) {
|
||||
const gpxWpt = gpx.wpt.find((w) => w.$.lat == wp.lat && w.$.lon == wp.lon)
|
||||
if(!gpxWpt) {
|
||||
if (!gpxWpt) {
|
||||
gpx.wpt.push({
|
||||
$: {
|
||||
lat: wp.lat,
|
||||
@@ -124,4 +129,43 @@ export function fromTCX(tcxData: string) {
|
||||
}
|
||||
const gpx = GeoJsonToGpx(geojson as any, options)
|
||||
return new XMLSerializer().serializeToString(gpx)
|
||||
}
|
||||
|
||||
export async function fromFIT(fitData: ArrayBuffer) {
|
||||
const easyFit = new EasyFit({
|
||||
});
|
||||
return new Promise<string>((resolve, reject) => easyFit.parse(fitData, function (error: string, data: any) {
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
reject(error)
|
||||
}
|
||||
console.log(data);
|
||||
|
||||
const gpx = new GPX({
|
||||
metadata: {
|
||||
name: "",
|
||||
desc: "",
|
||||
time: data.activity?.timestamp ?? new Date(),
|
||||
keywords: "wanderer"
|
||||
},
|
||||
trk: [
|
||||
new Track({
|
||||
trkseg: new TrackSegment({
|
||||
trkpt: data.records.flatMap((d => {
|
||||
return (d.position_lat && d.position_long) ? new GPXWaypoint({
|
||||
$: { lat: d.position_lat, lon: d.position_long },
|
||||
time: d.timestamp,
|
||||
ele: d.altitude
|
||||
|
||||
}) : []
|
||||
}))
|
||||
})
|
||||
})
|
||||
]
|
||||
});
|
||||
console.log(gpx);
|
||||
|
||||
resolve(gpx.toString());
|
||||
}));
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
{ text: $_("english"), value: "en" },
|
||||
{ text: $_("french"), value: "fr" },
|
||||
{ text: $_("hungarian"), value: "hu" },
|
||||
{ text: $_("italian"), value: "it" },
|
||||
{ text: $_("dutch"), value: "nl" },
|
||||
{ text: $_("polish"), value: "pl" },
|
||||
{ text: $_("portuguese"), value: "pt" },
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
formatElevation,
|
||||
formatTimeHHMM,
|
||||
} from "$lib/util/format_util";
|
||||
import { fromKML, fromTCX, gpx2trail } from "$lib/util/gpx_util";
|
||||
import { fromFIT, fromKML, fromTCX, gpx2trail } from "$lib/util/gpx_util";
|
||||
import {
|
||||
createAnchorMarker,
|
||||
createMarkerFromWaypoint,
|
||||
@@ -221,7 +221,37 @@
|
||||
document.getElementById("fileInput")!.click();
|
||||
}
|
||||
|
||||
function handleFileSelection() {
|
||||
async function parseFile(file: File) {
|
||||
const fileExtension = file.name.split(".").pop()?.toLowerCase();
|
||||
|
||||
let gpxData = "";
|
||||
|
||||
if (fileExtension !== "fit") {
|
||||
const fileContent = await file.text();
|
||||
if (fileContent.includes("http://www.opengis.net/kml")) {
|
||||
gpxData = fromKML(fileContent);
|
||||
gpxFile = new Blob([gpxData], {
|
||||
type: "application/gpx+xml",
|
||||
});
|
||||
return gpxData;
|
||||
} else if (fileContent.includes("TrainingCenterDatabase")) {
|
||||
gpxData = fromTCX(fileContent);
|
||||
gpxFile = new Blob([gpxData], {
|
||||
type: "application/gpx+xml",
|
||||
});
|
||||
} else {
|
||||
gpxData = fileContent;
|
||||
gpxFile = file;
|
||||
}
|
||||
} else {
|
||||
const fileContent = await file.arrayBuffer();
|
||||
gpxData = await fromFIT(fileContent);
|
||||
}
|
||||
|
||||
return gpxData
|
||||
}
|
||||
|
||||
async function handleFileSelection() {
|
||||
const selectedFile = (
|
||||
document.getElementById("fileInput") as HTMLInputElement
|
||||
).files?.[0];
|
||||
@@ -235,61 +265,45 @@
|
||||
clearRoute();
|
||||
drawingActive = false;
|
||||
overwriteGPX = false;
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.readAsText(selectedFile);
|
||||
let gpxData = await parseFile(selectedFile);
|
||||
|
||||
reader.onload = async function (e) {
|
||||
let gpxData = "";
|
||||
const fileContent = e.target?.result as string;
|
||||
if (fileContent.includes("http://www.opengis.net/kml")) {
|
||||
gpxData = fromKML(e.target?.result as string);
|
||||
gpxFile = new Blob([gpxData], { type: "application/gpx+xml" });
|
||||
} else if (fileContent.includes("TrainingCenterDatabase")) {
|
||||
gpxData = fromTCX(e.target?.result as string);
|
||||
gpxFile = new Blob([gpxData], { type: "application/gpx+xml" });
|
||||
} else {
|
||||
gpxData = fileContent;
|
||||
gpxFile = selectedFile;
|
||||
try {
|
||||
const parseResult = await gpx2trail(gpxData);
|
||||
$form = parseResult.trail;
|
||||
$form.expand.gpx_data = gpxData;
|
||||
$form.category = $categories[0].id;
|
||||
|
||||
setRoute(parseResult.gpx);
|
||||
initRouteAnchors(parseResult.gpx);
|
||||
|
||||
for (const waypoint of $form.expand.waypoints) {
|
||||
saveWaypoint(waypoint);
|
||||
}
|
||||
try {
|
||||
const parseResult = await gpx2trail(gpxData);
|
||||
$form = parseResult.trail;
|
||||
$form.expand.gpx_data = gpxData;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
||||
setRoute(parseResult.gpx);
|
||||
initRouteAnchors(parseResult.gpx);
|
||||
|
||||
for (const waypoint of $form.expand.waypoints) {
|
||||
saveWaypoint(waypoint);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
||||
show_toast({
|
||||
icon: "close",
|
||||
type: "error",
|
||||
text: $_("error-reading-file"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const r = await fetch("/api/v1/search/cities500", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
q: "",
|
||||
options: {
|
||||
filter: [
|
||||
`_geoRadius(${$form.lat}, ${$form.lon}, 10000)`,
|
||||
],
|
||||
sort: [`_geoPoint(${$form.lat}, ${$form.lon}):asc`],
|
||||
limit: 1,
|
||||
},
|
||||
}),
|
||||
show_toast({
|
||||
icon: "close",
|
||||
type: "error",
|
||||
text: $_("error-reading-file"),
|
||||
});
|
||||
const closestCity = (await r.json()).hits[0];
|
||||
return;
|
||||
}
|
||||
const r = await fetch("/api/v1/search/cities500", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
q: "",
|
||||
options: {
|
||||
filter: [`_geoRadius(${$form.lat}, ${$form.lon}, 10000)`],
|
||||
sort: [`_geoPoint(${$form.lat}, ${$form.lon}):asc`],
|
||||
limit: 1,
|
||||
},
|
||||
}),
|
||||
});
|
||||
const closestCity = (await r.json()).hits[0];
|
||||
|
||||
$form.location = closestCity.name;
|
||||
};
|
||||
$form.location = closestCity.name;
|
||||
}
|
||||
|
||||
function clearWaypoints() {
|
||||
@@ -386,7 +400,7 @@
|
||||
}
|
||||
|
||||
function beforSummitLogModalOpen() {
|
||||
summitLog.set(new SummitLog(new Date().toISOString().split('T')[0]));
|
||||
summitLog.set(new SummitLog(new Date().toISOString().split("T")[0]));
|
||||
openSummitLogModal();
|
||||
}
|
||||
|
||||
@@ -640,7 +654,7 @@
|
||||
type="file"
|
||||
name="gpx"
|
||||
id="fileInput"
|
||||
accept=".gpx,.GPX,.tcx,.TCX,.kml,.KML"
|
||||
accept=".gpx,.GPX,.tcx,.TCX,.kml,.KML,.fit,.FIT"
|
||||
style="display: none;"
|
||||
on:change={handleFileSelection}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user