34 Commits

Author SHA1 Message Date
vcoppe
15f7aea300 preserve timestamps option 2024-10-21 22:56:18 +02:00
vcoppe
4ada271ad3 try to detect 512px custom tiles 2024-10-17 11:55:13 +02:00
vcoppe
1bda957778 scrollable poi content, closes #124 2024-10-14 19:00:05 +02:00
vcoppe
95328db1ee fix poi empty name 2024-10-14 18:42:14 +02:00
vcoppe
65cbf5e751 fix updating overlay opacity 2024-10-14 16:42:05 +02:00
vcoppe
60f24f8757 add h1's 2024-10-10 11:39:14 +02:00
vcoppe
d1e4588813 distance markers hierarchy 2024-10-08 16:58:04 +02:00
vcoppe
711825f5a3 refactor map popups and add inspect trackpoint feature 2024-10-08 15:49:14 +02:00
vcoppe
d823f44558 more precise polyfill 2024-10-08 12:39:00 +02:00
vcoppe
193c77e51a fix xml output for osm attributes 2024-10-08 12:04:07 +02:00
vcoppe
45f6c405c0 fix elevation profile drag on retina screens 2024-10-06 20:03:35 +02:00
vcoppe
78e1ea1e59 New Crowdin updates (#131)
* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations en.json (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Serbian (Latin))

* New translations en.json (Belarusian)

* New translations en.json (Danish)

* New translations en.json (Latvian)

* Update source file en.json

* New translations en.json (Spanish)

* New translations en.json (Dutch)

* New translations en.json (Portuguese, Brazilian)
2024-10-05 17:43:44 +02:00
vcoppe
ca51e1d788 fix derive file style in constructor 2024-10-05 17:40:25 +02:00
vcoppe
72b0b5a706 add spanish satellite layer 2024-10-05 17:06:17 +02:00
vcoppe
4d1de97ba5 New Crowdin updates (#130)
* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations en.json (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Belarusian)

* New translations en.json (Serbian (Latin))

* New translations en.json (Danish)

* New translations en.json (Latvian)

* Update source file en.json

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Dutch)

* New translations en.json (Italian)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations files-and-stats.mdx (Romanian)

* New translations files-and-stats.mdx (French)

* New translations files-and-stats.mdx (Spanish)

* New translations files-and-stats.mdx (Catalan)

* New translations files-and-stats.mdx (Czech)

* New translations files-and-stats.mdx (German)

* New translations files-and-stats.mdx (Greek)

* New translations files-and-stats.mdx (Hungarian)

* New translations files-and-stats.mdx (Italian)

* New translations files-and-stats.mdx (Lithuanian)

* New translations files-and-stats.mdx (Dutch)

* New translations files-and-stats.mdx (Norwegian)

* New translations files-and-stats.mdx (Polish)

* New translations files-and-stats.mdx (Portuguese)

* New translations files-and-stats.mdx (Russian)

* New translations files-and-stats.mdx (Swedish)

* New translations files-and-stats.mdx (Chinese Simplified)

* New translations files-and-stats.mdx (Vietnamese)

* New translations files-and-stats.mdx (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations files-and-stats.mdx (Korean)

* New translations en.json (Hebrew)

* New translations files-and-stats.mdx (Hebrew)

* New translations en.json (Finnish)

* New translations files-and-stats.mdx (Finnish)

* New translations en.json (Serbian (Latin))

* New translations files-and-stats.mdx (Serbian (Latin))

* New translations en.json (Belarusian)

* New translations files-and-stats.mdx (Belarusian)

* New translations en.json (Danish)

* New translations files-and-stats.mdx (Danish)

* New translations en.json (Latvian)

* New translations files-and-stats.mdx (Latvian)

* Update source file en.json

* Update source file files-and-stats.mdx

* New translations en.json (Spanish)

* New translations en.json (Spanish)

* New translations en.json (Spanish)

* New translations en.json (Spanish)

* New translations files-and-stats.mdx (Spanish)

* New translations en.json (French)

* New translations en.json (Dutch)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations en.json (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Serbian (Latin))

* New translations en.json (Belarusian)

* New translations en.json (Danish)

* New translations en.json (Latvian)

* Update source file en.json

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations en.json (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Belarusian)

* New translations en.json (Serbian (Latin))

* New translations en.json (Danish)

* New translations en.json (Latvian)

* New translations en.json (French)

* New translations en.json (Dutch)

* New translations files-and-stats.mdx (French)

* New translations files-and-stats.mdx (Dutch)
2024-10-04 19:53:31 +02:00
vcoppe
04769002d0 update screenshot 2024-10-04 19:53:03 +02:00
vcoppe
8190284148 correct highway naming 2024-10-04 18:10:16 +02:00
vcoppe
a668b4be62 improve highway names 2024-10-04 18:04:20 +02:00
vcoppe
87534468d2 highway, sac_scale and mtb:scale coloring 2024-10-04 17:32:05 +02:00
vcoppe
d7a02f714a add highway info to elevation profile, closes #65 2024-10-03 18:14:01 +02:00
vcoppe
0c16ddd534 fix z-indices 2024-10-03 14:19:51 +02:00
vcoppe
a96f989199 small ui improvements around elevation profile 2024-10-03 14:16:41 +02:00
vcoppe
35c7c9d965 compact elevation profile dataset control 2024-10-03 13:24:23 +02:00
vcoppe
efa05b93ce remove additional scales 2024-10-03 11:41:08 +02:00
vcoppe
0e298cd0e4 same surface tags as brouter 2024-10-03 10:12:10 +02:00
vcoppe
3ef98b2110 improve mapillary integration, closes #127 2024-10-02 18:52:02 +02:00
vcoppe
fbf93ed6f9 increase wpt popup max width 2024-10-02 17:03:59 +02:00
vcoppe
1bd56b6505 New Crowdin updates (#121)
* New translations en.json (Hungarian)

* New translations files-and-stats.mdx (Hungarian)

* New translations en.json (Hungarian)

* New translations funding.mdx (Hungarian)

* New translations integration.mdx (Hungarian)

* New translations faq.mdx (Hungarian)

* New translations en.json (Hungarian)

* New translations file.mdx (Italian)

* New translations file.mdx (Italian)

* New translations en.json (Italian)

* New translations file.mdx (Italian)

* New translations en.json (German)

* New translations en.json (German)

* New translations getting-started.mdx (German)

* New translations map-controls.mdx (German)

* New translations menu.mdx (German)

* New translations toolbar.mdx (German)

* New translations extract.mdx (German)

* New translations en.json (German)

* Update source file en.json

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Swedish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Korean)

* New translations en.json (Hebrew)

* New translations en.json (Finnish)

* New translations en.json (Belarusian)

* New translations en.json (Serbian (Latin))

* New translations en.json (Danish)

* New translations en.json (Latvian)

* New translations en.json (Hungarian)

* New translations menu.mdx (Hungarian)

* New translations toolbar.mdx (Hungarian)

* New translations en.json (Italian)
2024-10-02 12:53:50 +02:00
vcoppe
acf0750ccb temporary fix for #129 2024-10-02 12:49:08 +02:00
vcoppe
48eaa344e4 put ui elements below popups 2024-10-01 16:59:20 +02:00
vcoppe
3262dec7d3 show popup after content has been rendered, fixes popup placement, see #124 2024-10-01 16:56:13 +02:00
vcoppe
572d206c2c reduce hiding distance for popups 2024-10-01 14:18:23 +02:00
vcoppe
11934e5825 option to remove time gaps when merging 2024-10-01 13:17:39 +02:00
vcoppe
5cca106d18 fix button event propagation 2024-09-30 22:08:54 +02:00
108 changed files with 3399 additions and 1897 deletions

View File

@@ -133,22 +133,21 @@ export class GPXFile extends GPXTreeNode<Track> {
} }
if (gpx.hasOwnProperty('_data')) { if (gpx.hasOwnProperty('_data')) {
this._data = gpx._data; this._data = gpx._data;
}
if (!this._data.hasOwnProperty('style')) { if (!this._data.hasOwnProperty('style')) {
let style = this.getStyle(); let style = this.getStyle();
let fileStyle = {}; let fileStyle = {};
if (style.color.length === 1) { if (style.color.length === 1) {
fileStyle['color'] = style.color[0]; fileStyle['color'] = style.color[0];
} }
if (style.weight.length === 1) { if (style.weight.length === 1) {
fileStyle['weight'] = style.weight[0]; fileStyle['weight'] = style.weight[0];
} }
if (style.opacity.length === 1) { if (style.opacity.length === 1) {
fileStyle['opacity'] = style.opacity[0]; fileStyle['opacity'] = style.opacity[0];
} }
if (Object.keys(fileStyle).length > 0) { if (Object.keys(fileStyle).length > 0) {
this.setStyle(fileStyle); this.setStyle(fileStyle);
}
} }
} }
} else { } else {
@@ -775,12 +774,16 @@ export class TrackSegment extends GPXTreeLeaf {
} }
} }
if (i > 0 && points[i - 1].extensions && points[i - 1].extensions["gpxtpx:TrackPointExtension"] && points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface) { if (i > 0 && points[i - 1].extensions && points[i - 1].extensions["gpxtpx:TrackPointExtension"] && points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]) {
let surface = points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface; Object.entries(points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]).forEach(([key, value]) => {
if (statistics.global.surface[surface] === undefined) { if (statistics.global.extensions[key] === undefined) {
statistics.global.surface[surface] = 0; statistics.global.extensions[key] = {};
} }
statistics.global.surface[surface] += dist; if (statistics.global.extensions[key][value] === undefined) {
statistics.global.extensions[key][value] = 0;
}
statistics.global.extensions[key][value] += dist;
});
} }
} }
@@ -890,7 +893,7 @@ export class TrackSegment extends GPXTreeLeaf {
} }
// Producers // Producers
replaceTrackPoints(start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) { replaceTrackPoints(start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date, removeGaps?: boolean) {
let og = getOriginal(this); // Read as much as possible from the original object because it is faster let og = getOriginal(this); // Read as much as possible from the original object because it is faster
let trkpt = og.trkpt.slice(); let trkpt = og.trkpt.slice();
@@ -909,6 +912,21 @@ export class TrackSegment extends GPXTreeLeaf {
} else if (last !== undefined && points[0].time < last.time) { } else if (last !== undefined && points[0].time < last.time) {
// Adapt timestamps of the new points because they are too early // Adapt timestamps of the new points because they are too early
points = withShiftedAndCompressedTimestamps(points, speed, 1, last); points = withShiftedAndCompressedTimestamps(points, speed, 1, last);
} else if (last !== undefined && removeGaps) {
// Remove gaps between the new points and the previous point
if (last.getLatitude() === points[0].getLatitude() && last.getLongitude() === points[0].getLongitude()) {
// Same point, make the new points start at its timestamp and remove the first point
if (points[0].time > last.time) {
points = withShiftedAndCompressedTimestamps(points, speed, 1, last).slice(1);
}
} else {
// Different points, make the new points start one second after the previous point
if (points[0].time.getTime() - last.time.getTime() > 1000) {
let artificialLast = points[0].clone();
artificialLast.time = new Date(last.time.getTime() + 1000);
points = withShiftedAndCompressedTimestamps(points, speed, 1, artificialLast);
}
}
} }
} }
if (end < trkpt.length - 1) { if (end < trkpt.length - 1) {
@@ -1060,11 +1078,10 @@ export class TrackPoint {
return this.extensions && this.extensions["gpxpx:PowerExtension"] && this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] ? this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] : undefined; return this.extensions && this.extensions["gpxpx:PowerExtension"] && this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] ? this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] : undefined;
} }
getSurface(): string { setExtensions(extensions: Record<string, string>) {
return this.extensions && this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface ? this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface : undefined; if (Object.keys(extensions).length === 0) {
} return;
}
setSurface(surface: string): void {
if (!this.extensions) { if (!this.extensions) {
this.extensions = {}; this.extensions = {};
} }
@@ -1074,7 +1091,13 @@ export class TrackPoint {
if (!this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]) { if (!this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]) {
this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] = {}; this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] = {};
} }
this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]["surface"] = surface; Object.entries(extensions).forEach(([key, value]) => {
this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"][key] = value;
});
}
getExtensions(): Record<string, string> {
return this.extensions && this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] ? this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] : {};
} }
toTrackPointType(exclude: string[] = []): TrackPointType { toTrackPointType(exclude: string[] = []): TrackPointType {
@@ -1104,8 +1127,11 @@ export class TrackPoint {
if (this.extensions["gpxpx:PowerExtension"] && this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] && !exclude.includes('power')) { if (this.extensions["gpxpx:PowerExtension"] && this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] && !exclude.includes('power')) {
trkpt.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] = this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"]; trkpt.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"] = this.extensions["gpxpx:PowerExtension"]["gpxpx:PowerInWatts"];
} }
if (this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface && !exclude.includes('surface')) { if (this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && !exclude.includes('extensions')) {
trkpt.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] = { surface: this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface }; trkpt.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] = {};
Object.entries(this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]).forEach(([key, value]) => {
trkpt.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"][key] = value;
});
} }
} }
return trkpt; return trkpt;
@@ -1255,7 +1281,7 @@ export class GPXStatistics {
avg: number, avg: number,
count: number, count: number,
}, },
surface: Record<string, number>, extensions: Record<string, Record<string, number>>,
}; };
local: { local: {
points: TrackPoint[], points: TrackPoint[],
@@ -1326,7 +1352,7 @@ export class GPXStatistics {
avg: 0, avg: 0,
count: 0, count: 0,
}, },
surface: {}, extensions: {},
}; };
this.local = { this.local = {
points: [], points: [],
@@ -1396,11 +1422,16 @@ export class GPXStatistics {
this.global.cad.count += other.global.cad.count; this.global.cad.count += other.global.cad.count;
this.global.power.avg = (this.global.power.count * this.global.power.avg + other.global.power.count * other.global.power.avg) / Math.max(1, this.global.power.count + other.global.power.count); this.global.power.avg = (this.global.power.count * this.global.power.avg + other.global.power.count * other.global.power.avg) / Math.max(1, this.global.power.count + other.global.power.count);
this.global.power.count += other.global.power.count; this.global.power.count += other.global.power.count;
Object.keys(other.global.surface).forEach((surface) => { Object.keys(other.global.extensions).forEach((extension) => {
if (this.global.surface[surface] === undefined) { if (this.global.extensions[extension] === undefined) {
this.global.surface[surface] = 0; this.global.extensions[extension] = {};
} }
this.global.surface[surface] += other.global.surface[surface]; Object.keys(other.global.extensions[extension]).forEach((value) => {
if (this.global.extensions[extension][value] === undefined) {
this.global.extensions[extension][value] = 0;
}
this.global.extensions[extension][value] += other.global.extensions[extension][value];
});
}); });
} }

View File

@@ -92,9 +92,7 @@ export type TrackPointExtension = {
'gpxtpx:atemp'?: number; 'gpxtpx:atemp'?: number;
'gpxtpx:hr'?: number; 'gpxtpx:hr'?: number;
'gpxtpx:cad'?: number; 'gpxtpx:cad'?: number;
'gpxtpx:Extensions'?: { 'gpxtpx:Extensions'?: Record<string, string>;
surface?: string;
};
} }
export type PowerExtension = { export type PowerExtension = {

View File

@@ -45,24 +45,9 @@ export async function handle({ event, resolve }) {
`; `;
} }
const stringsHTML = page === 'app' ? stringsToHTML(strings) : '';
const response = await resolve(event, { const response = await resolve(event, {
transformPageChunk: ({ html }) => html.replace('<html>', htmlTag).replace('<head>', headTag).replace('</body>', `<div class="fixed -z-10 text-transparent">${stringsHTML}</div></body>`) transformPageChunk: ({ html }) => html.replace('<html>', htmlTag).replace('<head>', headTag),
}); });
return response; return response;
}
function stringsToHTML(dictionary, strings = new Set(), root = true) {
Object.values(dictionary).forEach((value) => {
if (typeof value === 'object') {
stringsToHTML(value, strings, false);
} else {
strings.add(value);
}
});
if (root) {
return Array.from(strings).map((string) => `<p>${string}</p>`).join('');
}
} }

View File

@@ -0,0 +1,161 @@
export const surfaceColors: { [key: string]: string } = {
"missing": "#d1d1d1",
"paved": "#8c8c8c",
"unpaved": "#6b443a",
"asphalt": "#8c8c8c",
"concrete": "#8c8c8c",
"cobblestone": "#ffd991",
"paving_stones": "#8c8c8c",
"sett": "#ffd991",
"metal": "#8c8c8c",
"wood": "#6b443a",
"compacted": "#ffffa8",
"fine_gravel": "#ffffa8",
"gravel": "#ffffa8",
"pebblestone": "#ffffa8",
"rock": "#ffd991",
"dirt": "#ffffa8",
"ground": "#6b443a",
"earth": "#6b443a",
"mud": "#6b443a",
"sand": "#ffffc4",
"grass": "#61b55c",
"grass_paver": "#61b55c",
"clay": "#6b443a",
"stone": "#ffd991",
};
export function getSurfaceColor(surface: string): string {
return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing;
}
export const highwayColors: { [key: string]: string } = {
"missing": "#d1d1d1",
"motorway": "#ff4d33",
"motorway_link": "#ff4d33",
"trunk": "#ff5e4d",
"trunk_link": "#ff947f",
"primary": "#ff6e5c",
"primary_link": "#ff6e5c",
"secondary": "#ff8d7b",
"secondary_link": "#ff8d7b",
"tertiary": "#ffd75f",
"tertiary_link": "#ffd75f",
"unclassified": "#f1f2a5",
"road": "#f1f2a5",
"residential": "#73b2ff",
"living_street": "#73b2ff",
"service": "#9c9cd9",
"track": "#a8e381",
"footway": "#a8e381",
"path": "#a8e381",
"pedestrian": "#a8e381",
"cycleway": "#9de2ff",
"construction": "#e09a4a",
"bridleway": "#946f43",
"raceway": "#ff0000",
"rest_area": "#9c9cd9",
"services": "#9c9cd9",
"corridor": "#474747",
"elevator": "#474747",
"steps": "#474747",
"bus_stop": "#8545a3",
"busway": "#8545a3",
"via_ferrata": "#474747"
};
export const sacScaleColors: { [key: string]: string } = {
"hiking": "#007700",
"mountain_hiking": "#1843ad",
"demanding_mountain_hiking": "#ffff00",
"alpine_hiking": "#ff9233",
"demanding_alpine_hiking": "#ff0000",
"difficult_alpine_hiking": "#000000",
};
export const mtbScaleColors: { [key: string]: string } = {
"0-": "#007700",
"0": "#007700",
"0+": "#007700",
"1-": "#1843ad",
"1": "#1843ad",
"1+": "#1843ad",
"2-": "#ffff00",
"2": "#ffff00",
"2+": "#ffff00",
"3": "#ff0000",
"4": "#00ff00",
"5": "#000000",
"6": "#b105eb",
};
function createPattern(backgroundColor: string, sacScaleColor: string | undefined, mtbScaleColor: string | undefined, size: number = 16, lineWidth: number = 4) {
let canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
let ctx = canvas.getContext('2d');
if (ctx) {
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, size, size);
ctx.lineWidth = lineWidth;
const halfSize = size / 2;
const halfLineWidth = lineWidth / 2;
if (sacScaleColor) {
ctx.strokeStyle = sacScaleColor;
ctx.beginPath();
ctx.moveTo(halfSize - halfLineWidth, - halfLineWidth);
ctx.lineTo(size + halfLineWidth, halfSize + halfLineWidth);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(- halfLineWidth, halfSize - halfLineWidth);
ctx.lineTo(halfSize + halfLineWidth, size + halfLineWidth);
ctx.stroke();
}
if (mtbScaleColor) {
ctx.strokeStyle = mtbScaleColor;
ctx.beginPath();
ctx.moveTo(halfSize - halfLineWidth, size + halfLineWidth);
ctx.lineTo(size + halfLineWidth, halfSize - halfLineWidth);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(- halfLineWidth, halfSize + halfLineWidth);
ctx.lineTo(halfSize + halfLineWidth, - halfLineWidth);
ctx.stroke();
}
}
return ctx?.createPattern(canvas, 'repeat') || backgroundColor;
}
const patterns: Record<string, string | CanvasPattern> = {};
export function getHighwayColor(highway: string, sacScale: string | undefined, mtbScale: string | undefined) {
let backgroundColor = highwayColors[highway] ? highwayColors[highway] : highwayColors.missing;
let sacScaleColor = sacScale ? sacScaleColors[sacScale] : undefined;
let mtbScaleColor = mtbScale ? mtbScaleColors[mtbScale] : undefined;
if (sacScale || mtbScale) {
let patternId = `${backgroundColor}-${[sacScale, mtbScale].filter(x => x).join('-')}`;
if (!patterns[patternId]) {
patterns[patternId] = createPattern(backgroundColor, sacScaleColor, mtbScaleColor);
}
return patterns[patternId];
}
return backgroundColor;
}
const maxSlope = 20;
export function getSlopeColor(slope: number): string {
if (slope > maxSlope) {
slope = maxSlope;
} else if (slope < -maxSlope) {
slope = -maxSlope;
}
let v = slope / maxSlope;
v = 1 / (1 + Math.exp(-6 * v));
v = v - 0.5;
let hue = ((0.5 - v) * 120).toString(10);
let lightness = 90 - Math.abs(v) * 70;
return `hsl(${hue},70%,${lightness}%)`;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -1,11 +1,11 @@
import { TramFront, Utensils, ShoppingBasket, Droplet, ShowerHead, Fuel, CircleParking, Fence, FerrisWheel, Bed, Mountain, Pickaxe, Store, TrainFront, Bus, Ship, Croissant, House, Tent, Wrench, Binoculars } from 'lucide-static'; import { TramFront, Utensils, ShoppingBasket, Droplet, ShowerHead, Fuel, CircleParking, Fence, FerrisWheel, Bed, Mountain, Pickaxe, Store, TrainFront, Bus, Ship, Croissant, House, Tent, Wrench, Binoculars } from 'lucide-static';
import { type Style } from 'mapbox-gl'; import { type StyleSpecification } from 'mapbox-gl';
import ignFrTopo from './custom/ign-fr-topo.json'; import ignFrTopo from './custom/ign-fr-topo.json';
import ignFrPlan from './custom/ign-fr-plan.json'; import ignFrPlan from './custom/ign-fr-plan.json';
import ignFrSatellite from './custom/ign-fr-satellite.json'; import ignFrSatellite from './custom/ign-fr-satellite.json';
import bikerouterGravel from './custom/bikerouter-gravel.json'; import bikerouterGravel from './custom/bikerouter-gravel.json';
export const basemaps: { [key: string]: string | Style; } = { export const basemaps: { [key: string]: string | StyleSpecification; } = {
mapboxOutdoors: 'mapbox://styles/mapbox/outdoors-v12', mapboxOutdoors: 'mapbox://styles/mapbox/outdoors-v12',
mapboxSatellite: 'mapbox://styles/mapbox/satellite-streets-v12', mapboxSatellite: 'mapbox://styles/mapbox/satellite-streets-v12',
openStreetMap: { openStreetMap: {
@@ -158,7 +158,7 @@ export const basemaps: { [key: string]: string | Style; } = {
tiles: ['https://www.ign.es/wmts/mapa-raster?layer=MTN&style=default&tilematrixset=GoogleMapsCompatible&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/jpeg&TileMatrix={z}&TileCol={x}&TileRow={y}'], tiles: ['https://www.ign.es/wmts/mapa-raster?layer=MTN&style=default&tilematrixset=GoogleMapsCompatible&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/jpeg&TileMatrix={z}&TileCol={x}&TileRow={y}'],
tileSize: 256, tileSize: 256,
maxzoom: 20, maxzoom: 20,
attribution: 'IGN-F/Géoportail' attribution: '&copy; <a href="https://www.ign.es" target="_blank">IGN</a>'
} }
}, },
layers: [{ layers: [{
@@ -167,6 +167,23 @@ export const basemaps: { [key: string]: string | Style; } = {
source: 'ignEs', source: 'ignEs',
}], }],
}, },
ignEsSatellite: {
version: 8,
sources: {
ignEsSatellite: {
type: 'raster',
tiles: ['https://www.ign.es/wmts/pnoa-ma?layer=OI.OrthoimageCoverage&style=default&tilematrixset=GoogleMapsCompatible&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/jpeg&TileMatrix={z}&TileCol={x}&TileRow={y}'],
tileSize: 256,
maxzoom: 20,
attribution: '&copy; <a href="https://www.ign.es" target="_blank">IGN</a>'
}
},
layers: [{
id: 'ignEsSatellite',
type: 'raster',
source: 'ignEsSatellite',
}],
},
ordnanceSurvey: "https://api.os.uk/maps/vector/v1/vts/resources/styles?srs=3857&key=piCT8WysfuC3xLSUW7sGLfrAAJoYDvQz", ordnanceSurvey: "https://api.os.uk/maps/vector/v1/vts/resources/styles?srs=3857&key=piCT8WysfuC3xLSUW7sGLfrAAJoYDvQz",
norwayTopo: { norwayTopo: {
version: 8, version: 8,
@@ -286,7 +303,7 @@ export const basemaps: { [key: string]: string | Style; } = {
}, },
}; };
export const overlays: { [key: string]: string | Style; } = { export const overlays: { [key: string]: string | StyleSpecification; } = {
cyclOSMlite: { cyclOSMlite: {
version: 8, version: 8,
sources: { sources: {
@@ -636,6 +653,7 @@ export const basemapTree: LayerTreeType = {
}, },
spain: { spain: {
ignEs: true, ignEs: true,
ignEsSatellite: true,
}, },
sweden: { sweden: {
swedenTopo: true, swedenTopo: true,
@@ -740,7 +758,7 @@ export const overpassTree: LayerTreeType = {
export const defaultBasemap = 'mapboxOutdoors'; export const defaultBasemap = 'mapboxOutdoors';
// Default overlays used (none) // Default overlays used (none)
export const defaultOverlays = { export const defaultOverlays: LayerTreeType = {
overlays: { overlays: {
world: { world: {
waymarked_trails: { waymarked_trails: {
@@ -855,6 +873,7 @@ export const defaultBasemapTree: LayerTreeType = {
}, },
spain: { spain: {
ignEs: false, ignEs: false,
ignEsSatellite: false,
}, },
sweden: { sweden: {
swedenTopo: false, swedenTopo: false,

View File

@@ -1,31 +0,0 @@
export const surfaceColors: { [key: string]: string } = {
'missing': '#d1d1d1',
'paved': '#8c8c8c',
'unpaved': '#6b443a',
'asphalt': '#8c8c8c',
'concrete': '#8c8c8c',
'chipseal': '#8c8c8c',
'cobblestone': '#ffd991',
'unhewn_cobblestone': '#ffd991',
'paving_stones': '#8c8c8c',
'stepping_stones': '#c7b2db',
'sett': '#ffd991',
'metal': '#8c8c8c',
'wood': '#6b443a',
'compacted': '#ffffa8',
'fine_gravel': '#ffffa8',
'gravel': '#ffffa8',
'pebblestone': '#ffffa8',
'rock': '#ffd991',
'dirt': '#ffffa8',
'ground': '#6b443a',
'earth': '#6b443a',
'snow': '#bdfffc',
'ice': '#bdfffc',
'salt': '#b6c0f2',
'mud': '#6b443a',
'sand': '#ffffc4',
'woodchips': '#6b443a',
'grass': '#61b55c',
'grass_paver': '#61b55c'
}

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Tooltip from '$lib/components/ui/tooltip/index.js'; import * as Tooltip from '$lib/components/ui/tooltip/index.js';
import type { Builder } from 'bits-ui';
export let variant: export let variant:
| 'default' | 'default'
@@ -12,11 +13,12 @@
| undefined = 'default'; | undefined = 'default';
export let label: string; export let label: string;
export let side: 'top' | 'right' | 'bottom' | 'left' = 'top'; export let side: 'top' | 'right' | 'bottom' | 'left' = 'top';
export let builders: Builder[] = [];
</script> </script>
<Tooltip.Root> <Tooltip.Root>
<Tooltip.Trigger asChild let:builder> <Tooltip.Trigger asChild let:builder>
<Button builders={[builder]} {variant} {...$$restProps}> <Button builders={[...builders, builder]} {variant} {...$$restProps} on:click>
<slot /> <slot />
</Button> </Button>
</Tooltip.Trigger> </Tooltip.Trigger>

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte';
import * as Popover from '$lib/components/ui/popover';
import * as ToggleGroup from '$lib/components/ui/toggle-group'; import * as ToggleGroup from '$lib/components/ui/toggle-group';
import Tooltip from '$lib/components/Tooltip.svelte';
import Chart from 'chart.js/auto'; import Chart from 'chart.js/auto';
import mapboxgl from 'mapbox-gl'; import mapboxgl from 'mapbox-gl';
import { map } from '$lib/stores'; import { map } from '$lib/stores';
@@ -12,12 +13,15 @@
Orbit, Orbit,
SquareActivity, SquareActivity,
Thermometer, Thermometer,
Zap Zap,
Circle,
Check,
ChartNoAxesColumn,
Construction
} from 'lucide-svelte'; } from 'lucide-svelte';
import { surfaceColors } from '$lib/assets/surfaces'; import { getSlopeColor, getSurfaceColor, getHighwayColor } from '$lib/assets/colors';
import { _, locale } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { import {
getCadenceUnits,
getCadenceWithUnits, getCadenceWithUnits,
getConvertedDistance, getConvertedDistance,
getConvertedElevation, getConvertedElevation,
@@ -26,45 +30,26 @@
getDistanceUnits, getDistanceUnits,
getDistanceWithUnits, getDistanceWithUnits,
getElevationWithUnits, getElevationWithUnits,
getHeartRateUnits,
getHeartRateWithUnits, getHeartRateWithUnits,
getPowerUnits,
getPowerWithUnits, getPowerWithUnits,
getTemperatureUnits,
getTemperatureWithUnits, getTemperatureWithUnits,
getVelocityUnits, getVelocityWithUnits
getVelocityWithUnits,
secondsToHHMMSS
} from '$lib/units'; } from '$lib/units';
import type { Writable } from 'svelte/store'; import type { Writable } from 'svelte/store';
import { DateFormatter } from '@internationalized/date';
import type { GPXStatistics } from 'gpx'; import type { GPXStatistics } from 'gpx';
import { settings } from '$lib/db'; import { settings } from '$lib/db';
import { mode } from 'mode-watcher'; import { mode } from 'mode-watcher';
import { df } from '$lib/utils';
export let gpxStatistics: Writable<GPXStatistics>; export let gpxStatistics: Writable<GPXStatistics>;
export let slicedGPXStatistics: Writable<[GPXStatistics, number, number] | undefined>; export let slicedGPXStatistics: Writable<[GPXStatistics, number, number] | undefined>;
export let panelSize: number;
export let additionalDatasets: string[]; export let additionalDatasets: string[];
export let elevationFill: 'slope' | 'surface' | undefined; export let elevationFill: 'slope' | 'surface' | 'highway' | undefined;
export let showControls: boolean = true; export let showControls: boolean = true;
const { distanceUnits, velocityUnits, temperatureUnits } = settings; const { distanceUnits, velocityUnits, temperatureUnits } = settings;
let df: DateFormatter;
$: if ($locale) {
df = new DateFormatter($locale, {
dateStyle: 'medium',
timeStyle: 'medium'
});
}
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
let showAdditionalScales = true;
let updateShowAdditionalScales = () => {
showAdditionalScales = canvas.width / window.devicePixelRatio >= 600;
};
let overlay: HTMLCanvasElement; let overlay: HTMLCanvasElement;
let chart: Chart; let chart: Chart;
@@ -83,12 +68,11 @@
x: { x: {
type: 'linear', type: 'linear',
ticks: { ticks: {
callback: function (value: number, index: number, ticks: { value: number }[]) { callback: function (value: number) {
if (index === ticks.length - 1) {
return `${value.toFixed(1).replace(/\.0+$/, '')}`;
}
return `${value.toFixed(1).replace(/\.0+$/, '')} ${getDistanceUnits()}`; return `${value.toFixed(1).replace(/\.0+$/, '')} ${getDistanceUnits()}`;
} },
align: 'inner',
maxRotation: 0
} }
}, },
y: { y: {
@@ -159,7 +143,10 @@
segment: point.slope.segment.toFixed(1), segment: point.slope.segment.toFixed(1),
length: getDistanceWithUnits(point.slope.length) length: getDistanceWithUnits(point.slope.length)
}; };
let surface = point.surface ? point.surface : 'unknown'; let surface = point.extensions.surface ? point.extensions.surface : 'unknown';
let highway = point.extensions.highway ? point.extensions.highway : 'unknown';
let sacScale = point.extensions.sac_scale;
let mtbScale = point.extensions.mtb_scale;
let labels = [ let labels = [
` ${$_('quantities.distance')}: ${getDistanceWithUnits(point.x, false)}`, ` ${$_('quantities.distance')}: ${getDistanceWithUnits(point.x, false)}`,
@@ -172,6 +159,17 @@
); );
} }
if (elevationFill === 'highway') {
labels.push(
` ${$_('quantities.highway')}: ${$_(`toolbar.routing.highway.${highway}`)}${
sacScale ? ` (${$_(`toolbar.routing.sac_scale.${sacScale}`)})` : ''
}`
);
if (mtbScale) {
labels.push(` ${$_('toolbar.routing.mtb_scale')}: ${mtbScale}`);
}
}
if (point.time) { if (point.time) {
labels.push(` ${$_('quantities.time')}: ${df.format(point.time)}`); labels.push(` ${$_('quantities.time')}: ${df.format(point.time)}`);
} }
@@ -226,72 +224,21 @@
stacked: false, stacked: false,
onResize: function () { onResize: function () {
updateOverlay(); updateOverlay();
updateShowAdditionalScales();
} }
}; };
let datasets: { let datasets: string[] = ['speed', 'hr', 'cad', 'atemp', 'power'];
[key: string]: { datasets.forEach((id) => {
id: string;
getLabel: () => string;
getUnits: () => string;
};
} = {
speed: {
id: 'speed',
getLabel: () => ($velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')),
getUnits: () => getVelocityUnits()
},
hr: {
id: 'hr',
getLabel: () => $_('quantities.heartrate'),
getUnits: () => getHeartRateUnits()
},
cad: {
id: 'cad',
getLabel: () => $_('quantities.cadence'),
getUnits: () => getCadenceUnits()
},
atemp: {
id: 'atemp',
getLabel: () => $_('quantities.temperature'),
getUnits: () => getTemperatureUnits()
},
power: {
id: 'power',
getLabel: () => $_('quantities.power'),
getUnits: () => getPowerUnits()
}
};
for (let [id, dataset] of Object.entries(datasets)) {
options.scales[`y${id}`] = { options.scales[`y${id}`] = {
type: 'linear', type: 'linear',
position: 'right', position: 'right',
title: {
display: true,
text: dataset.getLabel() + ' (' + dataset.getUnits() + ')',
padding: {
top: 6,
bottom: 0
}
},
grid: { grid: {
display: false display: false
}, },
reverse: () => id === 'speed' && $velocityUnits === 'pace', reverse: () => id === 'speed' && $velocityUnits === 'pace',
display: false display: false
}; };
} });
options.scales.yspeed['ticks'] = {
callback: function (value: number) {
if ($velocityUnits === 'speed') {
return value;
} else {
return secondsToHHMMSS(value);
}
}
};
onMount(async () => { onMount(async () => {
Chart.register((await import('chartjs-plugin-zoom')).default); // dynamic import to avoid SSR and 'window is not defined' error Chart.register((await import('chartjs-plugin-zoom')).default); // dynamic import to avoid SSR and 'window is not defined' error
@@ -324,8 +271,6 @@
element element
}); });
updateShowAdditionalScales();
let startIndex = 0; let startIndex = 0;
let endIndex = 0; let endIndex = 0;
function getIndex(evt) { function getIndex(evt) {
@@ -414,7 +359,7 @@
segment: data.local.slope.segment[index], segment: data.local.slope.segment[index],
length: data.local.slope.length[index] length: data.local.slope.length[index]
}, },
surface: point.getSurface(), extensions: point.getExtensions(),
coordinates: point.getCoordinates(), coordinates: point.getCoordinates(),
index: index index: index
}; };
@@ -424,7 +369,6 @@
order: 1 order: 1
}; };
chart.data.datasets[1] = { chart.data.datasets[1] = {
label: datasets.speed.getLabel(),
data: data.local.points.map((point, index) => { data: data.local.points.map((point, index) => {
return { return {
x: getConvertedDistance(data.local.distance.total[index]), x: getConvertedDistance(data.local.distance.total[index]),
@@ -433,11 +377,10 @@
}; };
}), }),
normalized: true, normalized: true,
yAxisID: `y${datasets.speed.id}`, yAxisID: 'yspeed',
hidden: true hidden: true
}; };
chart.data.datasets[2] = { chart.data.datasets[2] = {
label: datasets.hr.getLabel(),
data: data.local.points.map((point, index) => { data: data.local.points.map((point, index) => {
return { return {
x: getConvertedDistance(data.local.distance.total[index]), x: getConvertedDistance(data.local.distance.total[index]),
@@ -446,11 +389,10 @@
}; };
}), }),
normalized: true, normalized: true,
yAxisID: `y${datasets.hr.id}`, yAxisID: 'yhr',
hidden: true hidden: true
}; };
chart.data.datasets[3] = { chart.data.datasets[3] = {
label: datasets.cad.getLabel(),
data: data.local.points.map((point, index) => { data: data.local.points.map((point, index) => {
return { return {
x: getConvertedDistance(data.local.distance.total[index]), x: getConvertedDistance(data.local.distance.total[index]),
@@ -459,11 +401,10 @@
}; };
}), }),
normalized: true, normalized: true,
yAxisID: `y${datasets.cad.id}`, yAxisID: 'ycad',
hidden: true hidden: true
}; };
chart.data.datasets[4] = { chart.data.datasets[4] = {
label: datasets.atemp.getLabel(),
data: data.local.points.map((point, index) => { data: data.local.points.map((point, index) => {
return { return {
x: getConvertedDistance(data.local.distance.total[index]), x: getConvertedDistance(data.local.distance.total[index]),
@@ -472,11 +413,10 @@
}; };
}), }),
normalized: true, normalized: true,
yAxisID: `y${datasets.atemp.id}`, yAxisID: 'yatemp',
hidden: true hidden: true
}; };
chart.data.datasets[5] = { chart.data.datasets[5] = {
label: datasets.power.getLabel(),
data: data.local.points.map((point, index) => { data: data.local.points.map((point, index) => {
return { return {
x: getConvertedDistance(data.local.distance.total[index]), x: getConvertedDistance(data.local.distance.total[index]),
@@ -485,43 +425,29 @@
}; };
}), }),
normalized: true, normalized: true,
yAxisID: `y${datasets.power.id}`, yAxisID: 'ypower',
hidden: true hidden: true
}; };
chart.options.scales.x['min'] = 0; chart.options.scales.x['min'] = 0;
chart.options.scales.x['max'] = getConvertedDistance(data.global.distance.total); chart.options.scales.x['max'] = getConvertedDistance(data.global.distance.total);
// update units
for (let [id, dataset] of Object.entries(datasets)) {
chart.options.scales[`y${id}`].title.text =
dataset.getLabel() + ' (' + dataset.getUnits() + ')';
}
chart.update(); chart.update();
} }
let maxSlope = 20;
function slopeFillCallback(context) { function slopeFillCallback(context) {
let slope = context.p0.raw.slope.segment; return getSlopeColor(context.p0.raw.slope.segment);
if (slope > maxSlope) {
slope = maxSlope;
} else if (slope < -maxSlope) {
slope = -maxSlope;
}
let v = slope / maxSlope;
v = 1 / (1 + Math.exp(-6 * v));
v = v - 0.5;
let hue = ((0.5 - v) * 120).toString(10);
let lightness = 90 - Math.abs(v) * 70;
return ['hsl(', hue, ',70%,', lightness, '%)'].join('');
} }
function surfaceFillCallback(context) { function surfaceFillCallback(context) {
let surface = context.p0.raw.surface; return getSurfaceColor(context.p0.raw.extensions.surface);
return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing; }
function highwayFillCallback(context) {
return getHighwayColor(
context.p0.raw.extensions.highway,
context.p0.raw.extensions.sac_scale,
context.p0.raw.extensions.mtb_scale
);
} }
$: if (chart) { $: if (chart) {
@@ -533,6 +459,10 @@
chart.data.datasets[0]['segment'] = { chart.data.datasets[0]['segment'] = {
backgroundColor: surfaceFillCallback backgroundColor: surfaceFillCallback
}; };
} else if (elevationFill === 'highway') {
chart.data.datasets[0]['segment'] = {
backgroundColor: highwayFillCallback
};
} else { } else {
chart.data.datasets[0]['segment'] = {}; chart.data.datasets[0]['segment'] = {};
} }
@@ -552,12 +482,6 @@
chart.data.datasets[4].hidden = !includeTemperature; chart.data.datasets[4].hidden = !includeTemperature;
chart.data.datasets[5].hidden = !includePower; chart.data.datasets[5].hidden = !includePower;
} }
chart.options.scales[`y${datasets.speed.id}`].display = includeSpeed && showAdditionalScales;
chart.options.scales[`y${datasets.hr.id}`].display = includeHeartRate && showAdditionalScales;
chart.options.scales[`y${datasets.cad.id}`].display = includeCadence && showAdditionalScales;
chart.options.scales[`y${datasets.atemp.id}`].display =
includeTemperature && showAdditionalScales;
chart.options.scales[`y${datasets.power.id}`].display = includePower && showAdditionalScales;
chart.update(); chart.update();
} }
@@ -568,6 +492,8 @@
overlay.width = canvas.width / window.devicePixelRatio; overlay.width = canvas.width / window.devicePixelRatio;
overlay.height = canvas.height / window.devicePixelRatio; overlay.height = canvas.height / window.devicePixelRatio;
overlay.style.width = `${overlay.width}px`;
overlay.style.height = `${overlay.height}px`;
if ($slicedGPXStatistics) { if ($slicedGPXStatistics) {
let startIndex = $slicedGPXStatistics[1]; let startIndex = $slicedGPXStatistics[1];
@@ -591,7 +517,7 @@
startPixel, startPixel,
chart.chartArea.top, chart.chartArea.top,
endPixel - startPixel, endPixel - startPixel,
chart.chartArea.bottom - chart.chartArea.top chart.chartArea.height
); );
} }
} else if (overlay) { } else if (overlay) {
@@ -611,75 +537,135 @@
}); });
</script> </script>
<div class="h-full grow min-w-0 flex flex-row gap-4 items-center {$$props.class ?? ''}"> <div class="h-full grow min-w-0 relative py-2">
<div class="grow h-full min-w-0 relative"> <canvas bind:this={overlay} class="w-full h-full absolute pointer-events-none"></canvas>
<canvas bind:this={overlay} class=" w-full h-full absolute pointer-events-none"></canvas> <canvas bind:this={canvas} class="w-full h-full absolute"></canvas>
<canvas bind:this={canvas} class="w-full h-full"></canvas>
</div>
{#if showControls} {#if showControls}
<div class="h-full flex flex-col justify-center" style="width: {panelSize > 158 ? 22 : 42}px"> <div class="absolute bottom-10 right-1.5">
<ToggleGroup.Root <Popover.Root>
class="{panelSize > 158 <Popover.Trigger asChild let:builder>
? 'flex-col' <ButtonWithTooltip
: 'flex-row'} flex-wrap gap-0 min-h-0 content-center border rounded-t-md" label={$_('chart.settings')}
type="single" builders={[builder]}
bind:value={elevationFill} variant="outline"
> class="w-7 h-7 p-0 flex justify-center opacity-70 hover:opacity-100 transition-opacity duration-300 hover:bg-background"
<ToggleGroup.Item class="p-0 w-5 h-5" value="slope" aria-label={$_('chart.show_slope')}>
<Tooltip side="left" label={$_('chart.show_slope')}>
<TriangleRight size="15" />
</Tooltip>
</ToggleGroup.Item>
<ToggleGroup.Item class="p-0 w-5 h-5" value="surface" aria-label={$_('chart.show_surface')}>
<Tooltip side="left" label={$_('chart.show_surface')}>
<BrickWall size="15" />
</Tooltip>
</ToggleGroup.Item>
</ToggleGroup.Root>
<ToggleGroup.Root
class="{panelSize > 158
? 'flex-col'
: 'flex-row'} flex-wrap gap-0 min-h-0 content-center border rounded-b-md -mt-[1px]"
type="multiple"
bind:value={additionalDatasets}
>
<ToggleGroup.Item
class="p-0 w-5 h-5"
value="speed"
aria-label={$velocityUnits === 'speed' ? $_('chart.show_speed') : $_('chart.show_pace')}
>
<Tooltip
side="left"
label={$velocityUnits === 'speed' ? $_('chart.show_speed') : $_('chart.show_pace')}
> >
<Zap size="15" /> <ChartNoAxesColumn size="18" />
</Tooltip> </ButtonWithTooltip>
</ToggleGroup.Item> </Popover.Trigger>
<ToggleGroup.Item class="p-0 w-5 h-5" value="hr" aria-label={$_('chart.show_heartrate')}> <Popover.Content class="w-fit p-0 flex flex-col divide-y" side="top" sideOffset={-32}>
<Tooltip side="left" label={$_('chart.show_heartrate')}> <ToggleGroup.Root
<HeartPulse size="15" /> class="flex flex-col items-start gap-0 p-1"
</Tooltip> type="single"
</ToggleGroup.Item> bind:value={elevationFill}
<ToggleGroup.Item class="p-0 w-5 h-5" value="cad" aria-label={$_('chart.show_cadence')}> >
<Tooltip side="left" label={$_('chart.show_cadence')}> <ToggleGroup.Item
<Orbit size="15" /> class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
</Tooltip> value="slope"
</ToggleGroup.Item> >
<ToggleGroup.Item <div class="w-6 flex justify-center items-center">
class="p-0 w-5 h-5" {#if elevationFill === 'slope'}
value="atemp" <Circle class="h-1.5 w-1.5 fill-current text-current" />
aria-label={$_('chart.show_temperature')} {/if}
> </div>
<Tooltip side="left" label={$_('chart.show_temperature')}> <TriangleRight size="15" class="mr-1" />
<Thermometer size="15" /> {$_('quantities.slope')}
</Tooltip> </ToggleGroup.Item>
</ToggleGroup.Item> <ToggleGroup.Item
<ToggleGroup.Item class="p-0 w-5 h-5" value="power" aria-label={$_('chart.show_power')}> class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
<Tooltip side="left" label={$_('chart.show_power')}> value="surface"
<SquareActivity size="15" /> variant="outline"
</Tooltip> >
</ToggleGroup.Item> <div class="w-6 flex justify-center items-center">
</ToggleGroup.Root> {#if elevationFill === 'surface'}
<Circle class="h-1.5 w-1.5 fill-current text-current" />
{/if}
</div>
<BrickWall size="15" class="mr-1" />
{$_('quantities.surface')}
</ToggleGroup.Item>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="highway"
variant="outline"
>
<div class="w-6 flex justify-center items-center">
{#if elevationFill === 'highway'}
<Circle class="h-1.5 w-1.5 fill-current text-current" />
{/if}
</div>
<Construction size="15" class="mr-1" />
{$_('quantities.highway')}
</ToggleGroup.Item>
</ToggleGroup.Root>
<ToggleGroup.Root
class="flex flex-col items-start gap-0 p-1"
type="multiple"
bind:value={additionalDatasets}
>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="speed"
>
<div class="w-6 flex justify-center items-center">
{#if additionalDatasets.includes('speed')}
<Check size="14" />
{/if}
</div>
<Zap size="15" class="mr-1" />
{$velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')}
</ToggleGroup.Item>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="hr"
>
<div class="w-6 flex justify-center items-center">
{#if additionalDatasets.includes('hr')}
<Check size="14" />
{/if}
</div>
<HeartPulse size="15" class="mr-1" />
{$_('quantities.heartrate')}
</ToggleGroup.Item>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="cad"
>
<div class="w-6 flex justify-center items-center">
{#if additionalDatasets.includes('cad')}
<Check size="14" />
{/if}
</div>
<Orbit size="15" class="mr-1" />
{$_('quantities.cadence')}
</ToggleGroup.Item>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="atemp"
>
<div class="w-6 flex justify-center items-center">
{#if additionalDatasets.includes('atemp')}
<Check size="14" />
{/if}
</div>
<Thermometer size="15" class="mr-1" />
{$_('quantities.temperature')}
</ToggleGroup.Item>
<ToggleGroup.Item
class="p-0 pr-1.5 h-6 w-full rounded flex justify-start data-[state=on]:bg-background data-[state=on]:hover:bg-accent hover:bg-accent hover:text-foreground"
value="power"
>
<div class="w-6 flex justify-center items-center">
{#if additionalDatasets.includes('power')}
<Check size="14" />
{/if}
</div>
<SquareActivity size="15" class="mr-1" />
{$_('quantities.power')}
</ToggleGroup.Item>
</ToggleGroup.Root>
</Popover.Content>
</Popover.Root>
</div> </div>
{/if} {/if}
</div> </div>

View File

@@ -16,7 +16,7 @@
import { import {
Download, Download,
Zap, Zap,
BrickWall, Earth,
HeartPulse, HeartPulse,
Orbit, Orbit,
Thermometer, Thermometer,
@@ -31,19 +31,19 @@
let open = false; let open = false;
let exportOptions: Record<string, boolean> = { let exportOptions: Record<string, boolean> = {
time: true, time: true,
surface: true,
hr: true, hr: true,
cad: true, cad: true,
atemp: true, atemp: true,
power: true power: true,
extensions: true
}; };
let hide: Record<string, boolean> = { let hide: Record<string, boolean> = {
time: false, time: false,
surface: false,
hr: false, hr: false,
cad: false, cad: false,
atemp: false, atemp: false,
power: false power: false,
extensions: false
}; };
$: if ($exportState !== ExportState.NONE) { $: if ($exportState !== ExportState.NONE) {
@@ -63,11 +63,11 @@
} }
hide.time = statistics.global.time.total === 0; hide.time = statistics.global.time.total === 0;
hide.surface = !Object.keys(statistics.global.surface).some((key) => key !== 'unknown');
hide.hr = statistics.global.hr.count === 0; hide.hr = statistics.global.hr.count === 0;
hide.cad = statistics.global.cad.count === 0; hide.cad = statistics.global.cad.count === 0;
hide.atemp = statistics.global.atemp.count === 0; hide.atemp = statistics.global.atemp.count === 0;
hide.power = statistics.global.power.count === 0; hide.power = statistics.global.power.count === 0;
hide.extensions = Object.keys(statistics.global.extensions).length === 0;
} }
$: exclude = Object.keys(exportOptions).filter((key) => !exportOptions[key]); $: exclude = Object.keys(exportOptions).filter((key) => !exportOptions[key]);
@@ -144,11 +144,11 @@
{$_('quantities.time')} {$_('quantities.time')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-1.5 {hide.surface ? 'hidden' : ''}"> <div class="flex flex-row items-center gap-1.5 {hide.extensions ? 'hidden' : ''}">
<Checkbox id="export-surface" bind:checked={exportOptions.surface} /> <Checkbox id="export-extensions" bind:checked={exportOptions.extensions} />
<Label for="export-surface" class="flex flex-row items-center gap-1"> <Label for="export-extensions" class="flex flex-row items-center gap-1">
<BrickWall size="16" /> <Earth size="16" />
{$_('quantities.surface')} {$_('quantities.osm_extensions')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}"> <div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}">

View File

@@ -28,7 +28,7 @@
<Card.Root <Card.Root
class="h-full {orientation === 'vertical' class="h-full {orientation === 'vertical'
? 'min-w-44 sm:min-w-52 text-sm sm:text-base' ? 'min-w-40 sm:min-w-44 text-sm sm:text-base'
: 'w-full'} border-none shadow-none" : 'w-full'} border-none shadow-none"
> >
<Card.Content <Card.Content
@@ -38,15 +38,15 @@
> >
<Tooltip label={$_('quantities.distance')}> <Tooltip label={$_('quantities.distance')}>
<span class="flex flex-row items-center"> <span class="flex flex-row items-center">
<Ruler size="18" class="mr-1" /> <Ruler size="16" class="mr-1" />
<WithUnits value={statistics.global.distance.total} type="distance" /> <WithUnits value={statistics.global.distance.total} type="distance" />
</span> </span>
</Tooltip> </Tooltip>
<Tooltip label={$_('quantities.elevation_gain_loss')}> <Tooltip label={$_('quantities.elevation_gain_loss')}>
<span class="flex flex-row items-center"> <span class="flex flex-row items-center">
<MoveUpRight size="18" class="mr-1" /> <MoveUpRight size="16" class="mr-1" />
<WithUnits value={statistics.global.elevation.gain} type="elevation" /> <WithUnits value={statistics.global.elevation.gain} type="elevation" />
<MoveDownRight size="18" class="mx-1" /> <MoveDownRight size="16" class="mx-1" />
<WithUnits value={statistics.global.elevation.loss} type="elevation" /> <WithUnits value={statistics.global.elevation.loss} type="elevation" />
</span> </span>
</Tooltip> </Tooltip>
@@ -58,7 +58,7 @@
)} / {$_('quantities.total')})" )} / {$_('quantities.total')})"
> >
<span class="flex flex-row items-center"> <span class="flex flex-row items-center">
<Zap size="18" class="mr-1" /> <Zap size="16" class="mr-1" />
<WithUnits value={statistics.global.speed.moving} type="speed" showUnits={false} /> <WithUnits value={statistics.global.speed.moving} type="speed" showUnits={false} />
<span class="mx-1">/</span> <span class="mx-1">/</span>
<WithUnits value={statistics.global.speed.total} type="speed" /> <WithUnits value={statistics.global.speed.total} type="speed" />
@@ -71,7 +71,7 @@
label="{$_('quantities.time')} ({$_('quantities.moving')} / {$_('quantities.total')})" label="{$_('quantities.time')} ({$_('quantities.moving')} / {$_('quantities.total')})"
> >
<span class="flex flex-row items-center"> <span class="flex flex-row items-center">
<Timer size="18" class="mr-1" /> <Timer size="16" class="mr-1" />
<WithUnits value={statistics.global.time.moving} type="time" /> <WithUnits value={statistics.global.time.moving} type="time" />
<span class="mx-1">/</span> <span class="mx-1">/</span>
<WithUnits value={statistics.global.time.total} type="time" /> <WithUnits value={statistics.global.time.total} type="time" />

View File

@@ -50,6 +50,20 @@
language = 'en'; language = 'en';
} }
const loadJson = mapboxgl.Style.prototype._load;
mapboxgl.Style.prototype._load = function (json, validate) {
if (
json['sources'] &&
json['sources']['mapbox-satellite'] &&
json['sources']['mapbox-satellite']['data'] &&
json['sources']['mapbox-satellite']['data']['data']
) {
// Temporary fix for https://github.com/gpxstudio/gpx.studio/issues/129
delete json['sources']['mapbox-satellite']['data']['data'];
}
loadJson.call(this, json, validate);
};
let newMap = new mapboxgl.Map({ let newMap = new mapboxgl.Map({
container: 'map', container: 'map',
style: { style: {
@@ -334,7 +348,7 @@
div :global(.mapboxgl-popup) { div :global(.mapboxgl-popup) {
@apply w-fit; @apply w-fit;
@apply z-20; @apply z-50;
} }
div :global(.mapboxgl-popup-content) { div :global(.mapboxgl-popup-content) {

View File

@@ -0,0 +1,25 @@
<svelte:options accessors />
<script lang="ts">
import { TrackPoint, Waypoint } from 'gpx';
import type { Writable } from 'svelte/store';
import WaypointPopup from '$lib/components/gpx-layer/WaypointPopup.svelte';
import TrackpointPopup from '$lib/components/gpx-layer/TrackpointPopup.svelte';
import OverpassPopup from '$lib/components/layer-control/OverpassPopup.svelte';
import type { PopupItem } from './MapPopup';
export let item: Writable<PopupItem | null>;
export let container: HTMLDivElement | null = null;
</script>
<div bind:this={container}>
{#if $item}
{#if $item.item instanceof Waypoint}
<WaypointPopup waypoint={$item} />
{:else if $item.item instanceof TrackPoint}
<TrackpointPopup trackpoint={$item} />
{:else}
<OverpassPopup poi={$item} />
{/if}
{/if}
</div>

View File

@@ -0,0 +1,78 @@
import { TrackPoint, Waypoint } from "gpx";
import mapboxgl from "mapbox-gl";
import { tick } from "svelte";
import { get, writable, type Writable } from "svelte/store";
import MapPopupComponent from "./MapPopup.svelte";
export type PopupItem<T = Waypoint | TrackPoint | any> = {
item: T;
fileId?: string;
};
export class MapPopup {
map: mapboxgl.Map;
popup: mapboxgl.Popup;
item: Writable<PopupItem | null> = writable(null);
maybeHideBinded = this.maybeHide.bind(this);
constructor(map: mapboxgl.Map, options?: mapboxgl.PopupOptions) {
this.map = map;
this.popup = new mapboxgl.Popup(options);
let component = new MapPopupComponent({
target: document.body,
props: {
item: this.item
}
});
tick().then(() => this.popup.setDOMContent(component.container));
}
setItem(item: PopupItem | null) {
this.item.set(item);
if (item === null) {
this.hide();
} else {
tick().then(() => this.show());
}
}
show() {
const i = get(this.item);
if (i === null) {
this.hide();
return;
}
this.popup.setLngLat(this.getCoordinates()).addTo(this.map);
this.map.on('mousemove', this.maybeHideBinded);
}
maybeHide(e: mapboxgl.MapMouseEvent) {
const i = get(this.item);
if (i === null) {
this.hide();
return;
}
if (this.map.project(this.getCoordinates()).dist(this.map.project(e.lngLat)) > 60) {
this.hide();
}
}
hide() {
this.popup.remove();
this.map.off('mousemove', this.maybeHideBinded);
}
remove() {
this.popup.remove();
}
getCoordinates() {
const i = get(this.item);
if (i === null) {
return new mapboxgl.LngLat(0, 0);
}
return (i.item instanceof Waypoint || i.item instanceof TrackPoint) ? i.item.getCoordinates() : new mapboxgl.LngLat(i.item.lon, i.item.lat);
}
}

View File

@@ -260,9 +260,7 @@
options.elevation.power ? 'power' : null options.elevation.power ? 'power' : null
].filter((dataset) => dataset !== null)} ].filter((dataset) => dataset !== null)}
elevationFill={options.elevation.fill} elevationFill={options.elevation.fill}
panelSize={options.elevation.height}
showControls={options.elevation.controls} showControls={options.elevation.controls}
class="py-2"
/> />
{/if} {/if}
</div> </div>

View File

@@ -10,7 +10,7 @@ export type EmbeddingOptions = {
show: boolean; show: boolean;
height: number; height: number;
controls: boolean; controls: boolean;
fill: 'slope' | 'surface' | undefined; fill: 'slope' | 'surface' | 'highway' | undefined;
speed: boolean; speed: boolean;
hr: boolean; hr: boolean;
cad: boolean; cad: boolean;

View File

@@ -142,7 +142,7 @@
let value = selected?.value; let value = selected?.value;
if (value === 'none') { if (value === 'none') {
options.elevation.fill = undefined; options.elevation.fill = undefined;
} else if (value === 'slope' || value === 'surface') { } else if (value === 'slope' || value === 'surface' || value === 'highway') {
options.elevation.fill = value; options.elevation.fill = value;
} }
}} }}
@@ -153,6 +153,7 @@
<Select.Content> <Select.Content>
<Select.Item value="slope">{$_('quantities.slope')}</Select.Item> <Select.Item value="slope">{$_('quantities.slope')}</Select.Item>
<Select.Item value="surface">{$_('quantities.surface')}</Select.Item> <Select.Item value="surface">{$_('quantities.surface')}</Select.Item>
<Select.Item value="highway">{$_('quantities.highway')}</Select.Item>
<Select.Item value="none">{$_('embedding.none')}</Select.Item> <Select.Item value="none">{$_('embedding.none')}</Select.Item>
</Select.Content> </Select.Content>
</Select.Root> </Select.Root>
@@ -165,35 +166,35 @@
<Checkbox id="show-speed" bind:checked={options.elevation.speed} /> <Checkbox id="show-speed" bind:checked={options.elevation.speed} />
<Label for="show-speed" class="flex flex-row items-center gap-1"> <Label for="show-speed" class="flex flex-row items-center gap-1">
<Zap size="16" /> <Zap size="16" />
{$_('chart.show_speed')} {$_('quantities.speed')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-2"> <div class="flex flex-row items-center gap-2">
<Checkbox id="show-hr" bind:checked={options.elevation.hr} /> <Checkbox id="show-hr" bind:checked={options.elevation.hr} />
<Label for="show-hr" class="flex flex-row items-center gap-1"> <Label for="show-hr" class="flex flex-row items-center gap-1">
<HeartPulse size="16" /> <HeartPulse size="16" />
{$_('chart.show_heartrate')} {$_('quantities.heartrate')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-2"> <div class="flex flex-row items-center gap-2">
<Checkbox id="show-cad" bind:checked={options.elevation.cad} /> <Checkbox id="show-cad" bind:checked={options.elevation.cad} />
<Label for="show-cad" class="flex flex-row items-center gap-1"> <Label for="show-cad" class="flex flex-row items-center gap-1">
<Orbit size="16" /> <Orbit size="16" />
{$_('chart.show_cadence')} {$_('quantities.cadence')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-2"> <div class="flex flex-row items-center gap-2">
<Checkbox id="show-temp" bind:checked={options.elevation.temp} /> <Checkbox id="show-temp" bind:checked={options.elevation.temp} />
<Label for="show-temp" class="flex flex-row items-center gap-1"> <Label for="show-temp" class="flex flex-row items-center gap-1">
<Thermometer size="16" /> <Thermometer size="16" />
{$_('chart.show_temperature')} {$_('quantities.temperature')}
</Label> </Label>
</div> </div>
<div class="flex flex-row items-center gap-2"> <div class="flex flex-row items-center gap-2">
<Checkbox id="show-power" bind:checked={options.elevation.power} /> <Checkbox id="show-power" bind:checked={options.elevation.power} />
<Label for="show-power" class="flex flex-row items-center gap-1"> <Label for="show-power" class="flex flex-row items-center gap-1">
<SquareActivity size="16" /> <SquareActivity size="16" />
{$_('chart.show_power')} {$_('quantities.power')}
</Label> </Label>
</div> </div>
</div> </div>

View File

@@ -49,17 +49,11 @@
gpxLayers, gpxLayers,
map map
} from '$lib/stores'; } from '$lib/stores';
import { import { GPXTreeElement, Track, type AnyGPXTreeElement, Waypoint, GPXFile } from 'gpx';
GPXTreeElement,
Track,
TrackSegment,
type AnyGPXTreeElement,
Waypoint,
GPXFile
} from 'gpx';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import MetadataDialog from './MetadataDialog.svelte'; import MetadataDialog from './MetadataDialog.svelte';
import StyleDialog from './StyleDialog.svelte'; import StyleDialog from './StyleDialog.svelte';
import { waypointPopup } from '$lib/components/gpx-layer/GPXLayerPopup';
export let node: GPXTreeElement<AnyGPXTreeElement> | Waypoint[] | Waypoint; export let node: GPXTreeElement<AnyGPXTreeElement> | Waypoint[] | Waypoint;
export let item: ListItem; export let item: ListItem;
@@ -179,7 +173,7 @@
if (layer && file) { if (layer && file) {
let waypoint = file.wpt[item.getWaypointIndex()]; let waypoint = file.wpt[item.getWaypointIndex()];
if (waypoint) { if (waypoint) {
layer.showWaypointPopup(waypoint); waypointPopup?.setItem({ item: waypoint, fileId: item.getFileId() });
} }
} }
} }
@@ -188,7 +182,7 @@
if (item instanceof ListWaypointItem) { if (item instanceof ListWaypointItem) {
let layer = gpxLayers.get(item.getFileId()); let layer = gpxLayers.get(item.getFileId());
if (layer) { if (layer) {
layer.hideWaypointPopup(); waypointPopup?.setItem(null);
} }
} }
}} }}

View File

@@ -5,6 +5,8 @@ import { get } from "svelte/store";
const { distanceMarkers, distanceUnits } = settings; const { distanceMarkers, distanceUnits } = settings;
const stops = [[100, 0], [50, 7], [25, 8, 10], [10, 10], [5, 11], [1, 13]];
export class DistanceMarkers { export class DistanceMarkers {
map: mapboxgl.Map; map: mapboxgl.Map;
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
@@ -31,30 +33,36 @@ export class DistanceMarkers {
data: this.getDistanceMarkersGeoJSON() data: this.getDistanceMarkersGeoJSON()
}); });
} }
if (!this.map.getLayer('distance-markers')) { stops.forEach(([d, minzoom, maxzoom]) => {
this.map.addLayer({ if (!this.map.getLayer(`distance-markers-${d}`)) {
id: 'distance-markers', this.map.addLayer({
type: 'symbol', id: `distance-markers-${d}`,
source: 'distance-markers', type: 'symbol',
layout: { source: 'distance-markers',
'text-field': ['get', 'distance'], filter: d === 5 ? ['any', ['==', ['get', 'level'], 5], ['==', ['get', 'level'], 25]] : ['==', ['get', 'level'], d],
'text-size': 14, minzoom: minzoom,
'text-font': ['Open Sans Bold'], maxzoom: maxzoom ?? 24,
'text-padding': 20, layout: {
}, 'text-field': ['get', 'distance'],
paint: { 'text-size': 14,
'text-color': 'black', 'text-font': ['Open Sans Bold'],
'text-halo-width': 2, },
'text-halo-color': 'white', paint: {
} 'text-color': 'black',
}); 'text-halo-width': 2,
} else { 'text-halo-color': 'white',
this.map.moveLayer('distance-markers'); }
} });
} else {
this.map.moveLayer(`distance-markers-${d}`);
}
});
} else { } else {
if (this.map.getLayer('distance-markers')) { stops.forEach(([d]) => {
this.map.removeLayer('distance-markers'); if (this.map.getLayer(`distance-markers-${d}`)) {
} this.map.removeLayer(`distance-markers-${d}`);
}
});
} }
} catch (e) { // No reliable way to check if the map is ready to add sources and layers } catch (e) { // No reliable way to check if the map is ready to add sources and layers
return; return;
@@ -73,6 +81,7 @@ export class DistanceMarkers {
for (let i = 0; i < statistics.local.distance.total.length; i++) { for (let i = 0; i < statistics.local.distance.total.length; i++) {
if (statistics.local.distance.total[i] >= currentTargetDistance * (get(distanceUnits) === 'metric' ? 1 : 1.60934)) { if (statistics.local.distance.total[i] >= currentTargetDistance * (get(distanceUnits) === 'metric' ? 1 : 1.60934)) {
let distance = currentTargetDistance.toFixed(0); let distance = currentTargetDistance.toFixed(0);
let [level, minzoom] = stops.find(([d]) => currentTargetDistance % d === 0) ?? [0, 0];
features.push({ features.push({
type: 'Feature', type: 'Feature',
geometry: { geometry: {
@@ -81,6 +90,8 @@ export class DistanceMarkers {
}, },
properties: { properties: {
distance, distance,
level,
minzoom,
} }
} as GeoJSON.Feature); } as GeoJSON.Feature);
currentTargetDistance += 1; currentTargetDistance += 1;

View File

@@ -2,11 +2,10 @@ import { currentTool, map, Tool } from "$lib/stores";
import { settings, type GPXFileWithStatistics, dbUtils } from "$lib/db"; import { settings, type GPXFileWithStatistics, dbUtils } from "$lib/db";
import { get, type Readable } from "svelte/store"; import { get, type Readable } from "svelte/store";
import mapboxgl from "mapbox-gl"; import mapboxgl from "mapbox-gl";
import { currentPopupWaypoint, deleteWaypoint, waypointPopup } from "./WaypointPopup"; import { waypointPopup, deleteWaypoint, trackpointPopup } from "./GPXLayerPopup";
import { addSelectItem, selectItem, selection } from "$lib/components/file-list/Selection"; import { addSelectItem, selectItem, selection } from "$lib/components/file-list/Selection";
import { ListTrackSegmentItem, ListWaypointItem, ListWaypointsItem, ListTrackItem, ListFileItem, ListRootItem } from "$lib/components/file-list/FileList"; import { ListTrackSegmentItem, ListWaypointItem, ListWaypointsItem, ListTrackItem, ListFileItem, ListRootItem } from "$lib/components/file-list/FileList";
import type { Waypoint } from "gpx"; import { getClosestLinePoint, getElevation, resetCursor, setGrabbingCursor, setPointerCursor, setScissorsCursor } from "$lib/utils";
import { getElevation, resetCursor, setGrabbingCursor, setPointerCursor, setScissorsCursor } from "$lib/utils";
import { selectedWaypoint } from "$lib/components/toolbar/tools/Waypoint.svelte"; import { selectedWaypoint } from "$lib/components/toolbar/tools/Waypoint.svelte";
import { MapPin, Square } from "lucide-static"; import { MapPin, Square } from "lucide-static";
import { getSymbolKey, symbols } from "$lib/assets/symbols"; import { getSymbolKey, symbols } from "$lib/assets/symbols";
@@ -43,6 +42,31 @@ function decrementColor(color: string) {
} }
} }
const inspectKey = 'Shift';
let inspectKeyDown: KeyDown | null = null;
class KeyDown {
key: string;
down: boolean = false;
constructor(key: string) {
this.key = key;
document.addEventListener('keydown', this.onKeyDown);
document.addEventListener('keyup', this.onKeyUp);
}
onKeyDown = (e: KeyboardEvent) => {
if (e.key === this.key) {
this.down = true;
}
}
onKeyUp = (e: KeyboardEvent) => {
if (e.key === this.key) {
this.down = false;
}
}
isDown() {
return this.down;
}
}
function getMarkerForSymbol(symbol: string | undefined, layerColor: string) { function getMarkerForSymbol(symbol: string | undefined, layerColor: string) {
let symbolSvg = symbol ? symbols[symbol]?.iconSvg : undefined; let symbolSvg = symbol ? symbols[symbol]?.iconSvg : undefined;
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
@@ -80,9 +104,9 @@ export class GPXLayer {
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
layerOnMouseEnterBinded: (e: any) => void = this.layerOnMouseEnter.bind(this); layerOnMouseEnterBinded: (e: any) => void = this.layerOnMouseEnter.bind(this);
layerOnMouseLeaveBinded: () => void = this.layerOnMouseLeave.bind(this); layerOnMouseLeaveBinded: () => void = this.layerOnMouseLeave.bind(this);
layerOnMouseMoveBinded: (e: any) => void = this.layerOnMouseMove.bind(this);
layerOnClickBinded: (e: any) => void = this.layerOnClick.bind(this); layerOnClickBinded: (e: any) => void = this.layerOnClick.bind(this);
layerOnContextMenuBinded: (e: any) => void = this.layerOnContextMenu.bind(this); layerOnContextMenuBinded: (e: any) => void = this.layerOnContextMenu.bind(this);
maybeHideWaypointPopupBinded: (e: any) => void = this.maybeHideWaypointPopup.bind(this);
constructor(map: mapboxgl.Map, fileId: string, file: Readable<GPXFileWithStatistics | undefined>) { constructor(map: mapboxgl.Map, fileId: string, file: Readable<GPXFileWithStatistics | undefined>) {
this.map = map; this.map = map;
@@ -113,6 +137,10 @@ export class GPXLayer {
this.draggable = get(currentTool) === Tool.WAYPOINT; this.draggable = get(currentTool) === Tool.WAYPOINT;
this.map.on('style.import.load', this.updateBinded); this.map.on('style.import.load', this.updateBinded);
if (inspectKeyDown === null) {
inspectKeyDown = new KeyDown(inspectKey);
}
} }
update() { update() {
@@ -157,6 +185,7 @@ export class GPXLayer {
this.map.on('contextmenu', this.fileId, this.layerOnContextMenuBinded); this.map.on('contextmenu', this.fileId, this.layerOnContextMenuBinded);
this.map.on('mouseenter', this.fileId, this.layerOnMouseEnterBinded); this.map.on('mouseenter', this.fileId, this.layerOnMouseEnterBinded);
this.map.on('mouseleave', this.fileId, this.layerOnMouseLeaveBinded); this.map.on('mouseleave', this.fileId, this.layerOnMouseLeaveBinded);
this.map.on('mousemove', this.fileId, this.layerOnMouseMoveBinded);
} }
if (get(directionMarkers)) { if (get(directionMarkers)) {
@@ -224,11 +253,11 @@ export class GPXLayer {
}).setLngLat(waypoint.getCoordinates()); }).setLngLat(waypoint.getCoordinates());
Object.defineProperty(marker, '_waypoint', { value: waypoint, writable: true }); Object.defineProperty(marker, '_waypoint', { value: waypoint, writable: true });
let dragEndTimestamp = 0; let dragEndTimestamp = 0;
marker.getElement().addEventListener('mouseover', (e) => { marker.getElement().addEventListener('mousemove', (e) => {
if (marker._isDragging) { if (marker._isDragging) {
return; return;
} }
this.showWaypointPopup(marker._waypoint); waypointPopup?.setItem({ item: marker._waypoint, fileId: this.fileId });
e.stopPropagation(); e.stopPropagation();
}); });
marker.getElement().addEventListener('click', (e) => { marker.getElement().addEventListener('click', (e) => {
@@ -251,14 +280,14 @@ export class GPXLayer {
} else if (get(currentTool) === Tool.WAYPOINT) { } else if (get(currentTool) === Tool.WAYPOINT) {
selectedWaypoint.set([marker._waypoint, this.fileId]); selectedWaypoint.set([marker._waypoint, this.fileId]);
} else { } else {
this.showWaypointPopup(marker._waypoint); waypointPopup?.setItem({ item: marker._waypoint, fileId: this.fileId });
} }
e.stopPropagation(); e.stopPropagation();
}); });
marker.on('dragstart', () => { marker.on('dragstart', () => {
setGrabbingCursor(); setGrabbingCursor();
marker.getElement().style.cursor = 'grabbing'; marker.getElement().style.cursor = 'grabbing';
this.hideWaypointPopup(); waypointPopup?.hide();
}); });
marker.on('dragend', (e) => { marker.on('dragend', (e) => {
resetCursor(); resetCursor();
@@ -307,6 +336,7 @@ export class GPXLayer {
this.map.off('contextmenu', this.fileId, this.layerOnContextMenuBinded); this.map.off('contextmenu', this.fileId, this.layerOnContextMenuBinded);
this.map.off('mouseenter', this.fileId, this.layerOnMouseEnterBinded); this.map.off('mouseenter', this.fileId, this.layerOnMouseEnterBinded);
this.map.off('mouseleave', this.fileId, this.layerOnMouseLeaveBinded); this.map.off('mouseleave', this.fileId, this.layerOnMouseLeaveBinded);
this.map.off('mousemove', this.fileId, this.layerOnMouseMoveBinded);
this.map.off('style.import.load', this.updateBinded); this.map.off('style.import.load', this.updateBinded);
if (this.map.getLayer(this.fileId + '-direction')) { if (this.map.getLayer(this.fileId + '-direction')) {
@@ -353,6 +383,19 @@ export class GPXLayer {
resetCursor(); resetCursor();
} }
layerOnMouseMove(e: any) {
if (inspectKeyDown?.isDown()) {
let trackIndex = e.features[0].properties.trackIndex;
let segmentIndex = e.features[0].properties.segmentIndex;
const file = get(this.file)?.file;
if (file) {
const closest = getClosestLinePoint(file.trk[trackIndex].trkseg[segmentIndex].trkpt, { lat: e.lngLat.lat, lon: e.lngLat.lng });
trackpointPopup?.setItem({ item: closest, fileId: this.fileId });
}
}
}
layerOnClick(e: any) { layerOnClick(e: any) {
if (get(currentTool) === Tool.ROUTING && get(selection).hasAnyChildren(new ListRootItem(), true, ['waypoints'])) { if (get(currentTool) === Tool.ROUTING && get(selection).hasAnyChildren(new ListRootItem(), true, ['waypoints'])) {
return; return;
@@ -391,43 +434,6 @@ export class GPXLayer {
} }
} }
showWaypointPopup(waypoint: Waypoint) {
if (get(currentPopupWaypoint) !== null) {
this.hideWaypointPopup();
}
let marker = this.markers[waypoint._data.index];
if (marker) {
currentPopupWaypoint.set([waypoint, this.fileId]);
marker.setPopup(waypointPopup);
marker.togglePopup();
this.map.on('mousemove', this.maybeHideWaypointPopupBinded);
}
}
maybeHideWaypointPopup(e: any) {
let waypoint = get(currentPopupWaypoint)?.[0];
if (waypoint) {
let marker = this.markers[waypoint._data.index];
if (marker) {
if (this.map.project(marker.getLngLat()).dist(this.map.project(e.lngLat)) > 100) {
this.hideWaypointPopup();
}
} else {
this.hideWaypointPopup();
}
}
}
hideWaypointPopup() {
let waypoint = get(currentPopupWaypoint)?.[0];
if (waypoint) {
let marker = this.markers[waypoint._data.index];
marker?.getPopup()?.remove();
currentPopupWaypoint.set(null);
this.map.off('mousemove', this.maybeHideWaypointPopupBinded);
}
}
getGeoJSON(): GeoJSON.FeatureCollection { getGeoJSON(): GeoJSON.FeatureCollection {
let file = get(this.file)?.file; let file = get(this.file)?.file;
if (!file) { if (!file) {

View File

@@ -0,0 +1,44 @@
import { dbUtils } from "$lib/db";
import { MapPopup } from "$lib/components/MapPopup";
export let waypointPopup: MapPopup | null = null;
export let trackpointPopup: MapPopup | null = null;
export function createPopups(map: mapboxgl.Map) {
removePopups();
waypointPopup = new MapPopup(map, {
closeButton: false,
focusAfterOpen: false,
maxWidth: undefined,
offset: {
'top': [0, 0],
'top-left': [0, 0],
'top-right': [0, 0],
'bottom': [0, -30],
'bottom-left': [0, -30],
'bottom-right': [0, -30],
'left': [10, -15],
'right': [-10, -15],
},
});
trackpointPopup = new MapPopup(map, {
closeButton: false,
focusAfterOpen: false,
maxWidth: undefined,
});
}
export function removePopups() {
if (waypointPopup !== null) {
waypointPopup.remove();
waypointPopup = null;
}
if (trackpointPopup !== null) {
trackpointPopup.remove();
trackpointPopup = null;
}
}
export function deleteWaypoint(fileId: string, waypointIndex: number) {
dbUtils.applyToFile(fileId, (file) => file.replaceWaypoints(waypointIndex, waypointIndex, []));
}

View File

@@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
import { map, gpxLayers } from '$lib/stores'; import { map, gpxLayers } from '$lib/stores';
import { GPXLayer } from './GPXLayer'; import { GPXLayer } from './GPXLayer';
import WaypointPopup from './WaypointPopup.svelte';
import { fileObservers } from '$lib/db'; import { fileObservers } from '$lib/db';
import { DistanceMarkers } from './DistanceMarkers'; import { DistanceMarkers } from './DistanceMarkers';
import { StartEndMarkers } from './StartEndMarkers'; import { StartEndMarkers } from './StartEndMarkers';
import { onDestroy } from 'svelte'; import { onDestroy } from 'svelte';
import { createPopups, removePopups } from './GPXLayerPopup';
let distanceMarkers: DistanceMarkers | undefined = undefined; let distanceMarkers: DistanceMarkers | undefined = undefined;
let startEndMarkers: StartEndMarkers | undefined = undefined; let startEndMarkers: StartEndMarkers | undefined = undefined;
@@ -35,6 +35,7 @@
if (startEndMarkers) { if (startEndMarkers) {
startEndMarkers.remove(); startEndMarkers.remove();
} }
createPopups($map);
distanceMarkers = new DistanceMarkers($map); distanceMarkers = new DistanceMarkers($map);
startEndMarkers = new StartEndMarkers($map); startEndMarkers = new StartEndMarkers($map);
} }
@@ -42,17 +43,14 @@
onDestroy(() => { onDestroy(() => {
gpxLayers.forEach((layer) => layer.remove()); gpxLayers.forEach((layer) => layer.remove());
gpxLayers.clear(); gpxLayers.clear();
removePopups();
if (distanceMarkers) { if (distanceMarkers) {
distanceMarkers.remove(); distanceMarkers.remove();
distanceMarkers = undefined; distanceMarkers = undefined;
} }
if (startEndMarkers) { if (startEndMarkers) {
startEndMarkers.remove(); startEndMarkers.remove();
startEndMarkers = undefined; startEndMarkers = undefined;
} }
}); });
</script> </script>
<WaypointPopup />

View File

@@ -0,0 +1,36 @@
<script lang="ts">
import type { TrackPoint } from 'gpx';
import type { PopupItem } from '$lib/components/MapPopup';
import * as Card from '$lib/components/ui/card';
import WithUnits from '$lib/components/WithUnits.svelte';
import { Compass, Mountain, Timer } from 'lucide-svelte';
import { df } from '$lib/utils';
export let trackpoint: PopupItem<TrackPoint>;
</script>
<Card.Root class="border-none shadow-md text-base p-2">
<Card.Header class="p-0">
<Card.Title class="text-md"></Card.Title>
</Card.Header>
<Card.Content class="flex flex-col p-0 text-xs gap-1">
<div class="flex flex-row items-center gap-1">
<Compass size="14" />
{trackpoint.item.getLatitude().toFixed(6)}&deg; {trackpoint.item
.getLongitude()
.toFixed(6)}&deg;
</div>
{#if trackpoint.item.ele !== undefined}
<div class="flex flex-row items-center gap-1">
<Mountain size="14" />
<WithUnits value={trackpoint.item.ele} type="elevation" />
</div>
{/if}
{#if trackpoint.item.time}
<div class="flex flex-row items-center gap-1">
<Timer size="14" />
{df.format(trackpoint.item.time)}
</div>
{/if}
</Card.Content>
</Card.Root>

View File

@@ -2,23 +2,20 @@
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import Shortcut from '$lib/components/Shortcut.svelte'; import Shortcut from '$lib/components/Shortcut.svelte';
import { waypointPopup, currentPopupWaypoint, deleteWaypoint } from './WaypointPopup'; import { deleteWaypoint } from './GPXLayerPopup';
import WithUnits from '$lib/components/WithUnits.svelte'; import WithUnits from '$lib/components/WithUnits.svelte';
import { Dot, ExternalLink, Trash2 } from 'lucide-svelte'; import { Dot, ExternalLink, Trash2 } from 'lucide-svelte';
import { onMount } from 'svelte';
import { Tool, currentTool } from '$lib/stores'; import { Tool, currentTool } from '$lib/stores';
import { getSymbolKey, symbols } from '$lib/assets/symbols'; import { getSymbolKey, symbols } from '$lib/assets/symbols';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import sanitizeHtml from 'sanitize-html'; import sanitizeHtml from 'sanitize-html';
import type { Waypoint } from 'gpx';
import type { PopupItem } from '$lib/components/MapPopup';
import { ScrollArea } from '$lib/components/ui/scroll-area/index.js';
let popupElement: HTMLDivElement; export let waypoint: PopupItem<Waypoint>;
onMount(() => { $: symbolKey = waypoint ? getSymbolKey(waypoint.item.sym) : undefined;
waypointPopup.setDOMContent(popupElement);
popupElement.classList.remove('hidden');
});
$: symbolKey = $currentPopupWaypoint ? getSymbolKey($currentPopupWaypoint[0].sym) : undefined;
function sanitize(text: string | undefined): string { function sanitize(text: string | undefined): string {
if (text === undefined) { if (text === undefined) {
@@ -34,68 +31,63 @@
} }
</script> </script>
<div bind:this={popupElement} class="hidden"> <Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]">
{#if $currentPopupWaypoint} <Card.Header class="p-0">
<Card.Root class="border-none shadow-md text-base max-w-80 p-2"> <Card.Title class="text-md">
<Card.Header class="p-0"> {#if waypoint.item.link && waypoint.item.link.attributes && waypoint.item.link.attributes.href}
<Card.Title class="text-md"> <a href={waypoint.item.link.attributes.href} target="_blank">
{#if $currentPopupWaypoint[0].link && $currentPopupWaypoint[0].link.attributes && $currentPopupWaypoint[0].link.attributes.href} {waypoint.item.name ?? waypoint.item.link.attributes.href}
<a href={$currentPopupWaypoint[0].link.attributes.href} target="_blank"> <ExternalLink size="12" class="inline-block mb-1.5" />
{$currentPopupWaypoint[0].name ?? $currentPopupWaypoint[0].link.attributes.href} </a>
<ExternalLink size="12" class="inline-block mb-1.5" /> {:else}
</a> {waypoint.item.name ?? $_('gpx.waypoint')}
{/if}
</Card.Title>
</Card.Header>
<Card.Content class="flex flex-col text-sm p-0">
<div class="flex flex-row items-center text-muted-foreground text-xs whitespace-nowrap">
{#if symbolKey}
<span>
{#if symbols[symbolKey].icon}
<svelte:component
this={symbols[symbolKey].icon}
size="12"
class="inline-block mb-0.5"
/>
{:else} {:else}
{$currentPopupWaypoint[0].name ?? $_('gpx.waypoint')} <span class="w-4 inline-block" />
{/if} {/if}
</Card.Title> {$_(`gpx.symbol.${symbolKey}`)}
</Card.Header> </span>
<Card.Content class="flex flex-col p-0 text-sm"> <Dot size="16" />
<div class="flex flex-row items-center text-muted-foreground text-xs whitespace-nowrap"> {/if}
{#if symbolKey} {waypoint.item.getLatitude().toFixed(6)}&deg; {waypoint.item.getLongitude().toFixed(6)}&deg;
<span> {#if waypoint.item.ele !== undefined}
{#if symbols[symbolKey].icon} <Dot size="16" />
<svelte:component <WithUnits value={waypoint.item.ele} type="elevation" />
this={symbols[symbolKey].icon} {/if}
size="12" </div>
class="inline-block mb-0.5" <ScrollArea class="flex flex-col" viewportClasses="max-h-[30dvh]">
/> {#if waypoint.item.desc}
{:else} <span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.desc)}</span>
<span class="w-4 inline-block" /> {/if}
{/if} {#if waypoint.item.cmt && waypoint.item.cmt !== waypoint.item.desc}
{$_(`gpx.symbol.${symbolKey}`)} <span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.cmt)}</span>
</span> {/if}
<Dot size="16" /> </ScrollArea>
{/if} {#if $currentTool === Tool.WAYPOINT}
{$currentPopupWaypoint[0].getLatitude().toFixed(6)}&deg; {$currentPopupWaypoint[0] <Button
.getLongitude() class="mt-2 w-full px-2 py-1 h-8 justify-start"
.toFixed(6)}&deg; variant="outline"
{#if $currentPopupWaypoint[0].ele !== undefined} on:click={() => deleteWaypoint(waypoint.fileId, waypoint.item._data.index)}
<Dot size="16" /> >
<WithUnits value={$currentPopupWaypoint[0].ele} type="elevation" /> <Trash2 size="16" class="mr-1" />
{/if} {$_('menu.delete')}
</div> <Shortcut shift={true} click={true} />
{#if $currentPopupWaypoint[0].desc} </Button>
<span class="whitespace-pre-wrap">{@html sanitize($currentPopupWaypoint[0].desc)}</span> {/if}
{/if} </Card.Content>
{#if $currentPopupWaypoint[0].cmt && $currentPopupWaypoint[0].cmt !== $currentPopupWaypoint[0].desc} </Card.Root>
<span class="whitespace-pre-wrap">{@html sanitize($currentPopupWaypoint[0].cmt)}</span>
{/if}
{#if $currentTool === Tool.WAYPOINT}
<Button
class="mt-2 w-full px-2 py-1 h-8 justify-start"
variant="outline"
on:click={() =>
deleteWaypoint($currentPopupWaypoint[1], $currentPopupWaypoint[0]._data.index)}
>
<Trash2 size="16" class="mr-1" />
{$_('menu.delete')}
<Shortcut shift={true} click={true} />
</Button>
{/if}
</Card.Content>
</Card.Root>
{/if}
</div>
<style lang="postcss"> <style lang="postcss">
div :global(a) { div :global(a) {

View File

@@ -1,25 +0,0 @@
import { dbUtils } from "$lib/db";
import type { Waypoint } from "gpx";
import mapboxgl from "mapbox-gl";
import { writable } from "svelte/store";
export const currentPopupWaypoint = writable<[Waypoint, string] | null>(null);
export const waypointPopup = new mapboxgl.Popup({
closeButton: false,
maxWidth: undefined,
offset: {
'top': [0, 0],
'top-left': [0, 0],
'top-right': [0, 0],
'bottom': [0, -30],
'bottom-left': [0, -30],
'bottom-right': [0, -30],
'left': [0, 0],
'right': [0, 0]
},
});
export function deleteWaypoint(fileId: string, waypointIndex: number) {
dbUtils.applyToFile(fileId, (file) => file.replaceWaypoints(waypointIndex, waypointIndex, []));
}

View File

@@ -1,435 +1,422 @@
<script lang="ts"> <script lang="ts">
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { Input } from '$lib/components/ui/input'; import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label'; import { Label } from '$lib/components/ui/label';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { Separator } from '$lib/components/ui/separator'; import { Separator } from '$lib/components/ui/separator';
import * as RadioGroup from '$lib/components/ui/radio-group'; import * as RadioGroup from '$lib/components/ui/radio-group';
import { import {
CirclePlus, CirclePlus,
CircleX, CircleX,
Minus, Minus,
Pencil, Pencil,
Plus, Plus,
Save, Save,
Trash2, Trash2,
Move, Move,
Map, Map,
Layers2 Layers2
} from 'lucide-svelte'; } from 'lucide-svelte';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { settings } from '$lib/db'; import { settings } from '$lib/db';
import { defaultBasemap, type CustomLayer } from '$lib/assets/layers'; import { defaultBasemap, type CustomLayer } from '$lib/assets/layers';
import { map } from '$lib/stores'; import { map } from '$lib/stores';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import Sortable from 'sortablejs/Sortable'; import Sortable from 'sortablejs/Sortable';
import { customBasemapUpdate } from './utils'; import { customBasemapUpdate } from './utils';
const { const {
customLayers, customLayers,
selectedBasemapTree, selectedBasemapTree,
selectedOverlayTree, selectedOverlayTree,
currentBasemap, currentBasemap,
previousBasemap, previousBasemap,
currentOverlays, currentOverlays,
previousOverlays, previousOverlays,
customBasemapOrder, customBasemapOrder,
customOverlayOrder customOverlayOrder
} = settings; } = settings;
let name: string = ''; let name: string = '';
let tileUrls: string[] = ['']; let tileUrls: string[] = [''];
let maxZoom: number = 20; let maxZoom: number = 20;
let layerType: 'basemap' | 'overlay' = 'basemap'; let layerType: 'basemap' | 'overlay' = 'basemap';
let resourceType: 'raster' | 'vector' = 'raster'; let resourceType: 'raster' | 'vector' = 'raster';
let basemapContainer: HTMLElement; let basemapContainer: HTMLElement;
let overlayContainer: HTMLElement; let overlayContainer: HTMLElement;
let basemapSortable: Sortable; let basemapSortable: Sortable;
let overlaySortable: Sortable; let overlaySortable: Sortable;
onMount(() => { onMount(() => {
if ($customBasemapOrder.length === 0) { if ($customBasemapOrder.length === 0) {
$customBasemapOrder = Object.keys($customLayers).filter( $customBasemapOrder = Object.keys($customLayers).filter(
(id) => $customLayers[id].layerType === 'basemap' (id) => $customLayers[id].layerType === 'basemap'
); );
} }
if ($customOverlayOrder.length === 0) { if ($customOverlayOrder.length === 0) {
$customOverlayOrder = Object.keys($customLayers).filter( $customOverlayOrder = Object.keys($customLayers).filter(
(id) => $customLayers[id].layerType === 'overlay' (id) => $customLayers[id].layerType === 'overlay'
); );
} }
basemapSortable = Sortable.create(basemapContainer, { basemapSortable = Sortable.create(basemapContainer, {
onSort: (e) => { onSort: (e) => {
$customBasemapOrder = basemapSortable.toArray(); $customBasemapOrder = basemapSortable.toArray();
$selectedBasemapTree.basemaps['custom'] = $customBasemapOrder.reduce((acc, id) => { $selectedBasemapTree.basemaps['custom'] = $customBasemapOrder.reduce((acc, id) => {
acc[id] = true; acc[id] = true;
return acc; return acc;
}, {}); }, {});
} }
}); });
overlaySortable = Sortable.create(overlayContainer, { overlaySortable = Sortable.create(overlayContainer, {
onSort: (e) => { onSort: (e) => {
$customOverlayOrder = overlaySortable.toArray(); $customOverlayOrder = overlaySortable.toArray();
$selectedOverlayTree.overlays['custom'] = $customOverlayOrder.reduce((acc, id) => { $selectedOverlayTree.overlays['custom'] = $customOverlayOrder.reduce((acc, id) => {
acc[id] = true; acc[id] = true;
return acc; return acc;
}, {}); }, {});
} }
}); });
basemapSortable.sort($customBasemapOrder); basemapSortable.sort($customBasemapOrder);
overlaySortable.sort($customOverlayOrder); overlaySortable.sort($customOverlayOrder);
}); });
onDestroy(() => { onDestroy(() => {
basemapSortable.destroy(); basemapSortable.destroy();
overlaySortable.destroy(); overlaySortable.destroy();
}); });
$: if (tileUrls[0].length > 0) { $: if (tileUrls[0].length > 0) {
if ( if (
tileUrls[0].includes('.json') || tileUrls[0].includes('.json') ||
(tileUrls[0].includes('api.mapbox.com/styles') && !tileUrls[0].includes('tiles')) (tileUrls[0].includes('api.mapbox.com/styles') && !tileUrls[0].includes('tiles'))
) { ) {
resourceType = 'vector'; resourceType = 'vector';
} else { } else {
resourceType = 'raster'; resourceType = 'raster';
} }
} }
function createLayer() { function createLayer() {
if (selectedLayerId && $customLayers[selectedLayerId].layerType !== layerType) { if (selectedLayerId && $customLayers[selectedLayerId].layerType !== layerType) {
deleteLayer(selectedLayerId); deleteLayer(selectedLayerId);
} }
if (typeof maxZoom === 'string') { if (typeof maxZoom === 'string') {
maxZoom = parseInt(maxZoom); maxZoom = parseInt(maxZoom);
} }
let is512 = tileUrls.some((url) => url.includes('512'));
let layerId = selectedLayerId ?? getLayerId(); let layerId = selectedLayerId ?? getLayerId();
let layer: CustomLayer = { let layer: CustomLayer = {
id: layerId, id: layerId,
name: name, name: name,
tileUrls: tileUrls.map((url) => decodeURI(url.trim())), tileUrls: tileUrls.map((url) => decodeURI(url.trim())),
maxZoom: maxZoom, maxZoom: maxZoom,
layerType: layerType, layerType: layerType,
resourceType: resourceType, resourceType: resourceType,
value: '' value: ''
}; };
if (resourceType === 'vector') { if (resourceType === 'vector') {
layer.value = layer.tileUrls[0]; layer.value = layer.tileUrls[0];
} else { } else {
layer.value = { layer.value = {
version: 8, version: 8,
sources: { sources: {
[layerId]: { [layerId]: {
type: 'raster', type: 'raster',
tiles: layer.tileUrls, tiles: layer.tileUrls,
tileSize: 256, tileSize: is512 ? 512 : 256,
maxzoom: maxZoom maxzoom: maxZoom
} }
}, },
layers: [ layers: [
{ {
id: layerId, id: layerId,
type: 'raster', type: 'raster',
source: layerId source: layerId
} }
] ]
}; };
} }
$customLayers[layerId] = layer; $customLayers[layerId] = layer;
addLayer(layerId); addLayer(layerId);
selectedLayerId = undefined; selectedLayerId = undefined;
setDataFromSelectedLayer(); setDataFromSelectedLayer();
} }
function getLayerId() { function getLayerId() {
for (let id = 0; ; id++) { for (let id = 0; ; id++) {
if (!$customLayers.hasOwnProperty(`custom-${id}`)) { if (!$customLayers.hasOwnProperty(`custom-${id}`)) {
return `custom-${id}`; return `custom-${id}`;
} }
} }
} }
function addLayer(layerId: string) { function addLayer(layerId: string) {
if (layerType === 'basemap') { if (layerType === 'basemap') {
selectedBasemapTree.update(($tree) => { selectedBasemapTree.update(($tree) => {
if (!$tree.basemaps.hasOwnProperty('custom')) { if (!$tree.basemaps.hasOwnProperty('custom')) {
$tree.basemaps['custom'] = {}; $tree.basemaps['custom'] = {};
} }
$tree.basemaps['custom'][layerId] = true; $tree.basemaps['custom'][layerId] = true;
return $tree; return $tree;
}); });
if ($currentBasemap === layerId) { if ($currentBasemap === layerId) {
$customBasemapUpdate++; $customBasemapUpdate++;
} else { } else {
$currentBasemap = layerId; $currentBasemap = layerId;
} }
if (!$customBasemapOrder.includes(layerId)) { if (!$customBasemapOrder.includes(layerId)) {
$customBasemapOrder = [...$customBasemapOrder, layerId]; $customBasemapOrder = [...$customBasemapOrder, layerId];
} }
} else { } else {
selectedOverlayTree.update(($tree) => { selectedOverlayTree.update(($tree) => {
if (!$tree.overlays.hasOwnProperty('custom')) { if (!$tree.overlays.hasOwnProperty('custom')) {
$tree.overlays['custom'] = {}; $tree.overlays['custom'] = {};
} }
$tree.overlays['custom'][layerId] = true; $tree.overlays['custom'][layerId] = true;
return $tree; return $tree;
}); });
if ( if (
$currentOverlays.overlays['custom'] && $currentOverlays.overlays['custom'] &&
$currentOverlays.overlays['custom'][layerId] && $currentOverlays.overlays['custom'][layerId] &&
$map $map
) { ) {
try { try {
$map.removeImport(layerId); $map.removeImport(layerId);
} catch (e) { } catch (e) {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
if (!$currentOverlays.overlays.hasOwnProperty('custom')) { if (!$currentOverlays.overlays.hasOwnProperty('custom')) {
$currentOverlays.overlays['custom'] = {}; $currentOverlays.overlays['custom'] = {};
} }
$currentOverlays.overlays['custom'][layerId] = true; $currentOverlays.overlays['custom'][layerId] = true;
if (!$customOverlayOrder.includes(layerId)) { if (!$customOverlayOrder.includes(layerId)) {
$customOverlayOrder = [...$customOverlayOrder, layerId]; $customOverlayOrder = [...$customOverlayOrder, layerId];
} }
} }
} }
function tryDeleteLayer(node: any, id: string): any { function tryDeleteLayer(node: any, id: string): any {
if (node.hasOwnProperty(id)) { if (node.hasOwnProperty(id)) {
delete node[id]; delete node[id];
} }
return node; return node;
} }
function deleteLayer(layerId: string) { function deleteLayer(layerId: string) {
let layer = $customLayers[layerId]; let layer = $customLayers[layerId];
if (layer.layerType === 'basemap') { if (layer.layerType === 'basemap') {
if (layerId === $currentBasemap) { if (layerId === $currentBasemap) {
$currentBasemap = defaultBasemap; $currentBasemap = defaultBasemap;
} }
if (layerId === $previousBasemap) { if (layerId === $previousBasemap) {
$previousBasemap = defaultBasemap; $previousBasemap = defaultBasemap;
} }
$selectedBasemapTree.basemaps['custom'] = tryDeleteLayer( $selectedBasemapTree.basemaps['custom'] = tryDeleteLayer(
$selectedBasemapTree.basemaps['custom'], $selectedBasemapTree.basemaps['custom'],
layerId layerId
); );
if (Object.keys($selectedBasemapTree.basemaps['custom']).length === 0) { if (Object.keys($selectedBasemapTree.basemaps['custom']).length === 0) {
$selectedBasemapTree.basemaps = tryDeleteLayer( $selectedBasemapTree.basemaps = tryDeleteLayer($selectedBasemapTree.basemaps, 'custom');
$selectedBasemapTree.basemaps, }
'custom' $customBasemapOrder = $customBasemapOrder.filter((id) => id !== layerId);
); } else {
} $currentOverlays.overlays['custom'][layerId] = false;
$customBasemapOrder = $customBasemapOrder.filter((id) => id !== layerId); if ($previousOverlays.overlays['custom']) {
} else { $previousOverlays.overlays['custom'] = tryDeleteLayer(
$currentOverlays.overlays['custom'][layerId] = false; $previousOverlays.overlays['custom'],
if ($previousOverlays.overlays['custom']) { layerId
$previousOverlays.overlays['custom'] = tryDeleteLayer( );
$previousOverlays.overlays['custom'], }
layerId
);
}
$selectedOverlayTree.overlays['custom'] = tryDeleteLayer( $selectedOverlayTree.overlays['custom'] = tryDeleteLayer(
$selectedOverlayTree.overlays['custom'], $selectedOverlayTree.overlays['custom'],
layerId layerId
); );
if (Object.keys($selectedOverlayTree.overlays['custom']).length === 0) { if (Object.keys($selectedOverlayTree.overlays['custom']).length === 0) {
$selectedOverlayTree.overlays = tryDeleteLayer( $selectedOverlayTree.overlays = tryDeleteLayer($selectedOverlayTree.overlays, 'custom');
$selectedOverlayTree.overlays, }
'custom' $customOverlayOrder = $customOverlayOrder.filter((id) => id !== layerId);
);
}
$customOverlayOrder = $customOverlayOrder.filter((id) => id !== layerId);
if ( if (
$currentOverlays.overlays['custom'] && $currentOverlays.overlays['custom'] &&
$currentOverlays.overlays['custom'][layerId] && $currentOverlays.overlays['custom'][layerId] &&
$map $map
) { ) {
try { try {
$map.removeImport(layerId); $map.removeImport(layerId);
} catch (e) { } catch (e) {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
} }
$customLayers = tryDeleteLayer($customLayers, layerId); $customLayers = tryDeleteLayer($customLayers, layerId);
} }
let selectedLayerId: string | undefined = undefined; let selectedLayerId: string | undefined = undefined;
function setDataFromSelectedLayer() { function setDataFromSelectedLayer() {
if (selectedLayerId) { if (selectedLayerId) {
const layer = $customLayers[selectedLayerId]; const layer = $customLayers[selectedLayerId];
name = layer.name; name = layer.name;
tileUrls = layer.tileUrls; tileUrls = layer.tileUrls;
maxZoom = layer.maxZoom; maxZoom = layer.maxZoom;
layerType = layer.layerType; layerType = layer.layerType;
resourceType = layer.resourceType; resourceType = layer.resourceType;
} else { } else {
name = ''; name = '';
tileUrls = ['']; tileUrls = [''];
maxZoom = 20; maxZoom = 20;
layerType = 'basemap'; layerType = 'basemap';
resourceType = 'raster'; resourceType = 'raster';
} }
} }
$: selectedLayerId, setDataFromSelectedLayer(); $: selectedLayerId, setDataFromSelectedLayer();
</script> </script>
<div class="flex flex-col"> <div class="flex flex-col">
{#if $customBasemapOrder.length > 0} {#if $customBasemapOrder.length > 0}
<div class="flex flex-row items-center gap-1 font-semibold mb-2"> <div class="flex flex-row items-center gap-1 font-semibold mb-2">
<Map size="16" /> <Map size="16" />
{$_('layers.label.basemaps')} {$_('layers.label.basemaps')}
<div class="grow"> <div class="grow">
<Separator /> <Separator />
</div> </div>
</div> </div>
{/if} {/if}
<div <div
bind:this={basemapContainer} bind:this={basemapContainer}
class="ml-1.5 flex flex-col gap-1 {$customBasemapOrder.length > 0 ? 'mb-2' : ''}" class="ml-1.5 flex flex-col gap-1 {$customBasemapOrder.length > 0 ? 'mb-2' : ''}"
> >
{#each $customBasemapOrder as id (id)} {#each $customBasemapOrder as id (id)}
<div class="flex flex-row items-center gap-2" data-id={id}> <div class="flex flex-row items-center gap-2" data-id={id}>
<Move size="12" /> <Move size="12" />
<span class="grow">{$customLayers[id].name}</span> <span class="grow">{$customLayers[id].name}</span>
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7"> <Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
<Pencil size="16" /> <Pencil size="16" />
</Button> </Button>
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7"> <Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
<Trash2 size="16" /> <Trash2 size="16" />
</Button> </Button>
</div> </div>
{/each} {/each}
</div> </div>
{#if $customOverlayOrder.length > 0} {#if $customOverlayOrder.length > 0}
<div class="flex flex-row items-center gap-1 font-semibold mb-2"> <div class="flex flex-row items-center gap-1 font-semibold mb-2">
<Layers2 size="16" /> <Layers2 size="16" />
{$_('layers.label.overlays')} {$_('layers.label.overlays')}
<div class="grow"> <div class="grow">
<Separator /> <Separator />
</div> </div>
</div> </div>
{/if} {/if}
<div <div
bind:this={overlayContainer} bind:this={overlayContainer}
class="ml-1.5 flex flex-col gap-1 {$customOverlayOrder.length > 0 ? 'mb-2' : ''}" class="ml-1.5 flex flex-col gap-1 {$customOverlayOrder.length > 0 ? 'mb-2' : ''}"
> >
{#each $customOverlayOrder as id (id)} {#each $customOverlayOrder as id (id)}
<div class="flex flex-row items-center gap-2" data-id={id}> <div class="flex flex-row items-center gap-2" data-id={id}>
<Move size="12" /> <Move size="12" />
<span class="grow">{$customLayers[id].name}</span> <span class="grow">{$customLayers[id].name}</span>
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7"> <Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
<Pencil size="16" /> <Pencil size="16" />
</Button> </Button>
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7"> <Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
<Trash2 size="16" /> <Trash2 size="16" />
</Button> </Button>
</div> </div>
{/each} {/each}
</div> </div>
<Card.Root> <Card.Root>
<Card.Header class="p-3"> <Card.Header class="p-3">
<Card.Title class="text-base"> <Card.Title class="text-base">
{#if selectedLayerId} {#if selectedLayerId}
{$_('layers.custom_layers.edit')} {$_('layers.custom_layers.edit')}
{:else} {:else}
{$_('layers.custom_layers.new')} {$_('layers.custom_layers.new')}
{/if} {/if}
</Card.Title> </Card.Title>
</Card.Header> </Card.Header>
<Card.Content class="p-3 pt-0"> <Card.Content class="p-3 pt-0">
<fieldset class="flex flex-col gap-2"> <fieldset class="flex flex-col gap-2">
<Label for="name">{$_('menu.metadata.name')}</Label> <Label for="name">{$_('menu.metadata.name')}</Label>
<Input bind:value={name} id="name" class="h-8" /> <Input bind:value={name} id="name" class="h-8" />
<Label for="url">{$_('layers.custom_layers.urls')}</Label> <Label for="url">{$_('layers.custom_layers.urls')}</Label>
{#each tileUrls as url, i} {#each tileUrls as url, i}
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
<Input <Input
bind:value={tileUrls[i]} bind:value={tileUrls[i]}
id="url" id="url"
class="h-8" class="h-8"
placeholder={$_('layers.custom_layers.url_placeholder')} placeholder={$_('layers.custom_layers.url_placeholder')}
/> />
{#if tileUrls.length > 1} {#if tileUrls.length > 1}
<Button <Button
on:click={() => on:click={() => (tileUrls = tileUrls.filter((_, index) => index !== i))}
(tileUrls = tileUrls.filter((_, index) => index !== i))} variant="outline"
variant="outline" class="p-1 h-8"
class="p-1 h-8" >
> <Minus size="16" />
<Minus size="16" /> </Button>
</Button> {/if}
{/if} {#if i === tileUrls.length - 1}
{#if i === tileUrls.length - 1} <Button
<Button on:click={() => (tileUrls = [...tileUrls, ''])}
on:click={() => (tileUrls = [...tileUrls, ''])} variant="outline"
variant="outline" class="p-1 h-8"
class="p-1 h-8" >
> <Plus size="16" />
<Plus size="16" /> </Button>
</Button> {/if}
{/if} </div>
</div> {/each}
{/each} {#if resourceType === 'raster'}
{#if resourceType === 'raster'} <Label for="maxZoom">{$_('layers.custom_layers.max_zoom')}</Label>
<Label for="maxZoom">{$_('layers.custom_layers.max_zoom')}</Label> <Input type="number" bind:value={maxZoom} id="maxZoom" min={0} max={22} class="h-8" />
<Input {/if}
type="number" <Label>{$_('layers.custom_layers.layer_type')}</Label>
bind:value={maxZoom} <RadioGroup.Root bind:value={layerType} class="flex flex-row">
id="maxZoom" <div class="flex items-center space-x-2">
min={0} <RadioGroup.Item value="basemap" id="basemap" />
max={22} <Label for="basemap">{$_('layers.custom_layers.basemap')}</Label>
class="h-8" </div>
/> <div class="flex items-center space-x-2">
{/if} <RadioGroup.Item value="overlay" id="overlay" />
<Label>{$_('layers.custom_layers.layer_type')}</Label> <Label for="overlay">{$_('layers.custom_layers.overlay')}</Label>
<RadioGroup.Root bind:value={layerType} class="flex flex-row"> </div>
<div class="flex items-center space-x-2"> </RadioGroup.Root>
<RadioGroup.Item value="basemap" id="basemap" /> {#if selectedLayerId}
<Label for="basemap">{$_('layers.custom_layers.basemap')}</Label> <div class="mt-2 flex flex-row gap-2">
</div> <Button variant="outline" on:click={createLayer} class="grow">
<div class="flex items-center space-x-2"> <Save size="16" class="mr-1" />
<RadioGroup.Item value="overlay" id="overlay" /> {$_('layers.custom_layers.update')}
<Label for="overlay">{$_('layers.custom_layers.overlay')}</Label> </Button>
</div> <Button variant="outline" on:click={() => (selectedLayerId = undefined)}>
</RadioGroup.Root> <CircleX size="16" />
{#if selectedLayerId} </Button>
<div class="mt-2 flex flex-row gap-2"> </div>
<Button variant="outline" on:click={createLayer} class="grow"> {:else}
<Save size="16" class="mr-1" /> <Button variant="outline" class="mt-2" on:click={createLayer}>
{$_('layers.custom_layers.update')} <CirclePlus size="16" class="mr-1" />
</Button> {$_('layers.custom_layers.create')}
<Button variant="outline" on:click={() => (selectedLayerId = undefined)}> </Button>
<CircleX size="16" /> {/if}
</Button> </fieldset>
</div> </Card.Content>
{:else} </Card.Root>
<Button variant="outline" class="mt-2" on:click={createLayer}>
<CirclePlus size="16" class="mr-1" />
{$_('layers.custom_layers.create')}
</Button>
{/if}
</fieldset>
</Card.Content>
</Card.Root>
</div> </div>

View File

@@ -13,7 +13,6 @@
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import { customBasemapUpdate, getLayers } from './utils'; import { customBasemapUpdate, getLayers } from './utils';
import { OverpassLayer } from './OverpassLayer'; import { OverpassLayer } from './OverpassLayer';
import OverpassPopup from './OverpassPopup.svelte';
let container: HTMLDivElement; let container: HTMLDivElement;
let overpassLayer: OverpassLayer; let overpassLayer: OverpassLayer;
@@ -34,7 +33,7 @@
if ($map) { if ($map) {
let basemap = basemaps.hasOwnProperty($currentBasemap) let basemap = basemaps.hasOwnProperty($currentBasemap)
? basemaps[$currentBasemap] ? basemaps[$currentBasemap]
: $customLayers[$currentBasemap]?.value ?? basemaps[defaultBasemap]; : ($customLayers[$currentBasemap]?.value ?? basemaps[defaultBasemap]);
$map.removeImport('basemap'); $map.removeImport('basemap');
if (typeof basemap === 'string') { if (typeof basemap === 'string') {
$map.addImport({ id: 'basemap', url: basemap }, 'overlays'); $map.addImport({ id: 'basemap', url: basemap }, 'overlays');
@@ -85,18 +84,21 @@
} }
function updateOverlays() { function updateOverlays() {
if ($map && $currentOverlays) { if ($map && $currentOverlays && $opacities) {
let overlayLayers = getLayers($currentOverlays); let overlayLayers = getLayers($currentOverlays);
try { try {
let activeOverlays = $map let activeOverlays = $map.getStyle().imports.reduce((acc, i) => {
.getStyle() if (!['basemap', 'overlays', 'glyphs-and-sprite'].includes(i.id)) {
.imports.filter((i) => i.id !== 'basemap' && i.id !== 'overlays'); acc[i.id] = i;
let toRemove = activeOverlays.filter((i) => !overlayLayers[i.id]); }
toRemove.forEach((i) => { return acc;
$map.removeImport(i.id); }, {});
let toRemove = Object.keys(activeOverlays).filter((id) => !overlayLayers[id]);
toRemove.forEach((id) => {
$map.removeImport(id);
}); });
let toAdd = Object.entries(overlayLayers) let toAdd = Object.entries(overlayLayers)
.filter(([id, selected]) => selected && !activeOverlays.some((j) => j.id === id)) .filter(([id, selected]) => selected && !activeOverlays.hasOwnProperty(id))
.map(([id]) => id); .map(([id]) => id);
toAdd.forEach((id) => { toAdd.forEach((id) => {
addOverlay(id); addOverlay(id);
@@ -107,7 +109,7 @@
} }
} }
$: if ($map && $currentOverlays) { $: if ($map && $currentOverlays && $opacities) {
updateOverlays(); updateOverlays();
} }
@@ -130,7 +132,9 @@
}); });
currentBasemap.subscribe((value) => { currentBasemap.subscribe((value) => {
// Updates coming from the database, or from the user swapping basemaps // Updates coming from the database, or from the user swapping basemaps
selectedBasemap.set(value); if (value !== get(selectedBasemap)) {
selectedBasemap.set(value);
}
}); });
let open = false; let open = false;
@@ -209,8 +213,6 @@
</div> </div>
</CustomControl> </CustomControl>
<OverpassPopup />
<svelte:window <svelte:window
on:click={(e) => { on:click={(e) => {
if (open && !cancelEvents && !container.contains(e.target)) { if (open && !cancelEvents && !container.contains(e.target)) {

View File

@@ -157,15 +157,16 @@
max={1} max={1}
step={0.1} step={0.1}
disabled={$selectedOverlay === undefined} disabled={$selectedOverlay === undefined}
onValueChange={() => { onValueChange={(value) => {
if ($selectedOverlay) { if ($selectedOverlay) {
$opacities[$selectedOverlay.value] = $overlayOpacity[0]; if ($map && isSelected($currentOverlays, $selectedOverlay.value)) {
if ($map) { try {
if ($map.getLayer($selectedOverlay.value)) { $map.removeImport($selectedOverlay.value);
$map.removeLayer($selectedOverlay.value); } catch (e) {
$currentOverlays = $currentOverlays; // No reliable way to check if the map is ready to remove sources and layers
} }
} }
$opacities[$selectedOverlay.value] = value[0];
} }
}} }}
/> />

View File

@@ -1,10 +1,10 @@
import SphericalMercator from "@mapbox/sphericalmercator"; import SphericalMercator from "@mapbox/sphericalmercator";
import { getLayers } from "./utils"; import { getLayers } from "./utils";
import mapboxgl from "mapbox-gl";
import { get, writable } from "svelte/store"; import { get, writable } from "svelte/store";
import { liveQuery } from "dexie"; import { liveQuery } from "dexie";
import { db, settings } from "$lib/db"; import { db, settings } from "$lib/db";
import { overpassQueryData } from "$lib/assets/layers"; import { overpassQueryData } from "$lib/assets/layers";
import { MapPopup } from "$lib/components/MapPopup";
const { const {
currentOverpassQueries currentOverpassQueries
@@ -14,14 +14,6 @@ const mercator = new SphericalMercator({
size: 256, size: 256,
}); });
export const overpassPopupPOI = writable<Record<string, any> | null>(null);
export const overpassPopup = new mapboxgl.Popup({
closeButton: false,
maxWidth: undefined,
offset: 15,
});
let data = writable<GeoJSON.FeatureCollection>({ type: 'FeatureCollection', features: [] }); let data = writable<GeoJSON.FeatureCollection>({ type: 'FeatureCollection', features: [] });
liveQuery(() => db.overpassdata.toArray()).subscribe((pois) => { liveQuery(() => db.overpassdata.toArray()).subscribe((pois) => {
@@ -34,6 +26,7 @@ export class OverpassLayer {
queryZoom = 12; queryZoom = 12;
expirationTime = 7 * 24 * 3600 * 1000; expirationTime = 7 * 24 * 3600 * 1000;
map: mapboxgl.Map; map: mapboxgl.Map;
popup: MapPopup;
currentQueries: Set<string> = new Set(); currentQueries: Set<string> = new Set();
nextQueries: Map<string, { x: number, y: number, queries: string[] }> = new Map(); nextQueries: Map<string, { x: number, y: number, queries: string[] }> = new Map();
@@ -42,10 +35,15 @@ export class OverpassLayer {
queryIfNeededBinded = this.queryIfNeeded.bind(this); queryIfNeededBinded = this.queryIfNeeded.bind(this);
updateBinded = this.update.bind(this); updateBinded = this.update.bind(this);
onHoverBinded = this.onHover.bind(this); onHoverBinded = this.onHover.bind(this);
maybeHidePopupBinded = this.maybeHidePopup.bind(this);
constructor(map: mapboxgl.Map) { constructor(map: mapboxgl.Map) {
this.map = map; this.map = map;
this.popup = new MapPopup(map, {
closeButton: false,
focusAfterOpen: false,
maxWidth: undefined,
offset: 15,
});
} }
add() { add() {
@@ -125,27 +123,12 @@ export class OverpassLayer {
} }
onHover(e: any) { onHover(e: any) {
overpassPopupPOI.set({ this.popup.setItem({
...e.features[0].properties, item: {
sym: overpassQueryData[e.features[0].properties.query].symbol ?? '' ...e.features[0].properties,
sym: overpassQueryData[e.features[0].properties.query].symbol ?? ''
}
}); });
overpassPopup.setLngLat(e.features[0].geometry.coordinates);
overpassPopup.addTo(this.map);
this.map.on('mousemove', this.maybeHidePopupBinded);
}
maybeHidePopup(e: any) {
let poi = get(overpassPopupPOI);
if (poi && this.map.project([poi.lon, poi.lat]).dist(this.map.project(e.lngLat)) > 100) {
this.hideWaypointPopup();
}
}
hideWaypointPopup() {
overpassPopupPOI.set(null);
overpassPopup.remove();
this.map.off('mousemove', this.maybeHidePopupBinded);
} }
query(bbox: [number, number, number, number]) { query(bbox: [number, number, number, number]) {

View File

@@ -1,102 +1,95 @@
<script lang="ts"> <script lang="ts">
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { overpassPopup, overpassPopupPOI } from './OverpassLayer';
import { selection } from '$lib/components/file-list/Selection'; import { selection } from '$lib/components/file-list/Selection';
import { PencilLine, MapPin } from 'lucide-svelte'; import { PencilLine, MapPin } from 'lucide-svelte';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { dbUtils } from '$lib/db'; import { dbUtils } from '$lib/db';
import type { PopupItem } from '$lib/components/MapPopup';
import { ScrollArea } from '$lib/components/ui/scroll-area/index.js';
let popupElement: HTMLDivElement; export let poi: PopupItem<any>;
onMount(() => {
overpassPopup.setDOMContent(popupElement);
popupElement.classList.remove('hidden');
});
let tags = {}; let tags = {};
let name = ''; let name = '';
$: if ($overpassPopupPOI) { $: if (poi) {
tags = JSON.parse($overpassPopupPOI.tags); tags = JSON.parse(poi.item.tags);
if (tags.name !== undefined && tags.name !== '') { if (tags.name !== undefined && tags.name !== '') {
name = tags.name; name = tags.name;
} else { } else {
name = $_(`layers.label.${$overpassPopupPOI.query}`); name = $_(`layers.label.${poi.item.query}`);
} }
} }
</script> </script>
<div bind:this={popupElement} class="hidden"> <Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]">
{#if $overpassPopupPOI} <Card.Header class="p-0">
<Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]"> <Card.Title class="text-md">
<Card.Header class="p-0"> <div class="flex flex-row gap-3">
<Card.Title class="text-md"> <div class="flex flex-col">
<div class="flex flex-row gap-3"> {name}
<div class="flex flex-col"> <div class="text-muted-foreground text-sm font-normal">
{name} {poi.item.lat.toFixed(6)}&deg; {poi.item.lon.toFixed(6)}&deg;
<div class="text-muted-foreground text-sm font-normal">
{$overpassPopupPOI.lat.toFixed(6)}&deg; {$overpassPopupPOI.lon.toFixed(6)}&deg;
</div>
</div>
<Button
class="ml-auto p-1.5 h-8"
variant="outline"
href="https://www.openstreetmap.org/edit?editor=id&node={$overpassPopupPOI.id}"
target="_blank"
>
<PencilLine size="16" />
</Button>
</div> </div>
</Card.Title> </div>
</Card.Header> <Button
class="ml-auto p-1.5 h-8"
variant="outline"
href="https://www.openstreetmap.org/edit?editor=id&node={poi.item.id}"
target="_blank"
>
<PencilLine size="16" />
</Button>
</div>
</Card.Title>
</Card.Header>
<Card.Content class="flex flex-col p-0 text-sm mt-1 whitespace-normal break-all">
<ScrollArea class="flex flex-col" viewportClasses="max-h-[30dvh]">
{#if tags.image || tags['image:0']} {#if tags.image || tags['image:0']}
<div class="w-full rounded-md overflow-clip my-2 max-w-96 mx-auto"> <div class="w-full rounded-md overflow-clip my-2 max-w-96 mx-auto">
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->
<img src={tags.image ?? tags['image:0']} /> <img src={tags.image ?? tags['image:0']} />
</div> </div>
{/if} {/if}
<Card.Content class="flex flex-col p-0 text-sm mt-1 whitespace-normal break-all"> <div class="grid grid-cols-[auto_auto] gap-x-3">
<div class="grid grid-cols-[auto_auto] gap-x-3"> {#each Object.entries(tags) as [key, value]}
{#each Object.entries(tags) as [key, value]} {#if key !== 'name' && !key.includes('image')}
{#if key !== 'name' && !key.includes('image')} <span class="font-mono">{key}</span>
<span class="font-mono">{key}</span> {#if key === 'website' || key.startsWith('website:') || key === 'contact:website' || key === 'contact:facebook' || key === 'contact:instagram' || key === 'contact:twitter'}
{#if key === 'website' || key === 'contact:website' || key === 'contact:facebook' || key === 'contact:instagram' || key === 'contact:twitter'} <a href={value} target="_blank" class="text-link underline">{value}</a>
<a href={value} target="_blank" class="text-link underline">{value}</a> {:else if key === 'phone' || key === 'contact:phone'}
{:else if key === 'phone' || key === 'contact:phone'} <a href={'tel:' + value} class="text-link underline">{value}</a>
<a href={'tel:' + value} class="text-link underline">{value}</a> {:else if key === 'email' || key === 'contact:email'}
{:else if key === 'email' || key === 'contact:email'} <a href={'mailto:' + value} class="text-link underline">{value}</a>
<a href={'mailto:' + value} class="text-link underline">{value}</a> {:else}
{:else} <span>{value}</span>
<span>{value}</span>
{/if}
{/if} {/if}
{/each} {/if}
</div> {/each}
<Button </div>
class="mt-2" </ScrollArea>
variant="outline" <Button
disabled={$selection.size === 0} class="mt-2"
on:click={() => { variant="outline"
let desc = Object.entries(tags) disabled={$selection.size === 0}
.map(([key, value]) => `${key}: ${value}`) on:click={() => {
.join('\n'); let desc = Object.entries(tags)
dbUtils.addOrUpdateWaypoint({ .map(([key, value]) => `${key}: ${value}`)
attributes: { .join('\n');
lat: $overpassPopupPOI.lat, dbUtils.addOrUpdateWaypoint({
lon: $overpassPopupPOI.lon attributes: {
}, lat: poi.item.lat,
name: name, lon: poi.item.lon
desc: desc, },
cmt: desc, name: name,
sym: $overpassPopupPOI.sym desc: desc,
}); cmt: desc,
}} sym: poi.item.sym
> });
<MapPin size="16" class="mr-1" /> }}
{$_('toolbar.waypoint.add')} >
</Button> <MapPin size="16" class="mr-1" />
</Card.Content> {$_('toolbar.waypoint.add')}
</Card.Root> </Button>
{/if} </Card.Content>
</div> </Card.Root>

View File

@@ -1,16 +1,17 @@
import mapboxgl from "mapbox-gl"; import mapboxgl, { type LayerSpecification, type VectorSourceSpecification } from "mapbox-gl";
import { Viewer } from 'mapillary-js/dist/mapillary.module'; import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
import 'mapillary-js/dist/mapillary.css'; import 'mapillary-js/dist/mapillary.css';
import { resetCursor, setPointerCursor } from "$lib/utils"; import { resetCursor, setPointerCursor } from "$lib/utils";
import type { Writable } from "svelte/store";
const mapillarySource = { const mapillarySource: VectorSourceSpecification = {
type: 'vector', type: 'vector',
tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_computed_public/2/{z}/{x}/{y}?access_token=MLY|4381405525255083|3204871ec181638c3c31320490f03011'], tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_computed_public/2/{z}/{x}/{y}?access_token=MLY|4381405525255083|3204871ec181638c3c31320490f03011'],
minzoom: 6, minzoom: 6,
maxzoom: 14, maxzoom: 14,
}; };
const mapillarySequenceLayer = { const mapillarySequenceLayer: LayerSpecification = {
id: 'mapillary-sequence', id: 'mapillary-sequence',
type: 'line', type: 'line',
source: 'mapillary', source: 'mapillary',
@@ -26,7 +27,7 @@ const mapillarySequenceLayer = {
}, },
}; };
const mapillaryImageLayer = { const mapillaryImageLayer: LayerSpecification = {
id: 'mapillary-image', id: 'mapillary-image',
type: 'circle', type: 'circle',
source: 'mapillary', source: 'mapillary',
@@ -40,35 +41,56 @@ const mapillaryImageLayer = {
export class MapillaryLayer { export class MapillaryLayer {
map: mapboxgl.Map; map: mapboxgl.Map;
popup: mapboxgl.Popup; marker: mapboxgl.Marker;
viewer: Viewer; viewer: Viewer;
active = false;
popupOpen: Writable<boolean>;
addBinded = this.add.bind(this); addBinded = this.add.bind(this);
onMouseEnterBinded = this.onMouseEnter.bind(this); onMouseEnterBinded = this.onMouseEnter.bind(this);
onMouseLeaveBinded = this.onMouseLeave.bind(this); onMouseLeaveBinded = this.onMouseLeave.bind(this);
constructor(map: mapboxgl.Map, container: HTMLElement) { constructor(map: mapboxgl.Map, container: HTMLElement, popupOpen: Writable<boolean>) {
this.map = map; this.map = map;
this.viewer = new Viewer({ this.viewer = new Viewer({
accessToken: 'MLY|4381405525255083|3204871ec181638c3c31320490f03011', accessToken: 'MLY|4381405525255083|3204871ec181638c3c31320490f03011',
container, container,
}); });
container.classList.remove('hidden');
this.popup = new mapboxgl.Popup({ const element = document.createElement('div');
closeButton: false, element.className = 'mapboxgl-user-location mapboxgl-user-location-show-heading';
maxWidth: container.style.width, const dot = document.createElement('div');
}).setDOMContent(container); dot.className = 'mapboxgl-user-location-dot';
const heading = document.createElement('div');
heading.className = 'mapboxgl-user-location-heading';
element.appendChild(dot);
element.appendChild(heading);
this.marker = new mapboxgl.Marker({
rotationAlignment: 'map',
element
});
this.viewer.on('position', async () => { this.viewer.on('position', async () => {
if (this.popup.isOpen()) { if (this.active) {
popupOpen.set(true);
let latLng = await this.viewer.getPosition(); let latLng = await this.viewer.getPosition();
this.popup.setLngLat(latLng); this.marker.setLngLat(latLng).addTo(this.map);
if (!this.map.getBounds().contains(latLng)) { if (!this.map.getBounds()?.contains(latLng)) {
this.map.panTo(latLng); this.map.panTo(latLng);
} }
} }
}); });
this.viewer.on('bearing', (e: ViewerBearingEvent) => {
if (this.active) {
this.marker.setRotation(e.bearing);
}
});
this.popupOpen = popupOpen;
} }
add() { add() {
@@ -101,15 +123,19 @@ export class MapillaryLayer {
this.map.removeSource('mapillary'); this.map.removeSource('mapillary');
} }
this.popup.remove(); this.marker.remove();
this.popupOpen.set(false);
} }
closePopup() { closePopup() {
this.popup.remove(); this.active = false;
this.marker.remove();
this.popupOpen.set(false);
} }
onMouseEnter(e: mapboxgl.MapLayerMouseEvent) { onMouseEnter(e: mapboxgl.MapMouseEvent) {
this.popup.addTo(this.map).setLngLat(e.lngLat); this.active = true;
this.viewer.resize(); this.viewer.resize();
this.viewer.moveTo(e.features[0].properties.id); this.viewer.moveTo(e.features[0].properties.id);

View File

@@ -8,16 +8,18 @@
import { map, streetViewEnabled } from '$lib/stores'; import { map, streetViewEnabled } from '$lib/stores';
import { settings } from '$lib/db'; import { settings } from '$lib/db';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { writable } from 'svelte/store';
const { streetViewSource } = settings; const { streetViewSource } = settings;
let googleRedirect: GoogleRedirect; let googleRedirect: GoogleRedirect;
let mapillaryLayer: MapillaryLayer; let mapillaryLayer: MapillaryLayer;
let mapillaryOpen = writable(false);
let container: HTMLElement; let container: HTMLElement;
$: if ($map) { $: if ($map) {
googleRedirect = new GoogleRedirect($map); googleRedirect = new GoogleRedirect($map);
mapillaryLayer = new MapillaryLayer($map, container); mapillaryLayer = new MapillaryLayer($map, container, mapillaryOpen);
} }
$: if (mapillaryLayer) { $: if (mapillaryLayer) {
@@ -53,7 +55,9 @@
<div <div
bind:this={container} bind:this={container}
class="hidden relative w-[50vw] h-[40vh] rounded-md border-background border-2" class="{$mapillaryOpen
? ''
: 'hidden'} !absolute bottom-[44px] right-2.5 z-10 w-[40%] h-[40%] bg-background rounded-md overflow-hidden border-background border-2"
> >
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->

View File

@@ -11,15 +11,18 @@
import { selection } from '$lib/components/file-list/Selection'; import { selection } from '$lib/components/file-list/Selection';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { Label } from '$lib/components/ui/label/index.js'; import { Label } from '$lib/components/ui/label/index.js';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as RadioGroup from '$lib/components/ui/radio-group'; import * as RadioGroup from '$lib/components/ui/radio-group';
import { _, locale } from 'svelte-i18n'; import { _, locale } from 'svelte-i18n';
import { dbUtils, getFile } from '$lib/db'; import { dbUtils, getFile } from '$lib/db';
import { Group } from 'lucide-svelte'; import { Group } from 'lucide-svelte';
import { getURLForLanguage } from '$lib/utils'; import { getURLForLanguage } from '$lib/utils';
import Shortcut from '$lib/components/Shortcut.svelte'; import Shortcut from '$lib/components/Shortcut.svelte';
import { gpxStatistics } from '$lib/stores';
let canMergeTraces = false; let canMergeTraces = false;
let canMergeContents = false; let canMergeContents = false;
let removeGaps = false;
$: if ($selection.size > 1) { $: if ($selection.size > 1) {
canMergeTraces = true; canMergeTraces = true;
@@ -56,22 +59,31 @@
<div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}"> <div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}">
<RadioGroup.Root bind:value={mergeType}> <RadioGroup.Root bind:value={mergeType}>
<Label class="flex flex-row items-center gap-2 leading-5"> <Label class="flex flex-row items-center gap-1.5 leading-5">
<RadioGroup.Item value={MergeType.TRACES} /> <RadioGroup.Item value={MergeType.TRACES} />
{$_('toolbar.merge.merge_traces')} {$_('toolbar.merge.merge_traces')}
</Label> </Label>
<Label class="flex flex-row items-center gap-2 leading-5"> <Label class="flex flex-row items-center gap-1.5 leading-5">
<RadioGroup.Item value={MergeType.CONTENTS} /> <RadioGroup.Item value={MergeType.CONTENTS} />
{$_('toolbar.merge.merge_contents')} {$_('toolbar.merge.merge_contents')}
</Label> </Label>
</RadioGroup.Root> </RadioGroup.Root>
{#if mergeType === MergeType.TRACES && $gpxStatistics.global.time.total > 0}
<div class="flex flex-row items-center gap-1.5">
<Checkbox id="remove-gaps" bind:checked={removeGaps} />
<Label for="remove-gaps">{$_('toolbar.merge.remove_gaps')}</Label>
</div>
{/if}
<Button <Button
variant="outline" variant="outline"
class="whitespace-normal h-fit" class="whitespace-normal h-fit"
disabled={(mergeType === MergeType.TRACES && !canMergeTraces) || disabled={(mergeType === MergeType.TRACES && !canMergeTraces) ||
(mergeType === MergeType.CONTENTS && !canMergeContents)} (mergeType === MergeType.CONTENTS && !canMergeContents)}
on:click={() => { on:click={() => {
dbUtils.mergeSelection(mergeType === MergeType.TRACES); dbUtils.mergeSelection(
mergeType === MergeType.TRACES,
mergeType === MergeType.TRACES && $gpxStatistics.global.time.total > 0 && removeGaps
);
}} }}
> >
<Group size="16" class="mr-1 shrink-0" /> <Group size="16" class="mr-1 shrink-0" />

View File

@@ -3,6 +3,7 @@
import { Switch } from '$lib/components/ui/switch'; import { Switch } from '$lib/components/ui/switch';
import { Label } from '$lib/components/ui/label/index.js'; import { Label } from '$lib/components/ui/label/index.js';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import * as RadioGroup from '$lib/components/ui/radio-group';
import Help from '$lib/components/Help.svelte'; import Help from '$lib/components/Help.svelte';
import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte'; import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte';
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
@@ -19,16 +20,22 @@
RouteOff, RouteOff,
Repeat, Repeat,
SquareArrowUpLeft, SquareArrowUpLeft,
SquareArrowOutDownRight SquareArrowOutDownRight,
Timer
} from 'lucide-svelte'; } from 'lucide-svelte';
import { map, newGPXFile, routingControls, selectFileWhenLoaded } from '$lib/stores'; import {
gpxStatistics,
map,
newGPXFile,
routingControls,
selectFileWhenLoaded
} from '$lib/stores';
import { dbUtils, getFile, getFileIds, settings } from '$lib/db'; import { dbUtils, getFile, getFileIds, settings } from '$lib/db';
import { brouterProfiles, routingProfileSelectItem } from './Routing'; import { brouterProfiles, routingProfileSelectItem } from './Routing';
import { _, locale } from 'svelte-i18n'; import { _, locale } from 'svelte-i18n';
import { RoutingControls } from './RoutingControls'; import { RoutingControls } from './RoutingControls';
import mapboxgl from 'mapbox-gl';
import { fileObservers } from '$lib/db'; import { fileObservers } from '$lib/db';
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
import { getOrderedSelection, selection } from '$lib/components/file-list/Selection'; import { getOrderedSelection, selection } from '$lib/components/file-list/Selection';
@@ -40,6 +47,7 @@
type ListItem type ListItem
} from '$lib/components/file-list/FileList'; } from '$lib/components/file-list/FileList';
import { flyAndScale, getURLForLanguage, resetCursor, setCrosshairCursor } from '$lib/utils'; import { flyAndScale, getURLForLanguage, resetCursor, setCrosshairCursor } from '$lib/utils';
import { TimestampsMode } from '$lib/types';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { TrackPoint } from 'gpx'; import { TrackPoint } from 'gpx';
@@ -49,7 +57,7 @@
export let popupElement: HTMLElement | undefined = undefined; export let popupElement: HTMLElement | undefined = undefined;
let selectedItem: ListItem | null = null; let selectedItem: ListItem | null = null;
const { privateRoads, routing } = settings; const { privateRoads, routing, timestampsMode } = settings;
$: if ($map && popup && popupElement) { $: if ($map && popup && popupElement) {
// remove controls for deleted files // remove controls for deleted files
@@ -161,7 +169,7 @@
</Select.Root> </Select.Root>
</Label> </Label>
<Label class="flex flex-row justify-between items-center gap-2"> <Label class="flex flex-row justify-between items-center gap-2">
<span class="flex flex-row gap-1"> <span class="flex flex-row items-center gap-1">
<TriangleAlert size="16" /> <TriangleAlert size="16" />
{$_('toolbar.routing.allow_private')} {$_('toolbar.routing.allow_private')}
</span> </span>
@@ -169,6 +177,28 @@
</Label> </Label>
</div> </div>
{/if} {/if}
{#if $gpxStatistics.global.time.total > 0}
<RadioGroup.Root bind:value={$timestampsMode}>
<div class="flex flex-row items-center gap-2">
<RadioGroup.Item
value={TimestampsMode.PRESERVE_AVERAGE_SPEED}
id={TimestampsMode.PRESERVE_AVERAGE_SPEED}
/>
<Label for={TimestampsMode.PRESERVE_AVERAGE_SPEED}>
{$_('toolbar.routing.preserve_average_speed')}
</Label>
</div>
<div class="flex flex-row items-center gap-2">
<RadioGroup.Item
value={TimestampsMode.PRESERVE_TIMESTAMPS}
id={TimestampsMode.PRESERVE_TIMESTAMPS}
/>
<Label for={TimestampsMode.PRESERVE_TIMESTAMPS}>
{$_('toolbar.routing.preserve_timestamps')}
</Label>
</div>
</RadioGroup.Root>
{/if}
</div> </div>
<div class="flex flex-row flex-wrap justify-center gap-1"> <div class="flex flex-row flex-wrap justify-center gap-1">
<ButtonWithTooltip <ButtonWithTooltip

View File

@@ -3,7 +3,6 @@ import { TrackPoint, distance } from "gpx";
import { derived, get, writable } from "svelte/store"; import { derived, get, writable } from "svelte/store";
import { settings } from "$lib/db"; import { settings } from "$lib/db";
import { _, isLoading, locale } from "svelte-i18n"; import { _, isLoading, locale } from "svelte-i18n";
import { map } from "$lib/stores";
import { getElevation } from "$lib/utils"; import { getElevation } from "$lib/utils";
const { routing, routingProfile, privateRoads } = settings; const { routing, routingProfile, privateRoads } = settings;
@@ -66,7 +65,7 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
const latIdx = messages[0].indexOf("Latitude"); const latIdx = messages[0].indexOf("Latitude");
const tagIdx = messages[0].indexOf("WayTags"); const tagIdx = messages[0].indexOf("WayTags");
let messageIdx = 1; let messageIdx = 1;
let surface = messageIdx < messages.length ? getSurface(messages[messageIdx][tagIdx]) : undefined; let tags = messageIdx < messages.length ? getTags(messages[messageIdx][tagIdx]) : {};
for (let i = 0; i < coordinates.length; i++) { for (let i = 0; i < coordinates.length; i++) {
let coord = coordinates[i]; let coord = coordinates[i];
@@ -83,25 +82,26 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
coordinates[i][1] == Number(messages[messageIdx][latIdx]) / 1000000) { coordinates[i][1] == Number(messages[messageIdx][latIdx]) / 1000000) {
messageIdx++; messageIdx++;
if (messageIdx == messages.length) surface = undefined; if (messageIdx == messages.length) tags = {};
else surface = getSurface(messages[messageIdx][tagIdx]); else tags = getTags(messages[messageIdx][tagIdx]);
} }
if (surface) { route[route.length - 1].setExtensions(tags);
route[route.length - 1].setSurface(surface);
}
} }
return route; return route;
} }
function getSurface(message: string): string | undefined { function getTags(message: string): { [key: string]: string } {
const fields = message.split(" "); const fields = message.split(" ");
for (let i = 0; i < fields.length; i++) if (fields[i].startsWith("surface=")) { let tags: { [key: string]: string } = {};
return fields[i].substring(8); for (let i = 0; i < fields.length; i++) {
let [key, value] = fields[i].split("=");
key = key.replace(/:/g, '_');
tags[key] = value;
} }
return undefined; return tags;
}; }
function getIntermediatePoints(points: Coordinates[]): Promise<TrackPoint[]> { function getIntermediatePoints(points: Coordinates[]): Promise<TrackPoint[]> {
let route: TrackPoint[] = []; let route: TrackPoint[] = [];

View File

@@ -2,15 +2,16 @@ import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedP
import { get, writable, type Readable } from "svelte/store"; import { get, writable, type Readable } from "svelte/store";
import mapboxgl from "mapbox-gl"; import mapboxgl from "mapbox-gl";
import { route } from "./Routing"; import { route } from "./Routing";
import { toast } from "svelte-sonner"; import { toast } from "svelte-sonner";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { dbUtils, type GPXFileWithStatistics } from "$lib/db"; import { dbUtils, settings, type GPXFileWithStatistics } from "$lib/db";
import { getOrderedSelection, selection } from "$lib/components/file-list/Selection"; import { getOrderedSelection, selection } from "$lib/components/file-list/Selection";
import { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList"; import { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
import { currentTool, streetViewEnabled, Tool } from "$lib/stores"; import { currentTool, streetViewEnabled, Tool } from "$lib/stores";
import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils"; import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils";
import { TimestampsMode } from "$lib/types";
const { streetViewSource, timestampsMode } = settings;
export const canChangeStart = writable(false); export const canChangeStart = writable(false);
@@ -458,7 +459,7 @@ export class RoutingControls {
} }
async appendAnchor(e: mapboxgl.MapMouseEvent) { // Add a new anchor to the end of the last segment async appendAnchor(e: mapboxgl.MapMouseEvent) { // Add a new anchor to the end of the last segment
if (get(streetViewEnabled)) { if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
return; return;
} }
@@ -574,9 +575,11 @@ export class RoutingControls {
} }
if (anchors[0].point._data.index === 0) { // First anchor is the first point of the segment if (anchors[0].point._data.index === 0) { // First anchor is the first point of the segment
response[0].time = anchors[0].point.time;
anchors[0].point = response[0]; // replace the first anchor anchors[0].point = response[0]; // replace the first anchor
anchors[0].point._data.index = 0; anchors[0].point._data.index = 0;
} else if (anchors[0].point._data.index === segment.trkpt.length - 1 && distance(anchors[0].point.getCoordinates(), response[0].getCoordinates()) < 1) { // First anchor is the last point of the segment, and the new point is close enough } else if (anchors[0].point._data.index === segment.trkpt.length - 1 && distance(anchors[0].point.getCoordinates(), response[0].getCoordinates()) < 1) { // First anchor is the last point of the segment, and the new point is close enough
response[0].time = anchors[0].point.time;
anchors[0].point = response[0]; // replace the first anchor anchors[0].point = response[0]; // replace the first anchor
anchors[0].point._data.index = segment.trkpt.length - 1; anchors[0].point._data.index = segment.trkpt.length - 1;
} else { } else {
@@ -585,6 +588,7 @@ export class RoutingControls {
} }
if (anchors[anchors.length - 1].point._data.index === segment.trkpt.length - 1) { // Last anchor is the last point of the segment if (anchors[anchors.length - 1].point._data.index === segment.trkpt.length - 1) { // Last anchor is the last point of the segment
response[response.length - 1].time = anchors[anchors.length - 1].point.time;
anchors[anchors.length - 1].point = response[response.length - 1]; // replace the last anchor anchors[anchors.length - 1].point = response[response.length - 1]; // replace the last anchor
anchors[anchors.length - 1].point._data.index = segment.trkpt.length - 1; anchors[anchors.length - 1].point._data.index = segment.trkpt.length - 1;
} else { } else {
@@ -608,20 +612,40 @@ export class RoutingControls {
let startTime = anchors[0].point.time; let startTime = anchors[0].point.time;
if (stats.global.speed.moving > 0) { if (stats.global.speed.moving > 0) {
let replacingTime = 0;
if (get(timestampsMode) === TimestampsMode.PRESERVE_TIMESTAMPS) {
this.extendResponseToContiguousAdaptedTimePoints(segment, anchors, response);
response.forEach((point) => point.time = undefined);
startTime = anchors[0].point.time;
replacingTime = stats.local.time.total[anchors[anchors.length - 1].point._data.index] - stats.local.time.total[anchors[0].point._data.index];
if (replacingTime > 0) {
for (let i = 1; i < anchors.length - 1; i++) {
anchors[i].point._data['adapted_time'] = true;
}
}
}
let replacingDistance = 0; let replacingDistance = 0;
for (let i = 1; i < response.length; i++) { for (let i = 1; i < response.length; i++) {
replacingDistance += distance(response[i - 1].getCoordinates(), response[i].getCoordinates()) / 1000; replacingDistance += distance(response[i - 1].getCoordinates(), response[i].getCoordinates()) / 1000;
} }
let replacedDistance = stats.local.distance.moving[anchors[anchors.length - 1].point._data.index] - stats.local.distance.moving[anchors[0].point._data.index];
let newDistance = stats.global.distance.moving + replacingDistance - replacedDistance; if (get(timestampsMode) === TimestampsMode.PRESERVE_AVERAGE_SPEED || replacingTime === 0) {
let newTime = newDistance / stats.global.speed.moving * 3600; let replacedDistance = stats.local.distance.moving[anchors[anchors.length - 1].point._data.index] - stats.local.distance.moving[anchors[0].point._data.index];
let remainingTime = stats.global.time.moving - (stats.local.time.moving[anchors[anchors.length - 1].point._data.index] - stats.local.time.moving[anchors[0].point._data.index]); let newDistance = stats.global.distance.moving + replacingDistance - replacedDistance;
let replacingTime = newTime - remainingTime; let newTime = newDistance / stats.global.speed.moving * 3600;
if (replacingTime <= 0) { // Fallback to simple time difference let remainingTime = stats.global.time.moving - (stats.local.time.moving[anchors[anchors.length - 1].point._data.index] - stats.local.time.moving[anchors[0].point._data.index]);
replacingTime = stats.local.time.total[anchors[anchors.length - 1].point._data.index] - stats.local.time.total[anchors[0].point._data.index]; replacingTime = newTime - remainingTime;
if (replacingTime <= 0) { // Fallback to simple time difference
replacingTime = stats.local.time.total[anchors[anchors.length - 1].point._data.index] - stats.local.time.total[anchors[0].point._data.index];
}
} }
speed = replacingDistance / replacingTime * 3600; speed = replacingDistance / replacingTime * 3600;
@@ -637,6 +661,41 @@ export class RoutingControls {
return true; return true;
} }
extendResponseToContiguousAdaptedTimePoints(segment: TrackSegment, anchors: Anchor[], response: TrackPoint[]) {
while (anchors[0].point._data.adapted_time) {
let previousAnchor = null;
for (let i = 0; i < this.anchors.length; i++) {
if (this.anchors[i].point._data.index < anchors[0].point._data.index) {
previousAnchor = this.anchors[i];
} else {
break;
}
}
if (previousAnchor === null) {
break;
} else {
response.splice(0, 0, ...segment.trkpt.slice(previousAnchor.point._data.index, anchors[0].point._data.index).map((point) => point.clone()));
anchors.splice(0, 0, previousAnchor);
}
}
while (anchors[anchors.length - 1].point._data.adapted_time) {
let nextAnchor = null;
for (let i = this.anchors.length - 1; i >= 0; i--) {
if (this.anchors[i].point._data.index > anchors[anchors.length - 1].point._data.index) {
nextAnchor = this.anchors[i];
} else {
break;
}
}
if (nextAnchor === null) {
break;
} else {
response.push(...segment.trkpt.slice(anchors[anchors.length - 1].point._data.index + 1, nextAnchor.point._data.index + 1).map((point) => point.clone()));
anchors.push(nextAnchor);
}
}
}
destroy() { destroy() {
this.remove(); this.remove();
this.unsubscribes.forEach((unsubscribe) => unsubscribe()); this.unsubscribes.forEach((unsubscribe) => unsubscribe());

View File

@@ -1,31 +1,33 @@
<script lang="ts"> <script lang="ts">
import { ScrollArea as ScrollAreaPrimitive } from "bits-ui"; import { ScrollArea as ScrollAreaPrimitive } from 'bits-ui';
import { Scrollbar } from "./index.js"; import { Scrollbar } from './index.js';
import { cn } from "$lib/utils.js"; import { cn } from '$lib/utils.js';
type $$Props = ScrollAreaPrimitive.Props & { type $$Props = ScrollAreaPrimitive.Props & {
orientation?: "vertical" | "horizontal" | "both"; orientation?: 'vertical' | 'horizontal' | 'both';
scrollbarXClasses?: string; scrollbarXClasses?: string;
scrollbarYClasses?: string; scrollbarYClasses?: string;
viewportClasses?: string;
}; };
let className: $$Props["class"] = undefined; let className: $$Props['class'] = undefined;
export { className as class }; export { className as class };
export let orientation = "vertical"; export let orientation = 'vertical';
export let scrollbarXClasses: string = ""; export let scrollbarXClasses: string = '';
export let scrollbarYClasses: string = ""; export let scrollbarYClasses: string = '';
export let viewportClasses: string = '';
</script> </script>
<ScrollAreaPrimitive.Root {...$$restProps} class={cn("relative overflow-hidden", className)}> <ScrollAreaPrimitive.Root {...$$restProps} class={cn('relative overflow-hidden', className)}>
<ScrollAreaPrimitive.Viewport class="h-full w-full rounded-[inherit]"> <ScrollAreaPrimitive.Viewport class={cn('h-full w-full rounded-[inherit]', viewportClasses)}>
<ScrollAreaPrimitive.Content> <ScrollAreaPrimitive.Content>
<slot /> <slot />
</ScrollAreaPrimitive.Content> </ScrollAreaPrimitive.Content>
</ScrollAreaPrimitive.Viewport> </ScrollAreaPrimitive.Viewport>
{#if orientation === "vertical" || orientation === "both"} {#if orientation === 'vertical' || orientation === 'both'}
<Scrollbar orientation="vertical" class={scrollbarYClasses} /> <Scrollbar orientation="vertical" class={scrollbarYClasses} />
{/if} {/if}
{#if orientation === "horizontal" || orientation === "both"} {#if orientation === 'horizontal' || orientation === 'both'}
<Scrollbar orientation="horizontal" class={scrollbarXClasses} /> <Scrollbar orientation="horizontal" class={scrollbarXClasses} />
{/if} {/if}
<ScrollAreaPrimitive.Corner /> <ScrollAreaPrimitive.Corner />

View File

@@ -9,8 +9,8 @@ import { ListFileItem, ListItem, ListTrackItem, ListLevel, ListTrackSegmentItem,
import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify'; import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify';
import { SplitType } from '$lib/components/toolbar/tools/scissors/Scissors.svelte'; import { SplitType } from '$lib/components/toolbar/tools/scissors/Scissors.svelte';
import { getClosestLinePoint, getElevation } from '$lib/utils'; import { getClosestLinePoint, getElevation } from '$lib/utils';
import { TimestampsMode } from '$lib/types';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import type mapboxgl from 'mapbox-gl';
enableMapSet(); enableMapSet();
enablePatches(); enablePatches();
@@ -91,6 +91,7 @@ export const settings = {
routing: dexieSettingStore('routing', true), routing: dexieSettingStore('routing', true),
routingProfile: dexieSettingStore('routingProfile', 'bike'), routingProfile: dexieSettingStore('routingProfile', 'bike'),
privateRoads: dexieSettingStore('privateRoads', false), privateRoads: dexieSettingStore('privateRoads', false),
timestampsMode: dexieSettingStore('timestampsMode', TimestampsMode.PRESERVE_AVERAGE_SPEED),
currentBasemap: dexieSettingStore('currentBasemap', defaultBasemap), currentBasemap: dexieSettingStore('currentBasemap', defaultBasemap),
previousBasemap: dexieSettingStore('previousBasemap', defaultBasemap), previousBasemap: dexieSettingStore('previousBasemap', defaultBasemap),
selectedBasemapTree: dexieSettingStore('selectedBasemapTree', defaultBasemapTree), selectedBasemapTree: dexieSettingStore('selectedBasemapTree', defaultBasemapTree),
@@ -574,7 +575,7 @@ export const dbUtils = {
}); });
}); });
}, },
mergeSelection: (mergeTraces: boolean) => { mergeSelection: (mergeTraces: boolean, removeGaps: boolean) => {
applyGlobal((draft) => { applyGlobal((draft) => {
let first = true; let first = true;
let target: ListItem = new ListRootItem(); let target: ListItem = new ListRootItem();
@@ -649,7 +650,7 @@ export const dbUtils = {
let s = new TrackSegment(); let s = new TrackSegment();
toMerge.trk.map((track) => { toMerge.trk.map((track) => {
track.trkseg.forEach((segment) => { track.trkseg.forEach((segment) => {
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime); s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime, removeGaps);
}); });
}); });
toMerge.trk = [toMerge.trk[0]]; toMerge.trk = [toMerge.trk[0]];
@@ -658,7 +659,7 @@ export const dbUtils = {
if (toMerge.trkseg.length > 0) { if (toMerge.trkseg.length > 0) {
let s = new TrackSegment(); let s = new TrackSegment();
toMerge.trkseg.forEach((segment) => { toMerge.trkseg.forEach((segment) => {
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime); s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime, removeGaps);
}); });
toMerge.trkseg = [s]; toMerge.trkseg = [s];
} }

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Soubory a statistiky
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Pomocí tlačítek vpravo od výškového profilu můžete volitelně obarvit výškový profil podle: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -9,29 +9,29 @@ title: Erste Schritte
# { title } # { title }
Willkommen bei der offiziellen Anleitung für **gpx.studio**! Willkommen bei der offiziellen Anleitung für **gpx.studio**!
This guide will walk you through all the components and tools of the interface, helping you become a proficient user of the application. Diese Anleitung führt Sie durch alle Komponenten und Werkzeuge der Benutzeroberfläche und hilft Ihnen dabei ein erfahrener Anwender zu werden.
<DocsImage src="getting-started/interface" alt="Die gpx.studio Oberfläche." /> <DocsImage src="getting-started/interface" alt="Die gpx.studio Oberfläche." />
Wie im obigen Screenshot dargestellt, ist die Oberfläche in vier Bereiche um die Karte herum aufgeteilt. Wie im obigen Screenshot dargestellt, ist die Benutzeroberfläche in vier Bereiche um die Karte herum aufgeteilt.
Bevor wir in die Details der einzelnen Bereiche einsteigen, lassen Sie uns einen Überblick der Oberfläche verschaffen. Bevor wir in die Details der einzelnen Bereiche einsteigen, lassen Sie uns einen Überblick der Benutzeroberfläche verschaffen.
## Menü ## Menü
At the top of the interface, you will find the [main menu](./menu). Am oberen Rand der Benutzeroberfläche findest du das [Hauptmenü](./menu).
This is where you can access common actions such as opening, closing, and exporting files, undoing and redoing actions, and adjusting the application settings. Hier können Sie auf allgemeine Aktionen zugreifen, wie zum Beispiel das Öffnen, Schließen und Exportieren von Dateien, Rückgängig machen und Wiederholen sowie Anpassen der Einstellungen der Anwendung.
## Files and statistics ## Files and statistics
At the bottom of the interface, you will find the list of files currently open in the application. Am unteren Rand der Benutzeroberfläche finden Sie die Liste der aktuell geöffneten Dateien der Anwendung.
You can click on a file to select it and display its statistics below the list. Sie können auf eine Datei klicken, um sie auszuwählen und ihre Statistiken unter der Liste anzuzeigen.
In the [dedicated section](./files-and-stats), we will explain how to select multiple files and switch to a vertical layout for advanced file management. Im [zugehörigen Abschnitt](./files-and-stats) werden wir erklären, wie wir mehrere Dateien auswählen und zu einem vertikalen Layout für eine erweiterte Dateiverwaltung wechseln.
## Werkzeugleiste ## Werkzeugleiste
On the left side of the interface, you will find the [toolbar](./toolbar), which contains all the tools you can use to edit your files. Am linken Rand der Benutzeroberfläche finden Sie die [Werkzeugleiste](./toolbar), die alle Werkzeuge enthält, mit denen Sie Ihre Dateien bearbeiten können.
## Kartensteuerungen ## Kartensteuerungen
Finally, on the right side of the interface, you will find the [map controls](./map-controls). Schließlich findest du am rechten Rand der Benutzeroberfläche die [Kartensteuerungen](./map-controls).
These controls allow you to navigate the map, zoom in and out, and switch between different map styles. Mit diesen Steuerelementen können Sie auf der Karte navigieren, vergrößern und zwischen verschiedenen Kartenstilen wechseln.

View File

@@ -11,7 +11,7 @@ title: Kartensteuerungen
# { title } # { title }
The map controls are located on the right side of the interface. The map controls are located on the right side of the interface.
These controls allow you to navigate the map, zoom in and out, and switch between different map styles. Mit diesen Steuerelementen können Sie auf der Karte navigieren, vergrößern und zwischen verschiedenen Kartenstilen wechseln.
### <Diff size="16" class="inline-block" style="margin-bottom: 2px" /> Map navigation ### <Diff size="16" class="inline-block" style="margin-bottom: 2px" /> Map navigation

View File

@@ -8,10 +8,10 @@ title: Menü
# { title } # { title }
The main menu, located at the top of the interface, provides access to actions, options, and settings divided into several categories, explained separately in the following sections. Das Hauptmenü, welches sich oben in der Benutzeroberfläche befindet, bietet Zugriff auf Aktionen, Optionen, und Einstellungen, die wiederum in mehrere Kategorien aufgeteilt sind, wird in den folgenden Abschnitten beschrieben.
<DocsNote> <DocsNote>
Most of the menu actions can also be performed using the keyboard shortcuts displayed in the menu. Die meisten Aktionen des Menüs können auch mit den Tastaturkürzeln ausgeführt werden, die im Menü angezeigt werden.
</DocsNote> </DocsNote>

View File

@@ -18,7 +18,7 @@ title: Werkzeugleiste
# { title } # { title }
The toolbar is located on the left side of the map and is the heart of the application, as it provides access to the main features of **gpx.studio**. Die Symbolleiste befindet sich auf der linken Seite der Karte und ist das Herzstück der Anwendung, da es Zugriff auf die wichtigsten Funktionen von **gpx.studio** bietet.
Jedes Werkzeug wird durch ein Symbol dargestellt und kann durch einen Klick aktiviert werden. Jedes Werkzeug wird durch ein Symbol dargestellt und kann durch einen Klick aktiviert werden.
<div class="flex flex-row justify-center text-foreground"> <div class="flex flex-row justify-center text-foreground">
@@ -29,4 +29,4 @@ Jedes Werkzeug wird durch ein Symbol dargestellt und kann durch einen Klick akti
As with [edit actions](./menu/edit), most tools can be applied to multiple files at once and to [inner tracks and segments](./gpx). As with [edit actions](./menu/edit), most tools can be applied to multiple files at once and to [inner tracks and segments](./gpx).
In den folgenden Abschnitten werden die einzelnen Tools detailliert beschrieben. Die folgenden Abschnitten beschreiben jedes Werkzeug im Detail.

View File

@@ -10,17 +10,17 @@ title: Extrahieren
# <Ungroup size="24" class="inline-block" style="margin-bottom: 5px" /> { title } # <Ungroup size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
Dieses Tool ermöglicht Ihnen, [tracks (or segments)](../gpx) von Dateien (oder Tracks) zu extrahieren, die mehreren von denen enthalten. Dieses Werkzeug ermöglicht Ihnen [Tracks (oder Segmente)](../gpx) von Dateien (oder Tracks) zu extrahieren, die mehreren von ihnen enthalten.
<div class="flex flex-row justify-center"> <div class="flex flex-row justify-center">
<Extract class="text-foreground p-3 border rounded-md shadow-lg" /> <Extract class="text-foreground p-3 border rounded-md shadow-lg" />
</div> </div>
Wenn Sie das Tool auf eine Datei mit mehreren enthaltenen Tracks anwenden, wird für jeden der darin enthaltenen Tracks eine neue Datei erstellt. Wenn Sie das Werkzeug auf eine Datei mit mehreren enthaltenen Tracks anwenden, wird für jeden der darin enthaltenen Tracks eine neue Datei erstellt.
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains. Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
<DocsNote> <DocsNote>
Beim Extrahieren der Tracks aus einer Datei mit <a href="../gpx">points-of-interest</a>, wird das Tool automatisch jeden Punkt zuordnen, an dem es am nächsten ist. Beim Extrahieren der Tracks aus einer Datei mit <a href="../gpx">points-of-interest</a>, wird das Werkzeug automatisch jeden Punkt zuordnen, an dem es am nächsten ist.
</DocsNote> </DocsNote>

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,9 +73,9 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Archivos y estadísticas
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ Puede usar el ratón para acercar o alejar el perfil de elevación y moverse hac
### Datos adicionales ### Datos adicionales
Usando los botones situados a la derecha del perfil de elevación, puede colorearlo por: Usando el botón <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> en la parte inferior derecha del perfil de elevación, opcionalmente puede colorear el perfil de elevación por:
- **pendiente** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> información calculada a partir de los datos de elevación, o - Información de la **pendiente** calculada a partir de los datos de elevación, o
- **superficie** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> datos obtenidos de etiquetas de <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">superficie</a> de <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>. - Datos de **superficie** o **categoría** provenientes de la <a href="https://www.openstreetmap.org/" target="_blank">superficie</a> y etiquetas de <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">autopista</a> de <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">OpenStreetMap</a>.
Solo disponible para archivos creados con **gpx.studio**. Solo disponible para archivos creados con **gpx.studio**.
Si su selección lo incluye, puede visualizar datos de **velocidad** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **ritmo cardíaco** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadencia** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperatura** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" /> y **potencia** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> en el perfil de elevación. Si su selección lo incluye, también puede visualizar datos de **velocidad**, **ritmo cardíaco**, **cadencia**, **temperatura** y **potencia** en el perfil de elevación.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Fichiers et statistiques
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ Vous pouvez également utiliser la molette de la souris pour zoomer ou dézoomer
### Données supplémentaires ### Données supplémentaires
En utilisant les boutons à droite du profil d'altitude, vous pouvez optionnellement colorier le profil d'altitude en fonction de : En utilisant le bouton <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> en bas à droite du profil d'altitude, vous pouvez optionnellement colorier le profil altimétrique en fonction :
- des données de **pente** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> calculées à partir des données d'altitude, ou - des données de **pente** calculées à partir des données d'altitude, ou
- des données de **revêtement** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> venant des tags de <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> d'<a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>. - des données de **revêtement** ou de **catégorie** venant des tags <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> et <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> d'<a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>.
Ceci est uniquement disponible pour les fichiers créés avec **gpx.studio**. Ceci est uniquement disponible pour les fichiers créés avec **gpx.studio**.
Si votre sélection possède ces données, vous pouvez également visualiser les données de : **vitesse** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **fréquence cardiaque** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **température** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" /> et **puissance** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> sur le profil altimétrique. Si votre sélection possède ces données, vous pouvez également visualiser les données de : **vitesse** , **fréquence cardiaque** , **cadence** , **température** et **puissance** sur le profil altimétrique.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -1,5 +1,5 @@
--- ---
title: FAQ title: GYIK
--- ---
<script> <script>
@@ -10,7 +10,7 @@ title: FAQ
### Do I need to donate to use the website? ### Do I need to donate to use the website?
No. Nem.
The website is free to use and always will be (as long as it is financially sustainable). The website is free to use and always will be (as long as it is financially sustainable).
However, donations are appreciated and help keep the website running. However, donations are appreciated and help keep the website running.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -69,14 +69,14 @@ When hovering over the elevation profile, a tooltip will show statistics at the
To get the statistics for a specific section of the elevation profile, you can drag a selection rectangle on the profile. To get the statistics for a specific section of the elevation profile, you can drag a selection rectangle on the profile.
Click on the profile to reset the selection. Click on the profile to reset the selection.
Az egérgörgővel is méretezhetii a magassági profilt. Balra és jobbra mozoghat a profil húzásával, miközben lenyomva tartja a <kbd>Shift</kbd> billentyűt. Az egérgörgővel is méretezheti a magassági profilt. Balra és jobbra mozoghat a profil húzásával, miközben lenyomva tartja a <kbd>Shift</kbd> billentyűt.
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -7,6 +7,6 @@
Minden alkalommal, amikor GPS-pontokat ad hozzá vagy mozgat, szervereink kiszámítják a legjobb útvonalat az úthálózaton.<a href="https://mapbox.com" target="_blank">Mapbox</a> API-jait használjuk a gyönyörű térképek megjelenítésére, a magassági adatok lekérésére és a helyek keresésére. Minden alkalommal, amikor GPS-pontokat ad hozzá vagy mozgat, szervereink kiszámítják a legjobb útvonalat az úthálózaton.<a href="https://mapbox.com" target="_blank">Mapbox</a> API-jait használjuk a gyönyörű térképek megjelenítésére, a magassági adatok lekérésére és a helyek keresésére.
Sajnos ez magas költségű. Sajnos ez magas költségű.
Ha tetszik ezt az alkalmazás, kérjük, fontoljon meg egy kis adományt, hogy a webhely továbbra is ingyenes és hirdetésmentes legyen. Ha tetszik ez az alkalmazás, kérjük, fontoljon meg egy kis adományt, hogy a webhely továbbra is ingyenes és hirdetésmentes legyen.
Nagyon szépen köszönöm a támogatást! ❤️ Nagyon szépen köszönöm a támogatást! ❤️

View File

@@ -1,5 +1,5 @@
--- ---
title: Integration title: Integráció
--- ---
<script> <script>

View File

@@ -12,6 +12,6 @@ The main menu, located at the top of the interface, provides access to actions,
<DocsNote> <DocsNote>
Most of the menu actions can also be performed using the keyboard shortcuts displayed in the menu. A menüben található műveletek többsége a menüben megjelenített billentyűparancsok segítségével is végrehajtható.
</DocsNote> </DocsNote>

View File

@@ -29,4 +29,4 @@ Each tool is represented by an icon and can be activated by clicking on it.
As with [edit actions](./menu/edit), most tools can be applied to multiple files at once and to [inner tracks and segments](./gpx). As with [edit actions](./menu/edit), most tools can be applied to multiple files at once and to [inner tracks and segments](./gpx).
The next sections describe each tool in detail. A következő szakaszok részletesen ismertetik az egyes eszközöket.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Dati aggiuntivi ### Dati aggiuntivi
Utilizzando i pulsanti a destra del profilo di elevazione, è possibile colorare opzionalmente il profilo di elevazione mediante: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> informazioni calcolate dai dati di elevazione, o - **slope** information computed from the elevation data, or
- . - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
È disponibile solo per i file creati con **gpx.studio**. È disponibile solo per i file creati con **gpx.studio**.
Se la tua selezione lo prevede puoi visualizzare anche i dati di: **velocità** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **frequenza cardiaca** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadenza** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperatura** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, e **potenza** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> sul profilo altimetrico. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -1,5 +1,5 @@
--- ---
title: Azione sui File title: Azioni sui File
--- ---
<script lang="ts"> <script lang="ts">
@@ -17,7 +17,7 @@ Crea un nuovo file vuoto.
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Apri... ### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Apri...
Open files from your computer. Apre i file dal tuo computer.
<DocsNote> <DocsNote>
@@ -33,7 +33,7 @@ Crea una copia dei file attualmente selezionati.
Close the currently selected files. Close the currently selected files.
### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Close all ### <FileX size="16" class="inline-block" style="margin-bottom: 2px" />Chiudi tutto
Chiudi tutti i file. Chiudi tutti i file.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Puslapis nerastas
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Bestanden en statistieken
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ Je kunt het muiswiel ook gebruiken om in en uit te zoomen op het hoogte profiel,
### Aanvullende gegevens ### Aanvullende gegevens
Met behulp van de knoppen aan de rechterkant van het hoogteprofiel kunt u het hoogteprofiel optioneel kleuren door: Met behulp van de <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> knoppen aan de rechterkant van het hoogteprofiel kunt u het hoogteprofiel optioneel kleuren door:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> informatie berekend op basis van de hoogtegegevens, of - **helling** informatie berekend uit de hoogtegegevens, of
- **oppervlak** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data afkomstig van <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **oppervlakte** of **categorie** gegevens afkomstig van <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>zijn <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">oppervlak</a> en <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">snelweg</a> tags.
Dit is alleen beschikbaar voor bestanden gemaakt met **gpx.studio**. Dit is alleen beschikbaar voor bestanden gemaakt met **gpx.studio**.
Als je selectie het bevat, kun je ook visualiseren: **snelheid** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **hartsnelheid** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, en **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data op het hoogteprofiel. Als je selectie het bevat, kun je ook de volgende gegevens zichtbaar maken op het hoogteprofiel: **snelheid**, **hartritme**, **tempo**, **temperatuur**, en **vermogen**.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Arquivos e estatísticas
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ Você também pode usar a roda do mouse para aumentar e diminuir o zoom no perfi
### Dados adicionais ### Dados adicionais
Usando os botões à direita do perfil de elevação, você pode opcionalmente colorir o perfil de elevação por: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **inclinação** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> informação computada a partir dos dados de elevação, ou - **slope** information computed from the elevation data, or
- **superfície** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> dados vindos dos marcadores de <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">superfície</a> do <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
Isso só está disponível para arquivos criados com **gpx.studio**. Isso só está disponível para arquivos criados com **gpx.studio**.
Se sua seleção incluir, você também pode visualizar: **velocidade** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **frequência cardíaca** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadência** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperatura** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />e **energia** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> dados sobre o perfil de elevação. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Файлы и статистика
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ title: Файлы и статистика
### Дополнительные данные ### Дополнительные данные
С помощью кнопок справа от профиля высоты можно изменить цвет профиля высоты: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **угол наклона** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> информация, вычисленная на основе данных о высоте, или - **slope** information computed from the elevation data, or
- **поверхность** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> данные, полученные из тегов <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> по ключу <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a>. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
Это доступно только для файлов, созданных с помощью **gpx.studio**. Это доступно только для файлов, созданных с помощью **gpx.studio**.
Если ваш выбор включает это, вы также можете визуализировать: **скорость** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **частоту сердечных сокращений** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **каденцию** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **температуру** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, и **мощность** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> данные на профиле высоты. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

View File

@@ -3,7 +3,7 @@ title: Files and statistics
--- ---
<script> <script>
import { TriangleRight, BrickWall, Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte'; import { ChartNoAxesColumn } from 'lucide-svelte';
import DocsNote from '$lib/components/docs/DocsNote.svelte'; import DocsNote from '$lib/components/docs/DocsNote.svelte';
</script> </script>
@@ -74,10 +74,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
### Additional data ### Additional data
Using the buttons on the right of the elevation profile, you can optionally color the elevation profile by: Using the <kbd><ChartNoAxesColumn size="16" class="inline-block" style="margin-bottom: 2px"/></kbd> button at the bottom-right of the elevation profile, you can optionally color the elevation profile by:
- **slope** <TriangleRight size="16" class="inline-block" style="margin-bottom: 2px" /> information computed from the elevation data, or - **slope** information computed from the elevation data, or
- **surface** <BrickWall size="16" class="inline-block" style="margin-bottom: 2px" /> data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> tags. - **surface** or **category** data coming from <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a>'s <a href="https://wiki.openstreetmap.org/wiki/Key:surface" target="_blank">surface</a> and <a href="https://wiki.openstreetmap.org/wiki/Key:highway" target="_blank">highway</a> tags.
This is only available for files created with **gpx.studio**. This is only available for files created with **gpx.studio**.
If your selection includes it, you can also visualize: **speed** <Zap size="16" class="inline-block" style="margin-bottom: 2px" />, **heart rate** <HeartPulse size="16" class="inline-block" style="margin-bottom: 2px" />, **cadence** <Orbit size="16" class="inline-block" style="margin-bottom: 2px" />, **temperature** <Thermometer size="16" class="inline-block" style="margin-bottom: 2px" />, and **power** <SquareActivity size="16" class="inline-block" style="margin-bottom: 2px" /> data on the elevation profile. If your selection includes it, you can also visualize: **speed**, **heart rate**, **cadence**, **temperature** and **power** data on the elevation profile.

4
website/src/lib/types.ts Normal file
View File

@@ -0,0 +1,4 @@
export enum TimestampsMode {
PRESERVE_TIMESTAMPS = 'preserve_timestamps',
PRESERVE_AVERAGE_SPEED = 'preserve_average_speed',
};

View File

@@ -12,6 +12,7 @@ import mapboxgl from "mapbox-gl";
import tilebelt from "@mapbox/tilebelt"; import tilebelt from "@mapbox/tilebelt";
import { PUBLIC_MAPBOX_TOKEN } from "$env/static/public"; import { PUBLIC_MAPBOX_TOKEN } from "$env/static/public";
import PNGReader from "png.js"; import PNGReader from "png.js";
import type { DateFormatter } from "@internationalized/date";
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
@@ -215,4 +216,16 @@ export function getURLForLanguage(lang: string | null | undefined, path: string)
return `${base}${newPath}`; return `${base}${newPath}`;
} }
} }
} }
function getDateFormatter(locale: string) {
return new Intl.DateTimeFormat(locale, {
dateStyle: 'medium',
timeStyle: 'medium'
});
}
export let df: DateFormatter = getDateFormatter('en');
locale.subscribe((l) => {
df = getDateFormatter(l ?? 'en');
});

View File

@@ -119,11 +119,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Wood", "wood": "Wood",
@@ -135,15 +132,59 @@
"dirt": "Dirt", "dirt": "Dirt",
"ground": "Ground", "ground": "Ground",
"earth": "Earth", "earth": "Earth",
"snow": "Snow",
"ice": "Ice",
"salt": "Salt",
"mud": "Mud", "mud": "Mud",
"sand": "Sand", "sand": "Sand",
"woodchips": "Woodchips",
"grass": "Grass", "grass": "Grass",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "No pavimentat", "unpaved": "No pavimentat",
"asphalt": "Asfalt", "asphalt": "Asfalt",
"concrete": "Formigó", "concrete": "Formigó",
"chipseal": "Camí asfaltat",
"cobblestone": "Llambordes", "cobblestone": "Llambordes",
"unhewn_cobblestone": "Llambordes grosses",
"paving_stones": "Camí de pedres", "paving_stones": "Camí de pedres",
"stepping_stones": "Empedrat",
"sett": "Establir", "sett": "Establir",
"metal": "Metall", "metal": "Metall",
"wood": "Fusta", "wood": "Fusta",
@@ -135,15 +132,59 @@
"dirt": "Terra", "dirt": "Terra",
"ground": "Terreny", "ground": "Terreny",
"earth": "Planeta Terra", "earth": "Planeta Terra",
"snow": "Neu",
"ice": "Gel",
"salt": "Sal",
"mud": "Fang", "mud": "Fang",
"sand": "Sorra", "sand": "Sorra",
"woodchips": "Estella forestal",
"grass": "Herba", "grass": "Herba",
"grass_paver": "Gespa" "grass_paver": "Gespa",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "El punt d'inici és massa lluny de la via més propera", "from": "El punt d'inici és massa lluny de la via més propera",
"via": "El punt és massa lluny de la via més propera", "via": "El punt és massa lluny de la via més propera",
@@ -173,6 +214,7 @@
"merge_traces": "Connectar les traçades", "merge_traces": "Connectar les traçades",
"merge_contents": "Unir els continguts i mantenir les traçades desconnectades", "merge_contents": "Unir els continguts i mantenir les traçades desconnectades",
"merge_selection": "Combinar la selecció", "merge_selection": "Combinar la selecció",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Unir els elements", "tooltip": "Unir els elements",
"help_merge_traces": "Unir les traçades crearà una única traçada contínua.", "help_merge_traces": "Unir les traçades crearà una única traçada contínua.",
"help_cannot_merge_traces": "Has de sel·leccionar diverses traçades per tal d'unir-les.", "help_cannot_merge_traces": "Has de sel·leccionar diverses traçades per tal d'unir-les.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distancia", "distance": "Distancia",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Pendent", "slope": "Pendent",
"surface": "Superfície", "surface": "Superfície",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Nezpevněné", "unpaved": "Nezpevněné",
"asphalt": "Asfalt", "asphalt": "Asfalt",
"concrete": "Beton", "concrete": "Beton",
"chipseal": "Chipseal",
"cobblestone": "Dlažební kostky", "cobblestone": "Dlažební kostky",
"unhewn_cobblestone": "Hrubá dlažba",
"paving_stones": "Dlažba", "paving_stones": "Dlažba",
"stepping_stones": "Nášlapné kameny",
"sett": "Dlažební kostky", "sett": "Dlažební kostky",
"metal": "Kov", "metal": "Kov",
"wood": "Dřevo", "wood": "Dřevo",
@@ -135,15 +132,59 @@
"dirt": "Hlína", "dirt": "Hlína",
"ground": "Pozemek", "ground": "Pozemek",
"earth": "Země", "earth": "Země",
"snow": "Sníh",
"ice": "Led",
"salt": "Sůl",
"mud": "Bláto", "mud": "Bláto",
"sand": "Písek", "sand": "Písek",
"woodchips": "Dřevěné štěpky",
"grass": "Tráva", "grass": "Tráva",
"grass_paver": "Zatravňovací dlažba" "grass_paver": "Zatravňovací dlažba",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "Počáteční bod je příliš daleko od nejbližší cesty", "from": "Počáteční bod je příliš daleko od nejbližší cesty",
"via": "Průchozí bod je příliš daleko od nejbližší cesty", "via": "Průchozí bod je příliš daleko od nejbližší cesty",
@@ -173,6 +214,7 @@
"merge_traces": "Připojit trasy", "merge_traces": "Připojit trasy",
"merge_contents": "Sloučit obsah a zachovat trasy oddělené", "merge_contents": "Sloučit obsah a zachovat trasy oddělené",
"merge_selection": "Sloučit výběr", "merge_selection": "Sloučit výběr",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Sloučit položky", "tooltip": "Sloučit položky",
"help_merge_traces": "Připojení vybraných tras vytvoří jednu spojitou trasu.", "help_merge_traces": "Připojení vybraných tras vytvoří jednu spojitou trasu.",
"help_cannot_merge_traces": "Váš výběr musí obsahovat několik tras, které je chcete připojit.", "help_cannot_merge_traces": "Váš výběr musí obsahovat několik tras, které je chcete připojit.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topografická", "ignFrTopo": "IGN Topografická",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satelitní", "ignFrSatellite": "IGN Satelitní",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topografická", "swedenTopo": "Lantmäteriet Topografická",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Zobrazit sklon svahu", "settings": "Elevation profile settings"
"show_surface": "Zobrazit údaje o povrchu",
"show_speed": "Zobrazit údaje o rychlosti",
"show_pace": "Zobrazit údaje o tempu",
"show_heartrate": "Zobrazit údaje o tepové frekvenci",
"show_cadence": "Zobrazit údaje o kadenci",
"show_temperature": "Zobrazit údaje o teplotě",
"show_power": "Zobrazit údaje o energii"
}, },
"quantities": { "quantities": {
"distance": "Vzdálenost", "distance": "Vzdálenost",
@@ -366,9 +402,11 @@
"power": "Energie", "power": "Energie",
"slope": "Sklon", "slope": "Sklon",
"surface": "Povrch", "surface": "Povrch",
"highway": "Category",
"time": "Čas", "time": "Čas",
"moving": "V pohybu", "moving": "V pohybu",
"total": "Celkem" "total": "Celkem",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Wood", "wood": "Wood",
@@ -135,15 +132,59 @@
"dirt": "Dirt", "dirt": "Dirt",
"ground": "Ground", "ground": "Ground",
"earth": "Earth", "earth": "Earth",
"snow": "Snow",
"ice": "Ice",
"salt": "Salt",
"mud": "Mud", "mud": "Mud",
"sand": "Sand", "sand": "Sand",
"woodchips": "Woodchips",
"grass": "Grass", "grass": "Grass",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -1,7 +1,7 @@
{ {
"metadata": { "metadata": {
"home_title": "der online GPX Datei Editor", "home_title": "der online GPX Datei Editor",
"app_title": "app", "app_title": "App",
"embed_title": "der online GPX Datei Editor", "embed_title": "der online GPX Datei Editor",
"help_title": "hilfe", "help_title": "hilfe",
"404_title": "Seite nicht gefunden", "404_title": "Seite nicht gefunden",
@@ -33,8 +33,8 @@
"select_all": "Alle auswählen", "select_all": "Alle auswählen",
"view": "Ansicht", "view": "Ansicht",
"elevation_profile": "Höhenprofil", "elevation_profile": "Höhenprofil",
"vertical_file_view": "Vertical file list", "vertical_file_view": "Vertikale Dateiliste",
"switch_basemap": "Switch to previous basemap", "switch_basemap": "Zur vorherigen Basemap wechseln",
"toggle_overlays": "Toggle overlays", "toggle_overlays": "Toggle overlays",
"toggle_3d": "3D umschalten", "toggle_3d": "3D umschalten",
"settings": "Einstellungen", "settings": "Einstellungen",
@@ -49,21 +49,21 @@
"language": "Sprache", "language": "Sprache",
"mode": "Design", "mode": "Design",
"system": "System", "system": "System",
"light": "Light", "light": "Hell",
"dark": "Dark", "dark": "Dunkel",
"street_view_source": "Street view source", "street_view_source": "Street View Quelle",
"mapillary": "Mapillary", "mapillary": "Mapillary",
"google": "Google", "google": "Google",
"toggle_street_view": "Street view", "toggle_street_view": "Street View",
"layers": "Map layers...", "layers": "Map layers...",
"distance_markers": "Entfernungsmarkierungen", "distance_markers": "Entfernungsmarkierungen",
"direction_markers": "Direction arrows", "direction_markers": "Direction arrows",
"help": "Hilfe", "help": "Hilfe",
"more": "More...", "more": "Mehr...",
"donate": "Spenden", "donate": "Spenden",
"ctrl": "Strg", "ctrl": "Strg",
"click": "Klick", "click": "Klick",
"drag": "Drag", "drag": "Ziehen",
"metadata": { "metadata": {
"button": "Info...", "button": "Info...",
"name": "Bezeichnung", "name": "Bezeichnung",
@@ -77,83 +77,124 @@
"width": "Breite" "width": "Breite"
}, },
"hide": "Verbergen", "hide": "Verbergen",
"unhide": "Unhide", "unhide": "Einblenden",
"center": "Center", "center": "Center",
"open_in": "Open in" "open_in": "Open in"
}, },
"toolbar": { "toolbar": {
"routing": { "routing": {
"tooltip": "Plan or edit a route", "tooltip": "Route planen oder bearbeiten",
"activity": "Aktivität", "activity": "Aktivität",
"use_routing": "Routenführung", "use_routing": "Routenführung",
"use_routing_tooltip": "Connect anchor points via road network, or in a straight line if disabled", "use_routing_tooltip": "Connect anchor points via road network, or in a straight line if disabled",
"allow_private": "Allow private roads", "allow_private": "Private Straßen erlauben",
"reverse": { "reverse": {
"button": "Umkehren", "button": "Umkehren",
"tooltip": "Reverse the direction of the route" "tooltip": "Die Richtung der Route umkehren"
}, },
"route_back_to_start": { "route_back_to_start": {
"button": "Back to start", "button": "Zurück zum Start",
"tooltip": "Connect the last point of the route with the starting point" "tooltip": "Den letzten Punkt der Route mit dem Startpunkt verbinden"
}, },
"round_trip": { "round_trip": {
"button": "Round trip", "button": "Rundfahrt",
"tooltip": "Return to the starting point by the same route" "tooltip": "Kehre mit derselben Route zum Startpunkt zurück"
}, },
"start_loop_here": "Schleife hier starten", "start_loop_here": "Schleife hier starten",
"help_no_file": "Select a trace to use the routing tool, or click on the map to start creating a new route.", "help_no_file": "Select a trace to use the routing tool, or click on the map to start creating a new route.",
"help": "Click on the map to add a new anchor point, or drag existing ones to change the route.", "help": "Click on the map to add a new anchor point, or drag existing ones to change the route.",
"activities": { "activities": {
"bike": "Rad", "bike": "Fahrrad",
"racing_bike": "Road bike", "racing_bike": "Rennrad",
"gravel_bike": "Gravel Bike", "gravel_bike": "Gravel Bike",
"mountain_bike": "Mountainbike", "mountain_bike": "Mountainbike",
"foot": "Laufen/Wandern", "foot": "Laufen/Wandern",
"motorcycle": "Moped", "motorcycle": "Motorrad",
"water": "Water", "water": "Wasser",
"railway": "Railway" "railway": "Railway"
}, },
"surface": { "surface": {
"unknown": "Unknown", "unknown": "Unbekannt",
"paved": "Gepflastert", "paved": "Gepflastert",
"unpaved": "Unbefestigt", "unpaved": "Unbefestigt",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Beton", "concrete": "Beton",
"chipseal": "Chipseal",
"cobblestone": "Kopfsteinpflaster", "cobblestone": "Kopfsteinpflaster",
"unhewn_cobblestone": "Unhewn cobblestone", "paving_stones": "Verbundsteine",
"paving_stones": "Paving stones", "sett": "Behauenes Steinpflaster",
"stepping_stones": "Stepping stones",
"sett": "Sett",
"metal": "Metall", "metal": "Metall",
"wood": "Holz", "wood": "Holz",
"compacted": "Compacted gravel", "compacted": "verdichtet",
"fine_gravel": "Fine gravel", "fine_gravel": "Feiner Schotter",
"gravel": "Schotter", "gravel": "Schotter",
"pebblestone": "Kieselsteine", "pebblestone": "Kieselsteine",
"rock": "Fels", "rock": "Fels",
"dirt": "Dreck", "dirt": "Dreck",
"ground": "Boden", "ground": "Boden",
"earth": "Erde", "earth": "Erde",
"snow": "Schnee",
"ice": "Eis",
"salt": "Salz",
"mud": "Matsch", "mud": "Matsch",
"sand": "Sand", "sand": "Sand",
"woodchips": "Holzhäcksel",
"grass": "Gras", "grass": "Gras",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "Der Startpunkt ist zu weit von der nächsten Straße entfernt",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
"to": "The end point is too far from the nearest road", "to": "Der Endpunkt ist zu weit von der nächsten Straße entfernt",
"timeout": "Route calculation took too long, try adding points closer together" "timeout": "Route calculation took too long, try adding points closer together"
} }
}, },
"scissors": { "scissors": {
"tooltip": "Crop or split", "tooltip": "Schneiden oder Teilen",
"crop": "Crop", "crop": "Schneiden",
"split_as": "Split the trace into", "split_as": "Split the trace into",
"help_invalid_selection": "Select a trace to crop or split.", "help_invalid_selection": "Select a trace to crop or split.",
"help": "Use the slider to crop the trace, or split it by clicking on one of the split markers or on the trace itself." "help": "Use the slider to crop the trace, or split it by clicking on one of the split markers or on the trace itself."
@@ -161,11 +202,11 @@
"time": { "time": {
"tooltip": "Manage time data", "tooltip": "Manage time data",
"start": "Start", "start": "Start",
"end": "End", "end": "Ziel",
"total_time": "Zeit in Bewegung", "total_time": "Zeit in Bewegung",
"pick_date": "Pick a date", "pick_date": "Datum auswählen",
"artificial": "Create realistic time data", "artificial": "Erstelle realistische Zeitdaten",
"update": "Update time data", "update": "Aktualisiere Zeitdaten",
"help": "Use the form to set new time data.", "help": "Use the form to set new time data.",
"help_invalid_selection": "Select a single trace to manage its time data." "help_invalid_selection": "Select a single trace to manage its time data."
}, },
@@ -173,7 +214,8 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Auswahl zusammenführen", "merge_selection": "Auswahl zusammenführen",
"tooltip": "Merge items together", "remove_gaps": "Remove time gaps between traces",
"tooltip": "Elemente zusammenführen",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
"help_merge_contents": "Merging the contents of the selected items will group all the contents inside the first item.", "help_merge_contents": "Merging the contents of the selected items will group all the contents inside the first item.",
@@ -195,8 +237,8 @@
"tooltip": "Create and edit points of interest", "tooltip": "Create and edit points of interest",
"icon": "Icon", "icon": "Icon",
"link": "Link", "link": "Link",
"longitude": "Longitude", "longitude": "Längengrad",
"latitude": "Latitude", "latitude": "Breitengrad",
"create": "Create point of interest", "create": "Create point of interest",
"add": "Add point of interest to file", "add": "Add point of interest to file",
"help": "Fill in the form to create a new point of interest, or click on an existing one to edit it. Click on the map to fill the coordinates, or drag points of interest to move them.", "help": "Fill in the form to create a new point of interest, or click on an existing one to edit it. Click on the map to fill the coordinates, or drag points of interest to move them.",
@@ -204,15 +246,15 @@
}, },
"reduce": { "reduce": {
"tooltip": "Reduce the number of GPS points", "tooltip": "Reduce the number of GPS points",
"tolerance": "Tolerance", "tolerance": "Toleranz",
"number_of_points": "Number of GPS points", "number_of_points": "Anzahl der GPS-Punkte",
"button": "Minify", "button": "Minify",
"help": "Use the slider to choose the number of GPS points to keep.", "help": "Use the slider to choose the number of GPS points to keep.",
"help_no_selection": "Select a trace to reduce the number of its GPS points." "help_no_selection": "Select a trace to reduce the number of its GPS points."
}, },
"clean": { "clean": {
"tooltip": "Clean GPS points and points of interest with a rectangle selection", "tooltip": "Clean GPS points and points of interest with a rectangle selection",
"delete_trackpoints": "Delete GPS points", "delete_trackpoints": "GPS-Punkte löschen",
"delete_waypoints": "Delete points of interest", "delete_waypoints": "Delete points of interest",
"delete_inside": "Delete inside selection", "delete_inside": "Delete inside selection",
"delete_outside": "Delete outside selection", "delete_outside": "Delete outside selection",
@@ -243,19 +285,19 @@
"basemaps": "Basiskarte", "basemaps": "Basiskarte",
"overlays": "Ebenen", "overlays": "Ebenen",
"custom": "Custom", "custom": "Custom",
"world": "World", "world": "Welt",
"countries": "Countries", "countries": "Länder",
"belgium": "Belgium", "belgium": "Belgien",
"bulgaria": "Bulgarien", "bulgaria": "Bulgarien",
"finland": "Finland", "finland": "Finnland",
"france": "France", "france": "Frankreich",
"new_zealand": "New Zealand", "new_zealand": "Neuseeland",
"norway": "Norway", "norway": "Norwegen",
"spain": "Spain", "spain": "Spanien",
"sweden": "Sweden", "sweden": "Schweden",
"switzerland": "Switzerland", "switzerland": "Schweiz",
"united_kingdom": "United Kingdom", "united_kingdom": "Großbritannien",
"united_states": "United States", "united_states": "USA",
"mapboxOutdoors": "Mapbox Outdoors", "mapboxOutdoors": "Mapbox Outdoors",
"mapboxSatellite": "Mapbox Satellit", "mapboxSatellite": "Mapbox Satellit",
"openStreetMap": "OpenStreetMap", "openStreetMap": "OpenStreetMap",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -294,50 +337,50 @@
"ignSlope": "IGN Slope", "ignSlope": "IGN Slope",
"ignSkiTouring": "IGN Ski Touring", "ignSkiTouring": "IGN Ski Touring",
"waymarked_trails": "Waymarked Trails", "waymarked_trails": "Waymarked Trails",
"waymarkedTrailsHiking": "Hiking", "waymarkedTrailsHiking": "Wandern",
"waymarkedTrailsCycling": "Cycling", "waymarkedTrailsCycling": "Radfahren",
"waymarkedTrailsMTB": "MTB", "waymarkedTrailsMTB": "MTB",
"waymarkedTrailsSkating": "Skating", "waymarkedTrailsSkating": "Skating",
"waymarkedTrailsHorseRiding": "Horse Riding", "waymarkedTrailsHorseRiding": "Horse Riding",
"waymarkedTrailsWinter": "Winter", "waymarkedTrailsWinter": "Winter",
"points_of_interest": "Points of interest", "points_of_interest": "Points of interest",
"food": "Food", "food": "Food",
"bakery": "Bakery", "bakery": "Bäckerei",
"food-store": "Food Store", "food-store": "Food Store",
"eat-and-drink": "Eat and Drink", "eat-and-drink": "Eat and Drink",
"amenities": "Amenities", "amenities": "Amenities",
"toilets": "Toilets", "toilets": "Toiletten",
"water": "Water", "water": "Trinkwasser",
"shower": "Shower", "shower": "Dusche",
"shelter": "Shelter", "shelter": "Unterstand",
"motorized": "Cars and Motorcycles", "motorized": "Autos und Motorräder",
"fuel-station": "Fuel Station", "fuel-station": "Tankstelle",
"parking": "Parking", "parking": "Parking",
"garage": "Garage", "garage": "Garage",
"barrier": "Barrier", "barrier": "Barriere",
"tourism": "Tourism", "tourism": "Tourismus",
"attraction": "Attraction", "attraction": "Attraction",
"viewpoint": "Viewpoint", "viewpoint": "Aussichtspunkt",
"hotel": "Hotel", "hotel": "Hotel",
"campsite": "Campsite", "campsite": "Campingplatz",
"hut": "Hut", "hut": "Hütte",
"picnic": "Picnic Area", "picnic": "Picknickplatz",
"summit": "Summit", "summit": "Gipfel",
"pass": "Pass", "pass": "Gebirgspass",
"climbing": "Climbing", "climbing": "Climbing",
"bicycle": "Bicycle", "bicycle": "Fahrrad",
"bicycle-parking": "Bicycle Parking", "bicycle-parking": "Bicycle Parking",
"bicycle-rental": "Bicycle Rental", "bicycle-rental": "Fahrradverleih",
"bicycle-shop": "Fahrradgeschäft", "bicycle-shop": "Fahrradgeschäft",
"public-transport": "Öffentliche Verkehrsmittel", "public-transport": "Öffentliche Verkehrsmittel",
"railway-station": "Bahnhof", "railway-station": "Bahnhof",
"tram-stop": "Straßenbahnhaltestelle", "tram-stop": "Straßenbahnhaltestelle",
"bus-stop": "Bushaltestelle", "bus-stop": "Bushaltestelle",
"ferry": "Ferry" "ferry": "Fähre"
}, },
"color": { "color": {
"blue": "Blau", "blue": "Blau",
"bluered": "Blue Red", "bluered": "Blau Rot",
"gray": "Grau", "gray": "Grau",
"hot": "Heiß", "hot": "Heiß",
"purple": "Lila", "purple": "Lila",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distanz", "distance": "Distanz",
@@ -361,14 +397,16 @@
"temperature": "Temperatur", "temperature": "Temperatur",
"speed": "Geschwindigkeit", "speed": "Geschwindigkeit",
"pace": "Tempo", "pace": "Tempo",
"heartrate": "Heart rate", "heartrate": "Herzfrequenz",
"cadence": "Trittfrequenz", "cadence": "Trittfrequenz",
"power": "Leistung", "power": "Leistung",
"slope": "Gefälle", "slope": "Gefälle",
"surface": "Oberfläche", "surface": "Oberfläche",
"highway": "Category",
"time": "Zeit", "time": "Zeit",
"moving": "Moving", "moving": "Bewegung",
"total": "Gesamt" "total": "Gesamt",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",
@@ -389,8 +427,8 @@
"power": "W" "power": "W"
}, },
"gpx": { "gpx": {
"file": "File", "file": "Datei",
"files": "Files", "files": "Dateien",
"track": "Strecke", "track": "Strecke",
"tracks": "Strecken", "tracks": "Strecken",
"segment": "Abschnitt", "segment": "Abschnitt",
@@ -401,56 +439,56 @@
"alert": "Alert", "alert": "Alert",
"anchor": "Anchor", "anchor": "Anchor",
"bank": "Bank", "bank": "Bank",
"beach": "Beach", "beach": "Strand",
"bike_trail": "Bike Trail", "bike_trail": "Bike Trail",
"binoculars": "Binoculars", "binoculars": "Binoculars",
"bridge": "Bridge", "bridge": "Brücke",
"building": "Building", "building": "Gebäude",
"campground": "Campsite", "campground": "Campingplatz",
"car": "Car", "car": "Auto",
"car_repair": "Garage", "car_repair": "Garage",
"convenience_store": "Convenience Store", "convenience_store": "Convenience Store",
"crossing": "Crossing", "crossing": "Crossing",
"department_store": "Department Store", "department_store": "Department Store",
"drinking_water": "Water", "drinking_water": "Trinkwasser",
"exit": "Exit", "exit": "Exit",
"lodge": "Hut", "lodge": "Hut",
"lodging": "Accommodation", "lodging": "Accommodation",
"forest": "Forest", "forest": "Wald",
"gas_station": "Fuel Station", "gas_station": "Tankstelle",
"ground_transportation": "Ground Transportation", "ground_transportation": "Ground Transportation",
"hotel": "Hotel", "hotel": "Hotel",
"house": "House", "house": "House",
"information": "Information", "information": "Information",
"park": "Park", "park": "Park",
"parking_area": "Parking", "parking_area": "Parkplatz",
"pharmacy": "Pharmacy", "pharmacy": "Apotheke",
"picnic_area": "Picnic Area", "picnic_area": "Picknickplatz",
"restaurant": "Restaurant", "restaurant": "Restaurant",
"restricted_area": "Restricted Area", "restricted_area": "Restricted Area",
"restroom": "Toilets", "restroom": "Toiletten",
"road": "Road", "road": "Straße",
"scenic_area": "Scenic Area", "scenic_area": "Scenic Area",
"shelter": "Shelter", "shelter": "Unterstand",
"shopping_center": "Shopping Center", "shopping_center": "Einkaufszentrum",
"shower": "Shower", "shower": "Dusche",
"summit": "Summit", "summit": "Gipfel",
"telephone": "Telephone", "telephone": "Telefon",
"tunnel": "Tunnel", "tunnel": "Tunnel",
"water_source": "Water Source" "water_source": "Water Source"
} }
}, },
"homepage": { "homepage": {
"website": "Website", "website": "Webseite",
"home": "Home", "home": "Home",
"app": "App", "app": "App",
"contact": "Contact", "contact": "Kontakt",
"reddit": "Reddit", "reddit": "Reddit",
"x": "X", "x": "X",
"facebook": "Facebook", "facebook": "Facebook",
"github": "GitHub", "github": "GitHub",
"crowdin": "Crowdin", "crowdin": "Crowdin",
"email": "Email", "email": "E-Mail",
"contribute": "Contribute", "contribute": "Contribute",
"supported_by": "supported by", "supported_by": "supported by",
"support_button": "Support gpx.studio on Ko-fi", "support_button": "Support gpx.studio on Ko-fi",
@@ -466,19 +504,19 @@
"identity_description": "The website is free to use, without ads, and the source code is publicly available on GitHub. This is only possible thanks to the incredible support of the community." "identity_description": "The website is free to use, without ads, and the source code is publicly available on GitHub. This is only possible thanks to the incredible support of the community."
}, },
"docs": { "docs": {
"translate": "Improve the translation on Crowdin", "translate": "Verbessere die Übersetzung auf Crowdin",
"answer_not_found": "Did not find what you were looking for?", "answer_not_found": "Did not find what you were looking for?",
"ask_on_reddit": "Ask the community on Reddit", "ask_on_reddit": "Frage die Community auf Reddit",
"search": { "search": {
"search": "Search", "search": "Suche",
"clear": "Clear", "clear": "Clear",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"recent": "Recent searches", "recent": "Letzte Suchanfragen",
"no_recent": "No recent searches", "no_recent": "Keine kürzlichen Suchanfragen",
"save": "Save this search", "save": "Diese Suchanfrage speichern",
"remove": "Remove this search from history", "remove": "Diese Suchanfrage aus dem Verlauf entfernen",
"favorites": "Favorites", "favorites": "Favoriten",
"remove_favorite": "Remove this search from favorites", "remove_favorite": "Diese Suchanfrage aus Favoriten entfernen",
"to_select": "to select", "to_select": "to select",
"to_navigate": "to navigate", "to_navigate": "to navigate",
"to_close": "to close", "to_close": "to close",
@@ -506,7 +544,7 @@
"preview": "Vorschau", "preview": "Vorschau",
"code": "Integration code" "code": "Integration code"
}, },
"webgl2_required": "WebGL 2 is required to display the map.", "webgl2_required": "WebGL 2 ist erforderlich, um die Karte anzuzeigen.",
"enable_webgl2": "Learn how to enable WebGL 2 in your browser", "enable_webgl2": "Erfahren Sie, wie Sie WebGL 2 in Ihrem Browser aktivieren",
"page_not_found": "page not found" "page_not_found": "Seite nicht gefunden"
} }

View File

@@ -119,11 +119,8 @@
"unpaved": "Μη ασφαλτοστρωμένο", "unpaved": "Μη ασφαλτοστρωμένο",
"asphalt": "Άσφαλτος", "asphalt": "Άσφαλτος",
"concrete": "Τσιμέντο", "concrete": "Τσιμέντο",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Μέταλλο", "metal": "Μέταλλο",
"wood": "Ξύλο", "wood": "Ξύλο",
@@ -135,15 +132,59 @@
"dirt": "Βρωμιά", "dirt": "Βρωμιά",
"ground": "Χώμα", "ground": "Χώμα",
"earth": "Γη", "earth": "Γη",
"snow": "Χιόνι",
"ice": "Πάγος",
"salt": "Αλάτι",
"mud": "Λάσπη", "mud": "Λάσπη",
"sand": "Άμμος", "sand": "Άμμος",
"woodchips": "Woodchips",
"grass": "Γρασίδι", "grass": "Γρασίδι",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Απόσταση", "distance": "Απόσταση",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Πλαγιά", "slope": "Πλαγιά",
"surface": "Επιφάνεια", "surface": "Επιφάνεια",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Σύνολο" "total": "Σύνολο",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "μέτρα", "meters": "μέτρα",

View File

@@ -88,6 +88,8 @@
"use_routing": "Routing", "use_routing": "Routing",
"use_routing_tooltip": "Connect anchor points via road network, or in a straight line if disabled", "use_routing_tooltip": "Connect anchor points via road network, or in a straight line if disabled",
"allow_private": "Allow private roads", "allow_private": "Allow private roads",
"preserve_average_speed": "Maintain average speed",
"preserve_timestamps": "Adjust timestamps to fill gaps",
"reverse": { "reverse": {
"button": "Reverse", "button": "Reverse",
"tooltip": "Reverse the direction of the route" "tooltip": "Reverse the direction of the route"
@@ -119,11 +121,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Wood", "wood": "Wood",
@@ -135,15 +134,59 @@
"dirt": "Dirt", "dirt": "Dirt",
"ground": "Ground", "ground": "Ground",
"earth": "Earth", "earth": "Earth",
"snow": "Snow",
"ice": "Ice",
"salt": "Salt",
"mud": "Mud", "mud": "Mud",
"sand": "Sand", "sand": "Sand",
"woodchips": "Woodchips",
"grass": "Grass", "grass": "Grass",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +216,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +316,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +390,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +404,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Sin pavimento", "unpaved": "Sin pavimento",
"asphalt": "Asfalto", "asphalt": "Asfalto",
"concrete": "Hormigón", "concrete": "Hormigón",
"chipseal": "Pavimento delgado",
"cobblestone": "Adoquinado", "cobblestone": "Adoquinado",
"unhewn_cobblestone": "Adoquín sin labrar",
"paving_stones": "Adoquines", "paving_stones": "Adoquines",
"stepping_stones": "Peldaños",
"sett": "Adoquín", "sett": "Adoquín",
"metal": "Metal", "metal": "Metal",
"wood": "Madera", "wood": "Madera",
@@ -135,15 +132,59 @@
"dirt": "Tierra", "dirt": "Tierra",
"ground": "Tierra", "ground": "Tierra",
"earth": "Tierra natural", "earth": "Tierra natural",
"snow": "Nevado",
"ice": "Helado",
"salt": "Salado",
"mud": "Barro", "mud": "Barro",
"sand": "Arena", "sand": "Arena",
"woodchips": "Virutas de madera",
"grass": "Hierba", "grass": "Hierba",
"grass_paver": "Pavimento con césped" "grass_paver": "Pavimento con césped",
"clay": "Arcilla",
"stone": "Piedra"
}, },
"highway": {
"unknown": "Desconocido",
"motorway": "Autopista",
"motorway_link": "Enlace de autopista",
"trunk": "Carretera principal",
"trunk_link": "Enlace de carretera principal",
"primary": "Carretera principal",
"primary_link": "Enlace de carretera principal",
"secondary": "Carretera secundaria",
"secondary_link": "Enlace de carretera secundaria",
"tertiary": "Carretera terciaria",
"tertiary_link": "Enlace de carretera terciaria",
"unclassified": "Carretera menor",
"residential": "Vía residencial",
"living_street": "Calle residencial",
"service": "Vía de servicio",
"track": "Pista",
"footway": "Passarela",
"path": "Ruta",
"pedestrian": "Peatón",
"cycleway": "Ciclovia",
"steps": "Pasos",
"road": "Carretera",
"bridleway": "Ruta ecuestre",
"platform": "Plataforma",
"raceway": "Circuito de carreras",
"rest_area": "Área de descanso",
"abandoned": "Abandonado",
"services": "Servicios",
"corridor": "Pasillo",
"bus_stop": "Parada de autobús",
"busway": "Carril bus",
"elevator": "Ascensor",
"via_ferrata": "Vía ferrata",
"proposed": "Carretera por construir",
"construction": "Carretera en construcción"
},
"sac_scale": {
"hiking": "Senderismo",
"mountain_hiking": "Senderismo de montaña",
"demanding_mountain_hiking": "Senderismo de montaña exigente",
"alpine_hiking": "Senderismo alpino",
"demanding_alpine_hiking": "Senderismo alpino exigente",
"difficult_alpine_hiking": "Senderismo alpino difícil"
},
"mtb_scale": "Escala MTB",
"error": { "error": {
"from": "El punto de inicio está demasiado lejos de la carretera más cercana", "from": "El punto de inicio está demasiado lejos de la carretera más cercana",
"via": "El punto de paso está demasiado lejos de la carretera más cercana", "via": "El punto de paso está demasiado lejos de la carretera más cercana",
@@ -173,6 +214,7 @@
"merge_traces": "Conectar los trazados", "merge_traces": "Conectar los trazados",
"merge_contents": "Combinar los contenidos y mantener los trazados desconectados", "merge_contents": "Combinar los contenidos y mantener los trazados desconectados",
"merge_selection": "Combinar selección", "merge_selection": "Combinar selección",
"remove_gaps": "Eliminar intervalos vacíos de tiempo entre trazas",
"tooltip": "Combinar elementos", "tooltip": "Combinar elementos",
"help_merge_traces": "Conectar los trazados seleccionados creará un único trazado continuo.", "help_merge_traces": "Conectar los trazados seleccionados creará un único trazado continuo.",
"help_cannot_merge_traces": "Su selección debe contener varios trazados para conectarlos.", "help_cannot_merge_traces": "Su selección debe contener varios trazados para conectarlos.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satélite", "ignFrSatellite": "IGN Satélite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satélite",
"ordnanceSurvey": "Encuesta Ordnance", "ordnanceSurvey": "Encuesta Ordnance",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Mostrar datos de pendiente", "settings": "Configuración del perfil de elevación"
"show_surface": "Mostrar datos de superficie",
"show_speed": "Mostrar datos de velocidad",
"show_pace": "Mostrar datos de ritmo",
"show_heartrate": "Mostrar datos de ritmo cardíaco",
"show_cadence": "Mostrar datos de cadencia",
"show_temperature": "Mostrar datos de temperatura",
"show_power": "Mostrar datos de potencia"
}, },
"quantities": { "quantities": {
"distance": "Distancia", "distance": "Distancia",
@@ -366,9 +402,11 @@
"power": "Potencia", "power": "Potencia",
"slope": "Pendiente", "slope": "Pendiente",
"surface": "Superficie", "surface": "Superficie",
"highway": "Categoría",
"time": "Tiempo", "time": "Tiempo",
"moving": "Movimiento", "moving": "Movimiento",
"total": "Total" "total": "Total",
"osm_extensions": "Datos OpenStreetMap"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Päällystämätön", "unpaved": "Päällystämätön",
"asphalt": "Asfaltti", "asphalt": "Asfaltti",
"concrete": "Betoni", "concrete": "Betoni",
"chipseal": "Öljysora",
"cobblestone": "Mukulakivi", "cobblestone": "Mukulakivi",
"unhewn_cobblestone": "Luonnonmukainen mukulakivi",
"paving_stones": "Katukivetys", "paving_stones": "Katukivetys",
"stepping_stones": "Astinkivet",
"sett": "Kivetys", "sett": "Kivetys",
"metal": "Metalli", "metal": "Metalli",
"wood": "Puu", "wood": "Puu",
@@ -135,15 +132,59 @@
"dirt": "Maa", "dirt": "Maa",
"ground": "Maa", "ground": "Maa",
"earth": "Maa", "earth": "Maa",
"snow": "Lumi",
"ice": "Jää",
"salt": "Suola",
"mud": "Muta", "mud": "Muta",
"sand": "Hiekka", "sand": "Hiekka",
"woodchips": "Hake",
"grass": "Nurmi", "grass": "Nurmi",
"grass_paver": "Nurmikivi" "grass_paver": "Nurmikivi",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "Aloituspiste on liian kaukana lähimmästä tiestä", "from": "Aloituspiste on liian kaukana lähimmästä tiestä",
"via": "Reittipiste on liian kaukana lähimmästä tiestä", "via": "Reittipiste on liian kaukana lähimmästä tiestä",
@@ -173,6 +214,7 @@
"merge_traces": "Yhdistä reitit", "merge_traces": "Yhdistä reitit",
"merge_contents": "Yhdistä reitit samaan tiedostoon", "merge_contents": "Yhdistä reitit samaan tiedostoon",
"merge_selection": "Yhdistä valitut", "merge_selection": "Yhdistä valitut",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Yhdistä tiedostot", "tooltip": "Yhdistä tiedostot",
"help_merge_traces": "Yhdistäminen luo valituista reiteistä yhden yhtenäisen reitin.", "help_merge_traces": "Yhdistäminen luo valituista reiteistä yhden yhtenäisen reitin.",
"help_cannot_merge_traces": "Valitse useampia reittejä yhdistääksesi ne.", "help_cannot_merge_traces": "Valitse useampia reittejä yhdistääksesi ne.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Maastokartta", "ignFrTopo": "IGN Maastokartta",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Ilmakuva", "ignFrSatellite": "IGN Ilmakuva",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Maastokartta", "swedenTopo": "Lantmäteriet Maastokartta",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Näytä syketiedot",
"show_cadence": "Show cadence data",
"show_temperature": "Näytä lämpötilatiedot",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Kaltevuus", "slope": "Kaltevuus",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Sans revêtement", "unpaved": "Sans revêtement",
"asphalt": "Asphalte", "asphalt": "Asphalte",
"concrete": "Béton", "concrete": "Béton",
"chipseal": "Enduit superficiel routier",
"cobblestone": "Pavés", "cobblestone": "Pavés",
"unhewn_cobblestone": "Pavé non taillé",
"paving_stones": "Pavage en pierres", "paving_stones": "Pavage en pierres",
"stepping_stones": "Pierres de gué",
"sett": "Pavés", "sett": "Pavés",
"metal": "Métal", "metal": "Métal",
"wood": "Bois", "wood": "Bois",
@@ -135,15 +132,59 @@
"dirt": "Sol en érosion", "dirt": "Sol en érosion",
"ground": "Sol", "ground": "Sol",
"earth": "Terre", "earth": "Terre",
"snow": "Neige",
"ice": "Glace",
"salt": "Sel",
"mud": "Boue", "mud": "Boue",
"sand": "Sable", "sand": "Sable",
"woodchips": "Plaquette forestière",
"grass": "Herbe", "grass": "Herbe",
"grass_paver": "Mélange d'herbe et de pavés" "grass_paver": "Mélange d'herbe et de pavés",
"clay": "Argile",
"stone": "Pierre"
}, },
"highway": {
"unknown": "Inconnu",
"motorway": "Autoroute",
"motorway_link": "Bretelle d'autoroute",
"trunk": "Route principale",
"trunk_link": "Liaison de route principale",
"primary": "Route principale",
"primary_link": "Liaison de route principale",
"secondary": "Route secondaire",
"secondary_link": "Liaison de route secondaire",
"tertiary": "Route tertiaire",
"tertiary_link": "Liaison de route tertiaire",
"unclassified": "Route mineure",
"residential": "Route résidentielle",
"living_street": "Rue résidentielle",
"service": "Route de service",
"track": "Chemin",
"footway": "Chemin piéton",
"path": "Chemin",
"pedestrian": "Piéton",
"cycleway": "Voie cyclable",
"steps": "Marches",
"road": "Route",
"bridleway": "Chemin d'équitation",
"platform": "Quai",
"raceway": "Circuit de course",
"rest_area": "Aire de repos",
"abandoned": "Abandonné",
"services": "Services",
"corridor": "Couloir",
"bus_stop": "Arrêt de bus",
"busway": "Réservé bus",
"elevator": "Ascenseur",
"via_ferrata": "Via ferrata",
"proposed": "Route à construire",
"construction": "Route en construction"
},
"sac_scale": {
"hiking": "Randonnée",
"mountain_hiking": "Randonnée de montagne",
"demanding_mountain_hiking": "Randonnée de montagne exigeante",
"alpine_hiking": "Randonnée alpine",
"demanding_alpine_hiking": "Randonnée alpine exigeante",
"difficult_alpine_hiking": "Randonnée alpine difficile"
},
"mtb_scale": "Échelle VTT",
"error": { "error": {
"from": "Le point de départ est trop éloigné de la route la plus proche", "from": "Le point de départ est trop éloigné de la route la plus proche",
"via": "Le point de passage est trop éloigné de la route la plus proche", "via": "Le point de passage est trop éloigné de la route la plus proche",
@@ -173,6 +214,7 @@
"merge_traces": "Connecter les traces", "merge_traces": "Connecter les traces",
"merge_contents": "Fusionner les contenus et garder les traces déconnectées", "merge_contents": "Fusionner les contenus et garder les traces déconnectées",
"merge_selection": "Fusionner la sélection", "merge_selection": "Fusionner la sélection",
"remove_gaps": "Supprimer les écarts de temps entre les traces",
"tooltip": "Fusionner les éléments", "tooltip": "Fusionner les éléments",
"help_merge_traces": "Connecter les traces sélectionnées créera une seule trace continue.", "help_merge_traces": "Connecter les traces sélectionnées créera une seule trace continue.",
"help_cannot_merge_traces": "Votre sélection doit contenir plusieurs traces pour pouvoir les connecter.", "help_cannot_merge_traces": "Votre sélection doit contenir plusieurs traces pour pouvoir les connecter.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Afficher les données de pente", "settings": "Réglages du profil altimétrique"
"show_surface": "Afficher les données de surface",
"show_speed": "Afficher les données de vitesse",
"show_pace": "Afficher les données d'allure",
"show_heartrate": "Afficher les données de fréquence cardiaque",
"show_cadence": "Afficher les données de cadence",
"show_temperature": "Afficher les données de température",
"show_power": "Afficher les données de puissance"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -365,10 +401,12 @@
"cadence": "Cadence", "cadence": "Cadence",
"power": "Puissance", "power": "Puissance",
"slope": "Pente", "slope": "Pente",
"surface": "Surface", "surface": "Revêtement",
"highway": "Catégorie",
"time": "Temps", "time": "Temps",
"moving": "En mouvement", "moving": "En mouvement",
"total": "Total" "total": "Total",
"osm_extensions": "Données d'OpenStreetMap"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Wood", "wood": "Wood",
@@ -135,15 +132,59 @@
"dirt": "Dirt", "dirt": "Dirt",
"ground": "Ground", "ground": "Ground",
"earth": "Earth", "earth": "Earth",
"snow": "Snow",
"ice": "Ice",
"salt": "Salt",
"mud": "Mud", "mud": "Mud",
"sand": "Sand", "sand": "Sand",
"woodchips": "Woodchips",
"grass": "Grass", "grass": "Grass",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -5,7 +5,7 @@
"embed_title": "az online GPX szerkesztő", "embed_title": "az online GPX szerkesztő",
"help_title": "súgó", "help_title": "súgó",
"404_title": "az oldal nem található", "404_title": "az oldal nem található",
"description": "GPX-fájlok online megtekintése, szerkesztése és létrehozása fejlett útvonaltervezési képességekkel és fájlfeldolgozó eszközökkel, gyönyörű térképekkel és részletes adatmegjelenítésekkel." "description": "GPX fájlok online megtekintése, szerkesztése és létrehozása fejlett útvonal tervezési képességekkel és fájlfeldolgozó eszközökkel, gyönyörű térképekkel és részletes adatmegjelenítésekkel."
}, },
"menu": { "menu": {
"new": "Új", "new": "Új",
@@ -33,7 +33,7 @@
"select_all": "Összes kijelölése", "select_all": "Összes kijelölése",
"view": "Nézet", "view": "Nézet",
"elevation_profile": "Magassági profil", "elevation_profile": "Magassági profil",
"vertical_file_view": "Függoleges fájl lista", "vertical_file_view": "Függőleges fájl lista",
"switch_basemap": "Váltás az előző alaptérképre", "switch_basemap": "Váltás az előző alaptérképre",
"toggle_overlays": "Átfedés váltása", "toggle_overlays": "Átfedés váltása",
"toggle_3d": "3D nézet bekapcsolása", "toggle_3d": "3D nézet bekapcsolása",
@@ -54,7 +54,7 @@
"street_view_source": "Utcakép nézet forrása", "street_view_source": "Utcakép nézet forrása",
"mapillary": "Mapillary", "mapillary": "Mapillary",
"google": "Google", "google": "Google",
"toggle_street_view": "Street view", "toggle_street_view": "Utcakép nézet",
"layers": "Térképrétegek...", "layers": "Térképrétegek...",
"distance_markers": "Távolsági km szakaszok mutatása", "distance_markers": "Távolsági km szakaszok mutatása",
"direction_markers": "Menetirány mutatása", "direction_markers": "Menetirány mutatása",
@@ -86,11 +86,11 @@
"tooltip": "Útvonal tervezése vagy szerkesztése", "tooltip": "Útvonal tervezése vagy szerkesztése",
"activity": "Tevékenység", "activity": "Tevékenység",
"use_routing": "Útvonal választása", "use_routing": "Útvonal választása",
"use_routing_tooltip": "Útvonal követés kikapcsolava egyenes vonal rajzolása", "use_routing_tooltip": "Útvonal követés kikapcsolva egyenes vonal rajzolása",
"allow_private": "Magánutak engedélyezése", "allow_private": "Magánutak engedélyezése",
"reverse": { "reverse": {
"button": "Út menetirány váltás", "button": "Út menetirány váltás",
"tooltip": "Útvonal irányát megfordítása" "tooltip": "Útvonal irányának megfordítása"
}, },
"route_back_to_start": { "route_back_to_start": {
"button": "Vissza a starthoz", "button": "Vissza a starthoz",
@@ -119,11 +119,8 @@
"unpaved": "Földes", "unpaved": "Földes",
"asphalt": "Aszfalt", "asphalt": "Aszfalt",
"concrete": "Beton", "concrete": "Beton",
"chipseal": "Törmelékes",
"cobblestone": "Macskaköves", "cobblestone": "Macskaköves",
"unhewn_cobblestone": "Vágatlan nagy kavics",
"paving_stones": "Térkő", "paving_stones": "Térkő",
"stepping_stones": "Szikla lépcső",
"sett": "Kőlap", "sett": "Kőlap",
"metal": "Fém", "metal": "Fém",
"wood": "Fa", "wood": "Fa",
@@ -135,15 +132,59 @@
"dirt": "Piszok", "dirt": "Piszok",
"ground": "Föld", "ground": "Föld",
"earth": "Föld", "earth": "Föld",
"snow": "Hó",
"ice": "Jég",
"salt": "Só",
"mud": "Sár", "mud": "Sár",
"sand": "Homok", "sand": "Homok",
"woodchips": "Faforgács",
"grass": "Fű", "grass": "Fű",
"grass_paver": "Gyephézagos térkő" "grass_paver": "Gyephézagos térkő",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "A kiindulási pont túl messze van a legközelebbi úttól", "from": "A kiindulási pont túl messze van a legközelebbi úttól",
"via": "A köztes pont túl messze van a legközelebbi úttól", "via": "A köztes pont túl messze van a legközelebbi úttól",
@@ -159,20 +200,21 @@
"help": "Használja a csúszkát az útvonal kivágásához, vagy ossza fel az egyik jelölőre vagy magára az útvonalra kattintva." "help": "Használja a csúszkát az útvonal kivágásához, vagy ossza fel az egyik jelölőre vagy magára az útvonalra kattintva."
}, },
"time": { "time": {
"tooltip": "Manage time data", "tooltip": "Idő beállítása",
"start": "Rajt", "start": "Rajt",
"end": "End", "end": "Befejezés",
"total_time": "Mozgási idő", "total_time": "Mozgási idő",
"pick_date": "Pick a date", "pick_date": "Válassz dátumot",
"artificial": "Create realistic time data", "artificial": "Valósághű időadatok hozzáadása",
"update": "Update time data", "update": "Használd a formot új idő beállításához.",
"help": "Use the form to set new time data.", "help": "Használd a form-ot az új idő beállításához.",
"help_invalid_selection": "Select a single trace to manage its time data." "help_invalid_selection": "Válasszon ki egyetlen nyomvonalat az időadatainak kezeléséhez."
}, },
"merge": { "merge": {
"merge_traces": "Connect the traces", "merge_traces": "Kösd össze az útvonalakat",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Egyesítés kijelőlés", "merge_selection": "Egyesítés kijelölés",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -184,10 +226,10 @@
"tooltip": "Extract contents to separate items", "tooltip": "Extract contents to separate items",
"button": "Extract", "button": "Extract",
"help": "Extracting the contents of the selected items will create a separate item for each of their contents.", "help": "Extracting the contents of the selected items will create a separate item for each of their contents.",
"help_invalid_selection": "Your selection must contain items with multiple traces to extract them." "help_invalid_selection": "Több nyomvonalat kell tartalmazzon a kijelölés a kinyeréshez."
}, },
"elevation": { "elevation": {
"button": "Request elevation data", "button": "Magassági információk lekérése",
"help": "Requesting elevation data will erase the existing elevation data, if any, and replace it with data from Mapbox.", "help": "Requesting elevation data will erase the existing elevation data, if any, and replace it with data from Mapbox.",
"help_no_selection": "Select a file item to request elevation data." "help_no_selection": "Select a file item to request elevation data."
}, },
@@ -196,23 +238,23 @@
"icon": "Icon", "icon": "Icon",
"link": "Link", "link": "Link",
"longitude": "Longitude", "longitude": "Longitude",
"latitude": "Latitude", "latitude": "Szélesség",
"create": "Create point of interest", "create": "POI fájlba mentése",
"add": "Add point of interest to file", "add": "Add point of interest to file",
"help": "Fill in the form to create a new point of interest, or click on an existing one to edit it. Click on the map to fill the coordinates, or drag points of interest to move them.", "help": "Töltsd ki az űrlapot egy új POI létrehozásához, vagy kattints egy meglévőre a szerkesztéshez. Kattints a térképre a koordináták megadásához, vagy áthelyezéshez egérrel húzd el a POI-kat.",
"help_no_selection": "Select a file to create or edit points of interest." "help_no_selection": "Select a file to create or edit points of interest."
}, },
"reduce": { "reduce": {
"tooltip": "Reduce the number of GPS points", "tooltip": "Reduce the number of GPS points",
"tolerance": "Tolerance", "tolerance": "Tűréshatár",
"number_of_points": "Number of GPS points", "number_of_points": "GPS pontok száma",
"button": "Minify", "button": "Minify",
"help": "Use the slider to choose the number of GPS points to keep.", "help": "Use the slider to choose the number of GPS points to keep.",
"help_no_selection": "Select a trace to reduce the number of its GPS points." "help_no_selection": "Select a trace to reduce the number of its GPS points."
}, },
"clean": { "clean": {
"tooltip": "Clean GPS points and points of interest with a rectangle selection", "tooltip": "Clean GPS points and points of interest with a rectangle selection",
"delete_trackpoints": "Delete GPS points", "delete_trackpoints": "GPS pontok törlése",
"delete_waypoints": "Delete points of interest", "delete_waypoints": "Delete points of interest",
"delete_inside": "Delete inside selection", "delete_inside": "Delete inside selection",
"delete_outside": "Delete outside selection", "delete_outside": "Delete outside selection",
@@ -222,14 +264,14 @@
} }
}, },
"layers": { "layers": {
"settings": "Layer settings", "settings": "Réteg beállítások",
"settings_help": "Select the map layers you want to show in the interface, add custom ones, and adjust their settings.", "settings_help": "Select the map layers you want to show in the interface, add custom ones, and adjust their settings.",
"selection": "Layer selection", "selection": "Layer selection",
"custom_layers": { "custom_layers": {
"title": "Custom layers", "title": "Custom layers",
"new": "New custom layer", "new": "New custom layer",
"edit": "Edit custom layer", "edit": "Edit custom layer",
"urls": "URL(s)", "urls": "Webcím(ek)",
"url_placeholder": "WMTS, WMS vagy Mapbox stílus JSON", "url_placeholder": "WMTS, WMS vagy Mapbox stílus JSON",
"max_zoom": "Max nagyítás", "max_zoom": "Max nagyítás",
"layer_type": "Réteg típus", "layer_type": "Réteg típus",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Műhold", "ignFrSatellite": "IGN Műhold",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Hadifelmérés", "ordnanceSurvey": "Hadifelmérés",
"norwayTopo": "Norvégia topográfiai térképe 4", "norwayTopo": "Norvégia topográfiai térképe 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -321,8 +364,8 @@
"hotel": "Hotel", "hotel": "Hotel",
"campsite": "Kemping", "campsite": "Kemping",
"hut": "Hut", "hut": "Hut",
"picnic": "Picnic Area", "picnic": "Piknikező hely",
"summit": "Summit", "summit": "Csúcs",
"pass": "Pass", "pass": "Pass",
"climbing": "Climbing", "climbing": "Climbing",
"bicycle": "Kerékpár", "bicycle": "Kerékpár",
@@ -333,7 +376,7 @@
"railway-station": "Vasútállomás", "railway-station": "Vasútállomás",
"tram-stop": "Villamos megálló", "tram-stop": "Villamos megálló",
"bus-stop": "Buszmegálló", "bus-stop": "Buszmegálló",
"ferry": "Ferry" "ferry": "Komp"
}, },
"color": { "color": {
"blue": "Kék", "blue": "Kék",
@@ -341,18 +384,11 @@
"gray": "Szürke", "gray": "Szürke",
"hot": "Legérdekesebb", "hot": "Legérdekesebb",
"purple": "Lila", "purple": "Lila",
"orange": "Orange" "orange": "Narancssárga"
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Távolság", "distance": "Távolság",
@@ -366,9 +402,11 @@
"power": "Erő", "power": "Erő",
"slope": "Erőkifejtési szintkép színekkel", "slope": "Erőkifejtési szintkép színekkel",
"surface": "Szintkép", "surface": "Szintkép",
"highway": "Category",
"time": "Idő", "time": "Idő",
"moving": "Moving", "moving": "Moving",
"total": "Összes" "total": "Összes",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",
@@ -383,7 +421,7 @@
"minutes_per_kilometer": "min/km", "minutes_per_kilometer": "min/km",
"minutes_per_mile": "min/mi", "minutes_per_mile": "min/mi",
"minutes_per_nautical_mile": "min/nm", "minutes_per_nautical_mile": "min/nm",
"knots": "kn", "knots": "csomó",
"heartrate": "bpm", "heartrate": "bpm",
"cadence": "rpm", "cadence": "rpm",
"power": "W" "power": "W"
@@ -499,14 +537,14 @@
"manual_camera": "Manual camera", "manual_camera": "Manual camera",
"manual_camera_description": "You can move the map below to adjust the camera position.", "manual_camera_description": "You can move the map below to adjust the camera position.",
"latitude": "Latitude", "latitude": "Latitude",
"longitude": "Longitude", "longitude": "Hosszúság",
"zoom": "Zoom", "zoom": "Zoom",
"pitch": "Pitch", "pitch": "Dőlésszög",
"bearing": "Bearing", "bearing": "Irányszög",
"preview": "Előnézet", "preview": "Előnézet",
"code": "Integration code" "code": "Integration code"
}, },
"webgl2_required": "WebGL 2 is required to display the map.", "webgl2_required": "A térkép megjelenítéséhez WebGL 2 szükséges. ",
"enable_webgl2": "Learn how to enable WebGL 2 in your browser", "enable_webgl2": "Learn how to enable WebGL 2 in your browser",
"page_not_found": "page not found" "page_not_found": "page not found"
} }

View File

@@ -119,11 +119,8 @@
"unpaved": "Non asfaltato", "unpaved": "Non asfaltato",
"asphalt": "Asfalto", "asphalt": "Asfalto",
"concrete": "Calcestruzzo", "concrete": "Calcestruzzo",
"chipseal": "Chipseal",
"cobblestone": "Acciottolato", "cobblestone": "Acciottolato",
"unhewn_cobblestone": "Ciottolame",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Pavé", "sett": "Pavé",
"metal": "Metallo", "metal": "Metallo",
"wood": "Legno", "wood": "Legno",
@@ -135,15 +132,59 @@
"dirt": "Terra", "dirt": "Terra",
"ground": "Terreno", "ground": "Terreno",
"earth": "Terra", "earth": "Terra",
"snow": "Neve",
"ice": "Ghiaccio",
"salt": "Sale",
"mud": "Fango", "mud": "Fango",
"sand": "Sabbia", "sand": "Sabbia",
"woodchips": "Cippato",
"grass": "Erba", "grass": "Erba",
"grass_paver": "Pavimentazione erbosa" "grass_paver": "Pavimentazione erbosa",
"clay": "Argilla",
"stone": "Pietra"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "Il punto di partenza è troppo lontano dalla strada più vicina", "from": "Il punto di partenza è troppo lontano dalla strada più vicina",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,12 +214,13 @@
"merge_traces": "Collega le tracce", "merge_traces": "Collega le tracce",
"merge_contents": "Unisci i contenuti e mantieni le tracce disconnesse", "merge_contents": "Unisci i contenuti e mantieni le tracce disconnesse",
"merge_selection": "Selezione unione", "merge_selection": "Selezione unione",
"remove_gaps": "Rimuovere le differenze di tempo tra le tracce",
"tooltip": "Unisci gli elementi insieme", "tooltip": "Unisci gli elementi insieme",
"help_merge_traces": "Collegando le tracce selezionate si creerà una singola traccia continua.", "help_merge_traces": "Collegando le tracce selezionate si creerà una singola traccia continua.",
"help_cannot_merge_traces": "La tua selezione deve contenere diverse tracce per collegarle.", "help_cannot_merge_traces": "La tua selezione deve contenere diverse tracce per collegarle.",
"help_merge_contents": "Unendo il contenuto degli elementi selezionati si raggrupperà tutti i contenuti all'interno del primo elemento.", "help_merge_contents": "Unendo il contenuto degli elementi selezionati si raggrupperà tutti i contenuti all'interno del primo elemento.",
"help_cannot_merge_contents": "La selezione deve contenere diversi elementi per unire il loro contenuto.", "help_cannot_merge_contents": "La selezione deve contenere diversi elementi per unire il loro contenuto.",
"selection_tip": "Tip: use {KEYBOARD_SHORTCUT} to add items to the selection." "selection_tip": "Suggerimento: usa {KEYBOARD_SHORTCUT} per aggiungere elementi alla selezione."
}, },
"extract": { "extract": {
"tooltip": "Estrae i contenuti per separare gli elementi", "tooltip": "Estrae i contenuti per separare gli elementi",
@@ -188,8 +230,8 @@
}, },
"elevation": { "elevation": {
"button": "Richiedi dati elevazione", "button": "Richiedi dati elevazione",
"help": "Requesting elevation data will erase the existing elevation data, if any, and replace it with data from Mapbox.", "help": "Richiedere dati di altitudine cancellerà i dati di altitudine attuali, se presenti, e li rimpiazzerà con quelli provenienti da Mapbox.",
"help_no_selection": "Select a file item to request elevation data." "help_no_selection": "Seleziona un file per richiedere i dati di altitudine."
}, },
"waypoint": { "waypoint": {
"tooltip": "Crea e modifica punti di interesse", "tooltip": "Crea e modifica punti di interesse",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "Satellitare IGN", "ignFrSatellite": "Satellitare IGN",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Sondaggio Ordnance", "ordnanceSurvey": "Sondaggio Ordnance",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Mostra dati pendenza", "settings": "Elevation profile settings"
"show_surface": "Mostra dati di superficie",
"show_speed": "Mostra dati velocità",
"show_pace": "Mostra i dati del ritmo",
"show_heartrate": "Mostra i dati della frequenza cardiaca",
"show_cadence": "Mostra i dati di cadenza",
"show_temperature": "Mostra dati di temperatura",
"show_power": "Mostra dati di potenza"
}, },
"quantities": { "quantities": {
"distance": "Distanza", "distance": "Distanza",
@@ -366,9 +402,11 @@
"power": "Potenza", "power": "Potenza",
"slope": "Pendenza", "slope": "Pendenza",
"surface": "Superficie", "surface": "Superficie",
"highway": "Category",
"time": "Dati temporali", "time": "Dati temporali",
"moving": "Movimento", "moving": "Movimento",
"total": "Totale" "total": "Totale",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "비포장 도로", "unpaved": "비포장 도로",
"asphalt": "아스팔트", "asphalt": "아스팔트",
"concrete": "콘크리트", "concrete": "콘크리트",
"chipseal": "칩씰",
"cobblestone": "조약돌", "cobblestone": "조약돌",
"unhewn_cobblestone": "거친 조약돌",
"paving_stones": "포장석", "paving_stones": "포장석",
"stepping_stones": "디딤돌",
"sett": "정형 자갈", "sett": "정형 자갈",
"metal": "금속", "metal": "금속",
"wood": "목재", "wood": "목재",
@@ -135,15 +132,59 @@
"dirt": "흙길", "dirt": "흙길",
"ground": "지면", "ground": "지면",
"earth": "자연 지면", "earth": "자연 지면",
"snow": "눈",
"ice": "얼음",
"salt": "소금",
"mud": "진흙", "mud": "진흙",
"sand": "모래", "sand": "모래",
"woodchips": "목재 칩",
"grass": "잔디", "grass": "잔디",
"grass_paver": "잔디 포장" "grass_paver": "잔디 포장",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN 위성", "ignFrSatellite": "IGN 위성",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "경사 정보 표시", "settings": "Elevation profile settings"
"show_surface": "지면 정보 표시",
"show_speed": "속도 정보 표시",
"show_pace": "페이스 정보 표시",
"show_heartrate": "심박수 정보 표시",
"show_cadence": "케이던스 정보 표시",
"show_temperature": "온도 정보 표시",
"show_power": "파워 정보 표시"
}, },
"quantities": { "quantities": {
"distance": "거리", "distance": "거리",
@@ -366,9 +402,11 @@
"power": "파워", "power": "파워",
"slope": "경사", "slope": "경사",
"surface": "표면", "surface": "표면",
"highway": "Category",
"time": "시간", "time": "시간",
"moving": "이동 중", "moving": "이동 중",
"total": "전체" "total": "전체",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Negrįstas", "unpaved": "Negrįstas",
"asphalt": "Asfaltas", "asphalt": "Asfaltas",
"concrete": "Betonas", "concrete": "Betonas",
"chipseal": "Žvyrkelis",
"cobblestone": "Grįstas akmenimis", "cobblestone": "Grįstas akmenimis",
"unhewn_cobblestone": "Grįstas nešlifuotais akmenimis",
"paving_stones": "Plytelės", "paving_stones": "Plytelės",
"stepping_stones": "Plytelės su tarpais",
"sett": "Trinkelės", "sett": "Trinkelės",
"metal": "Metalo", "metal": "Metalo",
"wood": "Medžio", "wood": "Medžio",
@@ -135,15 +132,59 @@
"dirt": "Purvas", "dirt": "Purvas",
"ground": "Žemė", "ground": "Žemė",
"earth": "Žemė", "earth": "Žemė",
"snow": "Sniegas",
"ice": "Ledas",
"salt": "Druska",
"mud": "Purvas", "mud": "Purvas",
"sand": "Smėlis", "sand": "Smėlis",
"woodchips": "Medžio drožlės",
"grass": "Žolė", "grass": "Žolė",
"grass_paver": "Žolės grindinys" "grass_paver": "Žolės grindinys",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "Pradžios taškas yra per toli nuo artimiausio kelio", "from": "Pradžios taškas yra per toli nuo artimiausio kelio",
"via": "Tarpinis taškas yra per toli nuo artimiausio kelio", "via": "Tarpinis taškas yra per toli nuo artimiausio kelio",
@@ -173,6 +214,7 @@
"merge_traces": "Sujungti trasas", "merge_traces": "Sujungti trasas",
"merge_contents": "Sujungti turinį ir laikyti trasas atskirai", "merge_contents": "Sujungti turinį ir laikyti trasas atskirai",
"merge_selection": "Sujungti pasirinkimą", "merge_selection": "Sujungti pasirinkimą",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Sujungti elementus", "tooltip": "Sujungti elementus",
"help_merge_traces": "Sujungus pasirinktas trasas bus sukurta viena ištisinė trasa.", "help_merge_traces": "Sujungus pasirinktas trasas bus sukurta viena ištisinė trasa.",
"help_cannot_merge_traces": "Turi pasirinkti kelias trasas, kad galėtumėte jas sujungti.", "help_cannot_merge_traces": "Turi pasirinkti kelias trasas, kad galėtumėte jas sujungti.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Rodyti nuolydžio duomenis", "settings": "Elevation profile settings"
"show_surface": "Rodyti paviršiaus duomenis",
"show_speed": "Rodyti greičio duomenis",
"show_pace": "Rodyti tempo duomenis",
"show_heartrate": "Rodyti pulso duomenis",
"show_cadence": "Rodyti tempo duomenis",
"show_temperature": "Rodyti temperatūros duomenis",
"show_power": "Rodyti jėgos duomenis"
}, },
"quantities": { "quantities": {
"distance": "Atstumas", "distance": "Atstumas",
@@ -366,9 +402,11 @@
"power": "Jėga", "power": "Jėga",
"slope": "Nuolydis", "slope": "Nuolydis",
"surface": "Paviršius", "surface": "Paviršius",
"highway": "Category",
"time": "Laikas", "time": "Laikas",
"moving": "Judėjimas", "moving": "Judėjimas",
"total": "Bendras" "total": "Bendras",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Cobblestone", "cobblestone": "Cobblestone",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Wood", "wood": "Wood",
@@ -135,15 +132,59 @@
"dirt": "Dirt", "dirt": "Dirt",
"ground": "Ground", "ground": "Ground",
"earth": "Earth", "earth": "Earth",
"snow": "Snow",
"ice": "Ice",
"salt": "Salt",
"mud": "Mud", "mud": "Mud",
"sand": "Sand", "sand": "Sand",
"woodchips": "Woodchips",
"grass": "Grass", "grass": "Grass",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Onverhard", "unpaved": "Onverhard",
"asphalt": "Asfalt", "asphalt": "Asfalt",
"concrete": "Beton", "concrete": "Beton",
"chipseal": "Chipseal",
"cobblestone": "Klinkers", "cobblestone": "Klinkers",
"unhewn_cobblestone": "Ruwe kasseien",
"paving_stones": "Straatstenen", "paving_stones": "Straatstenen",
"stepping_stones": "Stapstenen",
"sett": "Instellen", "sett": "Instellen",
"metal": "Metaal", "metal": "Metaal",
"wood": "Hout", "wood": "Hout",
@@ -135,15 +132,59 @@
"dirt": "Onverhard", "dirt": "Onverhard",
"ground": "Ondergrond", "ground": "Ondergrond",
"earth": "Aarde", "earth": "Aarde",
"snow": "Sneeuw",
"ice": "IJs",
"salt": "Zout",
"mud": "Modder", "mud": "Modder",
"sand": "Zand", "sand": "Zand",
"woodchips": "Houtsnippers",
"grass": "Gras", "grass": "Gras",
"grass_paver": "Grastegel" "grass_paver": "Grastegel",
"clay": "Klei",
"stone": "Steen"
}, },
"highway": {
"unknown": "Onbekend",
"motorway": "Snelweg",
"motorway_link": "Snelweg aansluiting",
"trunk": "Primaire weg",
"trunk_link": "Aansluiting primaire weg",
"primary": "Primaire weg",
"primary_link": "Aansluiting primaire weg",
"secondary": "Secundaire weg",
"secondary_link": "Aansluiting secundaire weg",
"tertiary": "Tertiaire weg",
"tertiary_link": "Aansluiting tertiaire weg",
"unclassified": "Kleine weg",
"residential": "Bebouwde kom",
"living_street": "Woonstraat",
"service": "Ventweg",
"track": "Track",
"footway": "Voetpad",
"path": "Pad",
"pedestrian": "Voetganger",
"cycleway": "Fietspad",
"steps": "Trappen",
"road": "Weg",
"bridleway": "Ruiterpad",
"platform": "Platform",
"raceway": "Race circuit",
"rest_area": "Pauzeplek",
"abandoned": "Verlaten",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bushalte",
"busway": "Busbaan",
"elevator": "Lift",
"via_ferrata": "Via ferrata",
"proposed": "Geplande weg",
"construction": "Weg in aanleg"
},
"sac_scale": {
"hiking": "Hiken",
"mountain_hiking": "Bergwandelen",
"demanding_mountain_hiking": "Veeleisend bergwandelen",
"alpine_hiking": "Alpine wandelen",
"demanding_alpine_hiking": "Veeleisend alpine wandelen",
"difficult_alpine_hiking": "Moeilijke alpiene wandeling"
},
"mtb_scale": "MTB schaal",
"error": { "error": {
"from": "Het startpunt ligt te ver van de dichtstbijzijnde weg", "from": "Het startpunt ligt te ver van de dichtstbijzijnde weg",
"via": "Het via punt ligt te ver van de dichtstbijzijnde weg", "via": "Het via punt ligt te ver van de dichtstbijzijnde weg",
@@ -173,6 +214,7 @@
"merge_traces": "Verbind de routes", "merge_traces": "Verbind de routes",
"merge_contents": "Voeg de inhoud samen en houd de sporen gescheiden", "merge_contents": "Voeg de inhoud samen en houd de sporen gescheiden",
"merge_selection": "Voeg selectie samen", "merge_selection": "Voeg selectie samen",
"remove_gaps": "Verwijder tijdsprongen tussen sporen",
"tooltip": "Items samenvoegen", "tooltip": "Items samenvoegen",
"help_merge_traces": "Het verbinden van de geselecteerde sporen creëert één continu spoor.", "help_merge_traces": "Het verbinden van de geselecteerde sporen creëert één continu spoor.",
"help_cannot_merge_traces": "Uw selectie moet meerdere sporen bevatten om ze te verbinden.", "help_cannot_merge_traces": "Uw selectie moet meerdere sporen bevatten om ze te verbinden.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satelliet", "ignFrSatellite": "IGN Satelliet",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satelliet",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Toon richtingsgegevens", "settings": "Instellingen hoogteprofiel"
"show_surface": "Toon oppervlakte gegevens",
"show_speed": "Toon snelheidsgegevens",
"show_pace": "Toon oppervlakte gegevens",
"show_heartrate": "Toon hartslag gegevens",
"show_cadence": "Toon kadans gegevens",
"show_temperature": "Toon temperatuurgegevens",
"show_power": "Toon energie gegevens"
}, },
"quantities": { "quantities": {
"distance": "Afstand", "distance": "Afstand",
@@ -366,9 +402,11 @@
"power": "Kracht", "power": "Kracht",
"slope": "Helling", "slope": "Helling",
"surface": "Oppervlak", "surface": "Oppervlak",
"highway": "Categorie",
"time": "Tijd", "time": "Tijd",
"moving": "Beweging", "moving": "Beweging",
"total": "Totaal" "total": "Totaal",
"osm_extensions": "OpenStreetMap gegevens"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Uasfaltert", "unpaved": "Uasfaltert",
"asphalt": "Asfalt", "asphalt": "Asfalt",
"concrete": "Betong", "concrete": "Betong",
"chipseal": "Grov asfalt",
"cobblestone": "Brostein", "cobblestone": "Brostein",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metall", "metal": "Metall",
"wood": "Treverk", "wood": "Treverk",
@@ -135,15 +132,59 @@
"dirt": "Jord", "dirt": "Jord",
"ground": "Bakke", "ground": "Bakke",
"earth": "Jord", "earth": "Jord",
"snow": "Snø",
"ice": "Is",
"salt": "Salt",
"mud": "Gjørme", "mud": "Gjørme",
"sand": "Sand", "sand": "Sand",
"woodchips": "Treflis",
"grass": "Gress", "grass": "Gress",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Slå sammen valgte", "merge_selection": "Slå sammen valgte",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Slå sammen elementer", "tooltip": "Slå sammen elementer",
"help_merge_traces": "Ved å koble sammen de valgte sporene vil det opprettes ett enkelt kontinuerlig spor.", "help_merge_traces": "Ved å koble sammen de valgte sporene vil det opprettes ett enkelt kontinuerlig spor.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Avstand", "distance": "Avstand",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Skråning", "slope": "Skråning",
"surface": "Overflate", "surface": "Overflate",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Totalt" "total": "Totalt",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Nieutwardzona", "unpaved": "Nieutwardzona",
"asphalt": "Asfalt", "asphalt": "Asfalt",
"concrete": "Beton", "concrete": "Beton",
"chipseal": "Nawierzchnia utrwalana powierzchniowo",
"cobblestone": "Bruk", "cobblestone": "Bruk",
"unhewn_cobblestone": "Bruk",
"paving_stones": "Płyta", "paving_stones": "Płyta",
"stepping_stones": "Bruk",
"sett": "Bruk", "sett": "Bruk",
"metal": "Metal", "metal": "Metal",
"wood": "Drewno", "wood": "Drewno",
@@ -135,15 +132,59 @@
"dirt": "Ziemia", "dirt": "Ziemia",
"ground": "Teren", "ground": "Teren",
"earth": "Ziemia", "earth": "Ziemia",
"snow": "Śnieg",
"ice": "Lód",
"salt": "Sól",
"mud": "Błoto", "mud": "Błoto",
"sand": "Piasek", "sand": "Piasek",
"woodchips": "Zrębki",
"grass": "Trawa", "grass": "Trawa",
"grass_paver": "Płyta ażurowa" "grass_paver": "Płyta ażurowa",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "Punkt początkowy jest zbyt daleko od najbliższej drogi", "from": "Punkt początkowy jest zbyt daleko od najbliższej drogi",
"via": "Punkt przelotowy jest zbyt daleko od najbliższej drogi", "via": "Punkt przelotowy jest zbyt daleko od najbliższej drogi",
@@ -173,6 +214,7 @@
"merge_traces": "Połącz ślady", "merge_traces": "Połącz ślady",
"merge_contents": "Scal zawartość, ale utrzymaj rozłączone ślady", "merge_contents": "Scal zawartość, ale utrzymaj rozłączone ślady",
"merge_selection": "Scal zaznaczenie", "merge_selection": "Scal zaznaczenie",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Scal elementy razem", "tooltip": "Scal elementy razem",
"help_merge_traces": "Połączenie zaznaczonych śladów stworzy pojedynczy ciągły ślad.", "help_merge_traces": "Połączenie zaznaczonych śladów stworzy pojedynczy ciągły ślad.",
"help_cannot_merge_traces": "Wybór musi zawierać kilka śladów, aby je połączyć.", "help_cannot_merge_traces": "Wybór musi zawierać kilka śladów, aby je połączyć.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Pokaż dane nachylenia", "settings": "Elevation profile settings"
"show_surface": "Pokaż dane nawierzchni",
"show_speed": "Pokaż dane prędkości",
"show_pace": "Pokaż dane tempa",
"show_heartrate": "Pokaż dane tętna",
"show_cadence": "Pokaż dane rytmu",
"show_temperature": "Pokaż dane temperatury",
"show_power": "Pokaż dane mocy"
}, },
"quantities": { "quantities": {
"distance": "Dystans", "distance": "Dystans",
@@ -366,9 +402,11 @@
"power": "Moc", "power": "Moc",
"slope": "Nachylenie", "slope": "Nachylenie",
"surface": "Powierzchnia", "surface": "Powierzchnia",
"highway": "Category",
"time": "Czas", "time": "Czas",
"moving": "W ruchu", "moving": "W ruchu",
"total": "Łącznie" "total": "Łącznie",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Não pavimentado", "unpaved": "Não pavimentado",
"asphalt": "Asfalto", "asphalt": "Asfalto",
"concrete": "Cimento", "concrete": "Cimento",
"chipseal": "Pedriscos",
"cobblestone": "Empedrado", "cobblestone": "Empedrado",
"unhewn_cobblestone": "Paralelepípedo bruto",
"paving_stones": "Paralelepípedo", "paving_stones": "Paralelepípedo",
"stepping_stones": "Caminho de pedras",
"sett": "Pedra portuguesa", "sett": "Pedra portuguesa",
"metal": "Metal", "metal": "Metal",
"wood": "Madeira", "wood": "Madeira",
@@ -135,15 +132,59 @@
"dirt": "Terra", "dirt": "Terra",
"ground": "Chão", "ground": "Chão",
"earth": "Terra", "earth": "Terra",
"snow": "Neve",
"ice": "Gelo",
"salt": "Sal",
"mud": "Lama", "mud": "Lama",
"sand": "Areia", "sand": "Areia",
"woodchips": "Cavacos de madeira",
"grass": "Grama", "grass": "Grama",
"grass_paver": "Pavimentação com grama" "grass_paver": "Pavimentação com grama",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "O ponto de partida está muito longe da estrada mais próxima", "from": "O ponto de partida está muito longe da estrada mais próxima",
"via": "O ponto intermediário está muito longe da estrada mais próxima", "via": "O ponto intermediário está muito longe da estrada mais próxima",
@@ -173,6 +214,7 @@
"merge_traces": "Conecte as trilhas", "merge_traces": "Conecte as trilhas",
"merge_contents": "Mesclar o conteúdo e manter as trilhas desconectadas", "merge_contents": "Mesclar o conteúdo e manter as trilhas desconectadas",
"merge_selection": "Unir seleção", "merge_selection": "Unir seleção",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Unir itens", "tooltip": "Unir itens",
"help_merge_traces": "Conectar as trilhas selecionadas criará uma trilha única contínua.", "help_merge_traces": "Conectar as trilhas selecionadas criará uma trilha única contínua.",
"help_cannot_merge_traces": "Sua seleção deve conter várias trilhas para conectá-las.", "help_cannot_merge_traces": "Sua seleção deve conter várias trilhas para conectá-las.",
@@ -271,8 +313,9 @@
"ignFrPlan": "IGN Plan", "ignFrPlan": "IGN Plan",
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "Satélite IGN", "ignFrSatellite": "IGN Satélite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satélite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -291,7 +334,7 @@
"swisstopoMountainBikeClosures": "swisstopo MTB Closures", "swisstopoMountainBikeClosures": "swisstopo MTB Closures",
"swisstopoSkiTouring": "swisstopo Ski Touring", "swisstopoSkiTouring": "swisstopo Ski Touring",
"ignFrCadastre": "IGN Cadastre", "ignFrCadastre": "IGN Cadastre",
"ignSlope": "Inclinação IGN", "ignSlope": "IGN Inclinação",
"ignSkiTouring": "IGN Ski Touring", "ignSkiTouring": "IGN Ski Touring",
"waymarked_trails": "Trilhas demarcadas", "waymarked_trails": "Trilhas demarcadas",
"waymarkedTrailsHiking": "Caminhada", "waymarkedTrailsHiking": "Caminhada",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Mostrar dados de inclinação", "settings": "Elevation profile settings"
"show_surface": "Mostrar dados do terreno",
"show_speed": "Mostrar dados de velocidade",
"show_pace": "Mostrar dados de ritmo",
"show_heartrate": "Mostrar dados de frequência cardíaca",
"show_cadence": "Mostrar dados de cadência",
"show_temperature": "Mostrar dados de temperatura",
"show_power": "Mostrar dados de potência"
}, },
"quantities": { "quantities": {
"distance": "Distância", "distance": "Distância",
@@ -366,9 +402,11 @@
"power": "Potência", "power": "Potência",
"slope": "Inclinação", "slope": "Inclinação",
"surface": "Superfície", "surface": "Superfície",
"highway": "Category",
"time": "Tempo", "time": "Tempo",
"moving": "Movimento", "moving": "Movimento",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Não pavimentado", "unpaved": "Não pavimentado",
"asphalt": "Asfalto", "asphalt": "Asfalto",
"concrete": "Cimento", "concrete": "Cimento",
"chipseal": "Chipseal",
"cobblestone": "Empedrado", "cobblestone": "Empedrado",
"unhewn_cobblestone": "Unhewn cobblestone",
"paving_stones": "Paving stones", "paving_stones": "Paving stones",
"stepping_stones": "Stepping stones",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Madeira", "wood": "Madeira",
@@ -135,15 +132,59 @@
"dirt": "Terra", "dirt": "Terra",
"ground": "Chão", "ground": "Chão",
"earth": "Terra", "earth": "Terra",
"snow": "Neve",
"ice": "Gelo",
"salt": "Sal",
"mud": "Lama", "mud": "Lama",
"sand": "Areia", "sand": "Areia",
"woodchips": "Woodchips",
"grass": "Grama", "grass": "Grama",
"grass_paver": "Grass paver" "grass_paver": "Grass paver",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distância", "distance": "Distância",
@@ -366,9 +402,11 @@
"power": "Potência", "power": "Potência",
"slope": "Slope", "slope": "Slope",
"surface": "Superfície", "surface": "Superfície",
"highway": "Category",
"time": "Tempo", "time": "Tempo",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

View File

@@ -119,11 +119,8 @@
"unpaved": "Unpaved", "unpaved": "Unpaved",
"asphalt": "Asphalt", "asphalt": "Asphalt",
"concrete": "Concrete", "concrete": "Concrete",
"chipseal": "Chipseal",
"cobblestone": "Pavaj", "cobblestone": "Pavaj",
"unhewn_cobblestone": "Pavaj neșlefuit",
"paving_stones": "Pavaj din pietre", "paving_stones": "Pavaj din pietre",
"stepping_stones": "Pietre de pașit",
"sett": "Sett", "sett": "Sett",
"metal": "Metal", "metal": "Metal",
"wood": "Lemn", "wood": "Lemn",
@@ -135,15 +132,59 @@
"dirt": "Noroi", "dirt": "Noroi",
"ground": "Sol", "ground": "Sol",
"earth": "Pământ", "earth": "Pământ",
"snow": "Zăpadă",
"ice": "Gheață",
"salt": "Sare",
"mud": "Noroi", "mud": "Noroi",
"sand": "Nisip", "sand": "Nisip",
"woodchips": "Woodchips",
"grass": "Iarbă", "grass": "Iarbă",
"grass_paver": "Pavaj cu iarbă" "grass_paver": "Pavaj cu iarbă",
"clay": "Clay",
"stone": "Stone"
}, },
"highway": {
"unknown": "Unknown",
"motorway": "Highway",
"motorway_link": "Highway link",
"trunk": "Primary road",
"trunk_link": "Primary road link",
"primary": "Primary road",
"primary_link": "Primary road link",
"secondary": "Secondary road",
"secondary_link": "Secondary road link",
"tertiary": "Tertiary road",
"tertiary_link": "Tertiary road link",
"unclassified": "Minor road",
"residential": "Residential road",
"living_street": "Living street",
"service": "Service road",
"track": "Track",
"footway": "Footway",
"path": "Path",
"pedestrian": "Pedestrian",
"cycleway": "Cycleway",
"steps": "Steps",
"road": "Road",
"bridleway": "Horseriding path",
"platform": "Platform",
"raceway": "Racing circuit",
"rest_area": "Rest area",
"abandoned": "Abandoned",
"services": "Services",
"corridor": "Corridor",
"bus_stop": "Bus stop",
"busway": "Busway",
"elevator": "Elevator",
"via_ferrata": "Via ferrata",
"proposed": "Road to be built",
"construction": "Road under construction"
},
"sac_scale": {
"hiking": "Hiking",
"mountain_hiking": "Mountain hiking",
"demanding_mountain_hiking": "Demanding mountain hiking",
"alpine_hiking": "Alpine hiking",
"demanding_alpine_hiking": "Demanding alpine hiking",
"difficult_alpine_hiking": "Difficult alpine hiking"
},
"mtb_scale": "MTB scale",
"error": { "error": {
"from": "The start point is too far from the nearest road", "from": "The start point is too far from the nearest road",
"via": "The via point is too far from the nearest road", "via": "The via point is too far from the nearest road",
@@ -173,6 +214,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",
@@ -272,7 +314,8 @@
"ignFrTopo": "IGN Topo", "ignFrTopo": "IGN Topo",
"ignFrScan25": "IGN SCAN25", "ignFrScan25": "IGN SCAN25",
"ignFrSatellite": "IGN Satellite", "ignFrSatellite": "IGN Satellite",
"ignEs": "IGN", "ignEs": "IGN Topo",
"ignEsSatellite": "IGN Satellite",
"ordnanceSurvey": "Ordnance Survey", "ordnanceSurvey": "Ordnance Survey",
"norwayTopo": "Topografisk Norgeskart 4", "norwayTopo": "Topografisk Norgeskart 4",
"swedenTopo": "Lantmäteriet Topo", "swedenTopo": "Lantmäteriet Topo",
@@ -345,14 +388,7 @@
} }
}, },
"chart": { "chart": {
"show_slope": "Show slope data", "settings": "Elevation profile settings"
"show_surface": "Show surface data",
"show_speed": "Show speed data",
"show_pace": "Show pace data",
"show_heartrate": "Show heart rate data",
"show_cadence": "Show cadence data",
"show_temperature": "Show temperature data",
"show_power": "Show power data"
}, },
"quantities": { "quantities": {
"distance": "Distance", "distance": "Distance",
@@ -366,9 +402,11 @@
"power": "Power", "power": "Power",
"slope": "Slope", "slope": "Slope",
"surface": "Surface", "surface": "Surface",
"highway": "Category",
"time": "Time", "time": "Time",
"moving": "Moving", "moving": "Moving",
"total": "Total" "total": "Total",
"osm_extensions": "OpenStreetMap data"
}, },
"units": { "units": {
"meters": "m", "meters": "m",

Some files were not shown because too many files have changed in this diff Show More