mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-10-15 20:08:19 +00:00
Compare commits
34 Commits
drop-to-de
...
preserve-t
Author | SHA1 | Date | |
---|---|---|---|
![]() |
15f7aea300 | ||
![]() |
4ada271ad3 | ||
![]() |
1bda957778 | ||
![]() |
95328db1ee | ||
![]() |
65cbf5e751 | ||
![]() |
60f24f8757 | ||
![]() |
d1e4588813 | ||
![]() |
711825f5a3 | ||
![]() |
d823f44558 | ||
![]() |
193c77e51a | ||
![]() |
45f6c405c0 | ||
![]() |
78e1ea1e59 | ||
![]() |
ca51e1d788 | ||
![]() |
72b0b5a706 | ||
![]() |
4d1de97ba5 | ||
![]() |
04769002d0 | ||
![]() |
8190284148 | ||
![]() |
a668b4be62 | ||
![]() |
87534468d2 | ||
![]() |
d7a02f714a | ||
![]() |
0c16ddd534 | ||
![]() |
a96f989199 | ||
![]() |
35c7c9d965 | ||
![]() |
efa05b93ce | ||
![]() |
0e298cd0e4 | ||
![]() |
3ef98b2110 | ||
![]() |
fbf93ed6f9 | ||
![]() |
1bd56b6505 | ||
![]() |
acf0750ccb | ||
![]() |
48eaa344e4 | ||
![]() |
3262dec7d3 | ||
![]() |
572d206c2c | ||
![]() |
11934e5825 | ||
![]() |
5cca106d18 |
105
gpx/src/gpx.ts
105
gpx/src/gpx.ts
@@ -133,22 +133,21 @@ export class GPXFile extends GPXTreeNode<Track> {
|
||||
}
|
||||
if (gpx.hasOwnProperty('_data')) {
|
||||
this._data = gpx._data;
|
||||
|
||||
if (!this._data.hasOwnProperty('style')) {
|
||||
let style = this.getStyle();
|
||||
let fileStyle = {};
|
||||
if (style.color.length === 1) {
|
||||
fileStyle['color'] = style.color[0];
|
||||
}
|
||||
if (style.weight.length === 1) {
|
||||
fileStyle['weight'] = style.weight[0];
|
||||
}
|
||||
if (style.opacity.length === 1) {
|
||||
fileStyle['opacity'] = style.opacity[0];
|
||||
}
|
||||
if (Object.keys(fileStyle).length > 0) {
|
||||
this.setStyle(fileStyle);
|
||||
}
|
||||
}
|
||||
if (!this._data.hasOwnProperty('style')) {
|
||||
let style = this.getStyle();
|
||||
let fileStyle = {};
|
||||
if (style.color.length === 1) {
|
||||
fileStyle['color'] = style.color[0];
|
||||
}
|
||||
if (style.weight.length === 1) {
|
||||
fileStyle['weight'] = style.weight[0];
|
||||
}
|
||||
if (style.opacity.length === 1) {
|
||||
fileStyle['opacity'] = style.opacity[0];
|
||||
}
|
||||
if (Object.keys(fileStyle).length > 0) {
|
||||
this.setStyle(fileStyle);
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
let surface = points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface;
|
||||
if (statistics.global.surface[surface] === undefined) {
|
||||
statistics.global.surface[surface] = 0;
|
||||
}
|
||||
statistics.global.surface[surface] += dist;
|
||||
if (i > 0 && points[i - 1].extensions && points[i - 1].extensions["gpxtpx:TrackPointExtension"] && points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]) {
|
||||
Object.entries(points[i - 1].extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"]).forEach(([key, value]) => {
|
||||
if (statistics.global.extensions[key] === undefined) {
|
||||
statistics.global.extensions[key] = {};
|
||||
}
|
||||
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
|
||||
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 trkpt = og.trkpt.slice();
|
||||
|
||||
@@ -909,6 +912,21 @@ export class TrackSegment extends GPXTreeLeaf {
|
||||
} else if (last !== undefined && points[0].time < last.time) {
|
||||
// Adapt timestamps of the new points because they are too early
|
||||
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) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
getSurface(): 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;
|
||||
}
|
||||
|
||||
setSurface(surface: string): void {
|
||||
setExtensions(extensions: Record<string, string>) {
|
||||
if (Object.keys(extensions).length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!this.extensions) {
|
||||
this.extensions = {};
|
||||
}
|
||||
@@ -1074,7 +1091,13 @@ export class TrackPoint {
|
||||
if (!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 {
|
||||
@@ -1104,8 +1127,11 @@ export class TrackPoint {
|
||||
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"];
|
||||
}
|
||||
if (this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface && !exclude.includes('surface')) {
|
||||
trkpt.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] = { surface: this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"].surface };
|
||||
if (this.extensions["gpxtpx:TrackPointExtension"] && this.extensions["gpxtpx:TrackPointExtension"]["gpxtpx:Extensions"] && !exclude.includes('extensions')) {
|
||||
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;
|
||||
@@ -1255,7 +1281,7 @@ export class GPXStatistics {
|
||||
avg: number,
|
||||
count: number,
|
||||
},
|
||||
surface: Record<string, number>,
|
||||
extensions: Record<string, Record<string, number>>,
|
||||
};
|
||||
local: {
|
||||
points: TrackPoint[],
|
||||
@@ -1326,7 +1352,7 @@ export class GPXStatistics {
|
||||
avg: 0,
|
||||
count: 0,
|
||||
},
|
||||
surface: {},
|
||||
extensions: {},
|
||||
};
|
||||
this.local = {
|
||||
points: [],
|
||||
@@ -1396,11 +1422,16 @@ export class GPXStatistics {
|
||||
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.count += other.global.power.count;
|
||||
Object.keys(other.global.surface).forEach((surface) => {
|
||||
if (this.global.surface[surface] === undefined) {
|
||||
this.global.surface[surface] = 0;
|
||||
Object.keys(other.global.extensions).forEach((extension) => {
|
||||
if (this.global.extensions[extension] === undefined) {
|
||||
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];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -92,9 +92,7 @@ export type TrackPointExtension = {
|
||||
'gpxtpx:atemp'?: number;
|
||||
'gpxtpx:hr'?: number;
|
||||
'gpxtpx:cad'?: number;
|
||||
'gpxtpx:Extensions'?: {
|
||||
surface?: string;
|
||||
};
|
||||
'gpxtpx:Extensions'?: Record<string, string>;
|
||||
}
|
||||
|
||||
export type PowerExtension = {
|
||||
|
@@ -45,24 +45,9 @@ export async function handle({ event, resolve }) {
|
||||
`;
|
||||
}
|
||||
|
||||
const stringsHTML = page === 'app' ? stringsToHTML(strings) : '';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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('');
|
||||
}
|
||||
}
|
161
website/src/lib/assets/colors.ts
Normal file
161
website/src/lib/assets/colors.ts
Normal 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 |
@@ -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 { type Style } from 'mapbox-gl';
|
||||
import { type StyleSpecification } from 'mapbox-gl';
|
||||
import ignFrTopo from './custom/ign-fr-topo.json';
|
||||
import ignFrPlan from './custom/ign-fr-plan.json';
|
||||
import ignFrSatellite from './custom/ign-fr-satellite.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',
|
||||
mapboxSatellite: 'mapbox://styles/mapbox/satellite-streets-v12',
|
||||
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}'],
|
||||
tileSize: 256,
|
||||
maxzoom: 20,
|
||||
attribution: 'IGN-F/Géoportail'
|
||||
attribution: '© <a href="https://www.ign.es" target="_blank">IGN</a>'
|
||||
}
|
||||
},
|
||||
layers: [{
|
||||
@@ -167,6 +167,23 @@ export const basemaps: { [key: string]: string | Style; } = {
|
||||
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: '© <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",
|
||||
norwayTopo: {
|
||||
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: {
|
||||
version: 8,
|
||||
sources: {
|
||||
@@ -636,6 +653,7 @@ export const basemapTree: LayerTreeType = {
|
||||
},
|
||||
spain: {
|
||||
ignEs: true,
|
||||
ignEsSatellite: true,
|
||||
},
|
||||
sweden: {
|
||||
swedenTopo: true,
|
||||
@@ -740,7 +758,7 @@ export const overpassTree: LayerTreeType = {
|
||||
export const defaultBasemap = 'mapboxOutdoors';
|
||||
|
||||
// Default overlays used (none)
|
||||
export const defaultOverlays = {
|
||||
export const defaultOverlays: LayerTreeType = {
|
||||
overlays: {
|
||||
world: {
|
||||
waymarked_trails: {
|
||||
@@ -855,6 +873,7 @@ export const defaultBasemapTree: LayerTreeType = {
|
||||
},
|
||||
spain: {
|
||||
ignEs: false,
|
||||
ignEsSatellite: false,
|
||||
},
|
||||
sweden: {
|
||||
swedenTopo: false,
|
||||
|
@@ -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'
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
|
||||
import type { Builder } from 'bits-ui';
|
||||
|
||||
export let variant:
|
||||
| 'default'
|
||||
@@ -12,11 +13,12 @@
|
||||
| undefined = 'default';
|
||||
export let label: string;
|
||||
export let side: 'top' | 'right' | 'bottom' | 'left' = 'top';
|
||||
export let builders: Builder[] = [];
|
||||
</script>
|
||||
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger asChild let:builder>
|
||||
<Button builders={[builder]} {variant} {...$$restProps}>
|
||||
<Button builders={[...builders, builder]} {variant} {...$$restProps} on:click>
|
||||
<slot />
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<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 Tooltip from '$lib/components/Tooltip.svelte';
|
||||
import Chart from 'chart.js/auto';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
import { map } from '$lib/stores';
|
||||
@@ -12,12 +13,15 @@
|
||||
Orbit,
|
||||
SquareActivity,
|
||||
Thermometer,
|
||||
Zap
|
||||
Zap,
|
||||
Circle,
|
||||
Check,
|
||||
ChartNoAxesColumn,
|
||||
Construction
|
||||
} from 'lucide-svelte';
|
||||
import { surfaceColors } from '$lib/assets/surfaces';
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import { getSlopeColor, getSurfaceColor, getHighwayColor } from '$lib/assets/colors';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import {
|
||||
getCadenceUnits,
|
||||
getCadenceWithUnits,
|
||||
getConvertedDistance,
|
||||
getConvertedElevation,
|
||||
@@ -26,45 +30,26 @@
|
||||
getDistanceUnits,
|
||||
getDistanceWithUnits,
|
||||
getElevationWithUnits,
|
||||
getHeartRateUnits,
|
||||
getHeartRateWithUnits,
|
||||
getPowerUnits,
|
||||
getPowerWithUnits,
|
||||
getTemperatureUnits,
|
||||
getTemperatureWithUnits,
|
||||
getVelocityUnits,
|
||||
getVelocityWithUnits,
|
||||
secondsToHHMMSS
|
||||
getVelocityWithUnits
|
||||
} from '$lib/units';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { DateFormatter } from '@internationalized/date';
|
||||
import type { GPXStatistics } from 'gpx';
|
||||
import { settings } from '$lib/db';
|
||||
import { mode } from 'mode-watcher';
|
||||
import { df } from '$lib/utils';
|
||||
|
||||
export let gpxStatistics: Writable<GPXStatistics>;
|
||||
export let slicedGPXStatistics: Writable<[GPXStatistics, number, number] | undefined>;
|
||||
export let panelSize: number;
|
||||
export let additionalDatasets: string[];
|
||||
export let elevationFill: 'slope' | 'surface' | undefined;
|
||||
export let elevationFill: 'slope' | 'surface' | 'highway' | undefined;
|
||||
export let showControls: boolean = true;
|
||||
|
||||
const { distanceUnits, velocityUnits, temperatureUnits } = settings;
|
||||
|
||||
let df: DateFormatter;
|
||||
|
||||
$: if ($locale) {
|
||||
df = new DateFormatter($locale, {
|
||||
dateStyle: 'medium',
|
||||
timeStyle: 'medium'
|
||||
});
|
||||
}
|
||||
|
||||
let canvas: HTMLCanvasElement;
|
||||
let showAdditionalScales = true;
|
||||
let updateShowAdditionalScales = () => {
|
||||
showAdditionalScales = canvas.width / window.devicePixelRatio >= 600;
|
||||
};
|
||||
let overlay: HTMLCanvasElement;
|
||||
let chart: Chart;
|
||||
|
||||
@@ -83,12 +68,11 @@
|
||||
x: {
|
||||
type: 'linear',
|
||||
ticks: {
|
||||
callback: function (value: number, index: number, ticks: { value: number }[]) {
|
||||
if (index === ticks.length - 1) {
|
||||
return `${value.toFixed(1).replace(/\.0+$/, '')}`;
|
||||
}
|
||||
callback: function (value: number) {
|
||||
return `${value.toFixed(1).replace(/\.0+$/, '')} ${getDistanceUnits()}`;
|
||||
}
|
||||
},
|
||||
align: 'inner',
|
||||
maxRotation: 0
|
||||
}
|
||||
},
|
||||
y: {
|
||||
@@ -159,7 +143,10 @@
|
||||
segment: point.slope.segment.toFixed(1),
|
||||
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 = [
|
||||
` ${$_('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) {
|
||||
labels.push(` ${$_('quantities.time')}: ${df.format(point.time)}`);
|
||||
}
|
||||
@@ -226,72 +224,21 @@
|
||||
stacked: false,
|
||||
onResize: function () {
|
||||
updateOverlay();
|
||||
updateShowAdditionalScales();
|
||||
}
|
||||
};
|
||||
|
||||
let datasets: {
|
||||
[key: string]: {
|
||||
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)) {
|
||||
let datasets: string[] = ['speed', 'hr', 'cad', 'atemp', 'power'];
|
||||
datasets.forEach((id) => {
|
||||
options.scales[`y${id}`] = {
|
||||
type: 'linear',
|
||||
position: 'right',
|
||||
title: {
|
||||
display: true,
|
||||
text: dataset.getLabel() + ' (' + dataset.getUnits() + ')',
|
||||
padding: {
|
||||
top: 6,
|
||||
bottom: 0
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
reverse: () => id === 'speed' && $velocityUnits === 'pace',
|
||||
display: false
|
||||
};
|
||||
}
|
||||
options.scales.yspeed['ticks'] = {
|
||||
callback: function (value: number) {
|
||||
if ($velocityUnits === 'speed') {
|
||||
return value;
|
||||
} else {
|
||||
return secondsToHHMMSS(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
Chart.register((await import('chartjs-plugin-zoom')).default); // dynamic import to avoid SSR and 'window is not defined' error
|
||||
@@ -324,8 +271,6 @@
|
||||
element
|
||||
});
|
||||
|
||||
updateShowAdditionalScales();
|
||||
|
||||
let startIndex = 0;
|
||||
let endIndex = 0;
|
||||
function getIndex(evt) {
|
||||
@@ -414,7 +359,7 @@
|
||||
segment: data.local.slope.segment[index],
|
||||
length: data.local.slope.length[index]
|
||||
},
|
||||
surface: point.getSurface(),
|
||||
extensions: point.getExtensions(),
|
||||
coordinates: point.getCoordinates(),
|
||||
index: index
|
||||
};
|
||||
@@ -424,7 +369,6 @@
|
||||
order: 1
|
||||
};
|
||||
chart.data.datasets[1] = {
|
||||
label: datasets.speed.getLabel(),
|
||||
data: data.local.points.map((point, index) => {
|
||||
return {
|
||||
x: getConvertedDistance(data.local.distance.total[index]),
|
||||
@@ -433,11 +377,10 @@
|
||||
};
|
||||
}),
|
||||
normalized: true,
|
||||
yAxisID: `y${datasets.speed.id}`,
|
||||
yAxisID: 'yspeed',
|
||||
hidden: true
|
||||
};
|
||||
chart.data.datasets[2] = {
|
||||
label: datasets.hr.getLabel(),
|
||||
data: data.local.points.map((point, index) => {
|
||||
return {
|
||||
x: getConvertedDistance(data.local.distance.total[index]),
|
||||
@@ -446,11 +389,10 @@
|
||||
};
|
||||
}),
|
||||
normalized: true,
|
||||
yAxisID: `y${datasets.hr.id}`,
|
||||
yAxisID: 'yhr',
|
||||
hidden: true
|
||||
};
|
||||
chart.data.datasets[3] = {
|
||||
label: datasets.cad.getLabel(),
|
||||
data: data.local.points.map((point, index) => {
|
||||
return {
|
||||
x: getConvertedDistance(data.local.distance.total[index]),
|
||||
@@ -459,11 +401,10 @@
|
||||
};
|
||||
}),
|
||||
normalized: true,
|
||||
yAxisID: `y${datasets.cad.id}`,
|
||||
yAxisID: 'ycad',
|
||||
hidden: true
|
||||
};
|
||||
chart.data.datasets[4] = {
|
||||
label: datasets.atemp.getLabel(),
|
||||
data: data.local.points.map((point, index) => {
|
||||
return {
|
||||
x: getConvertedDistance(data.local.distance.total[index]),
|
||||
@@ -472,11 +413,10 @@
|
||||
};
|
||||
}),
|
||||
normalized: true,
|
||||
yAxisID: `y${datasets.atemp.id}`,
|
||||
yAxisID: 'yatemp',
|
||||
hidden: true
|
||||
};
|
||||
chart.data.datasets[5] = {
|
||||
label: datasets.power.getLabel(),
|
||||
data: data.local.points.map((point, index) => {
|
||||
return {
|
||||
x: getConvertedDistance(data.local.distance.total[index]),
|
||||
@@ -485,43 +425,29 @@
|
||||
};
|
||||
}),
|
||||
normalized: true,
|
||||
yAxisID: `y${datasets.power.id}`,
|
||||
yAxisID: 'ypower',
|
||||
hidden: true
|
||||
};
|
||||
chart.options.scales.x['min'] = 0;
|
||||
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();
|
||||
}
|
||||
|
||||
let maxSlope = 20;
|
||||
function slopeFillCallback(context) {
|
||||
let slope = 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('');
|
||||
return getSlopeColor(context.p0.raw.slope.segment);
|
||||
}
|
||||
|
||||
function surfaceFillCallback(context) {
|
||||
let surface = context.p0.raw.surface;
|
||||
return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing;
|
||||
return getSurfaceColor(context.p0.raw.extensions.surface);
|
||||
}
|
||||
|
||||
function highwayFillCallback(context) {
|
||||
return getHighwayColor(
|
||||
context.p0.raw.extensions.highway,
|
||||
context.p0.raw.extensions.sac_scale,
|
||||
context.p0.raw.extensions.mtb_scale
|
||||
);
|
||||
}
|
||||
|
||||
$: if (chart) {
|
||||
@@ -533,6 +459,10 @@
|
||||
chart.data.datasets[0]['segment'] = {
|
||||
backgroundColor: surfaceFillCallback
|
||||
};
|
||||
} else if (elevationFill === 'highway') {
|
||||
chart.data.datasets[0]['segment'] = {
|
||||
backgroundColor: highwayFillCallback
|
||||
};
|
||||
} else {
|
||||
chart.data.datasets[0]['segment'] = {};
|
||||
}
|
||||
@@ -552,12 +482,6 @@
|
||||
chart.data.datasets[4].hidden = !includeTemperature;
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -568,6 +492,8 @@
|
||||
|
||||
overlay.width = canvas.width / window.devicePixelRatio;
|
||||
overlay.height = canvas.height / window.devicePixelRatio;
|
||||
overlay.style.width = `${overlay.width}px`;
|
||||
overlay.style.height = `${overlay.height}px`;
|
||||
|
||||
if ($slicedGPXStatistics) {
|
||||
let startIndex = $slicedGPXStatistics[1];
|
||||
@@ -591,7 +517,7 @@
|
||||
startPixel,
|
||||
chart.chartArea.top,
|
||||
endPixel - startPixel,
|
||||
chart.chartArea.bottom - chart.chartArea.top
|
||||
chart.chartArea.height
|
||||
);
|
||||
}
|
||||
} else if (overlay) {
|
||||
@@ -611,75 +537,135 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="h-full grow min-w-0 flex flex-row gap-4 items-center {$$props.class ?? ''}">
|
||||
<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={canvas} class="w-full h-full"></canvas>
|
||||
</div>
|
||||
<div class="h-full grow min-w-0 relative py-2">
|
||||
<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>
|
||||
{#if showControls}
|
||||
<div class="h-full flex flex-col justify-center" style="width: {panelSize > 158 ? 22 : 42}px">
|
||||
<ToggleGroup.Root
|
||||
class="{panelSize > 158
|
||||
? 'flex-col'
|
||||
: 'flex-row'} flex-wrap gap-0 min-h-0 content-center border rounded-t-md"
|
||||
type="single"
|
||||
bind:value={elevationFill}
|
||||
>
|
||||
<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')}
|
||||
<div class="absolute bottom-10 right-1.5">
|
||||
<Popover.Root>
|
||||
<Popover.Trigger asChild let:builder>
|
||||
<ButtonWithTooltip
|
||||
label={$_('chart.settings')}
|
||||
builders={[builder]}
|
||||
variant="outline"
|
||||
class="w-7 h-7 p-0 flex justify-center opacity-70 hover:opacity-100 transition-opacity duration-300 hover:bg-background"
|
||||
>
|
||||
<Zap size="15" />
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
<ToggleGroup.Item class="p-0 w-5 h-5" value="hr" aria-label={$_('chart.show_heartrate')}>
|
||||
<Tooltip side="left" label={$_('chart.show_heartrate')}>
|
||||
<HeartPulse size="15" />
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
<ToggleGroup.Item class="p-0 w-5 h-5" value="cad" aria-label={$_('chart.show_cadence')}>
|
||||
<Tooltip side="left" label={$_('chart.show_cadence')}>
|
||||
<Orbit size="15" />
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
<ToggleGroup.Item
|
||||
class="p-0 w-5 h-5"
|
||||
value="atemp"
|
||||
aria-label={$_('chart.show_temperature')}
|
||||
>
|
||||
<Tooltip side="left" label={$_('chart.show_temperature')}>
|
||||
<Thermometer size="15" />
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
<ToggleGroup.Item class="p-0 w-5 h-5" value="power" aria-label={$_('chart.show_power')}>
|
||||
<Tooltip side="left" label={$_('chart.show_power')}>
|
||||
<SquareActivity size="15" />
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
</ToggleGroup.Root>
|
||||
<ChartNoAxesColumn size="18" />
|
||||
</ButtonWithTooltip>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content class="w-fit p-0 flex flex-col divide-y" side="top" sideOffset={-32}>
|
||||
<ToggleGroup.Root
|
||||
class="flex flex-col items-start gap-0 p-1"
|
||||
type="single"
|
||||
bind:value={elevationFill}
|
||||
>
|
||||
<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="slope"
|
||||
>
|
||||
<div class="w-6 flex justify-center items-center">
|
||||
{#if elevationFill === 'slope'}
|
||||
<Circle class="h-1.5 w-1.5 fill-current text-current" />
|
||||
{/if}
|
||||
</div>
|
||||
<TriangleRight size="15" class="mr-1" />
|
||||
{$_('quantities.slope')}
|
||||
</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="surface"
|
||||
variant="outline"
|
||||
>
|
||||
<div class="w-6 flex justify-center items-center">
|
||||
{#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>
|
||||
{/if}
|
||||
</div>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
import {
|
||||
Download,
|
||||
Zap,
|
||||
BrickWall,
|
||||
Earth,
|
||||
HeartPulse,
|
||||
Orbit,
|
||||
Thermometer,
|
||||
@@ -31,19 +31,19 @@
|
||||
let open = false;
|
||||
let exportOptions: Record<string, boolean> = {
|
||||
time: true,
|
||||
surface: true,
|
||||
hr: true,
|
||||
cad: true,
|
||||
atemp: true,
|
||||
power: true
|
||||
power: true,
|
||||
extensions: true
|
||||
};
|
||||
let hide: Record<string, boolean> = {
|
||||
time: false,
|
||||
surface: false,
|
||||
hr: false,
|
||||
cad: false,
|
||||
atemp: false,
|
||||
power: false
|
||||
power: false,
|
||||
extensions: false
|
||||
};
|
||||
|
||||
$: if ($exportState !== ExportState.NONE) {
|
||||
@@ -63,11 +63,11 @@
|
||||
}
|
||||
|
||||
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.cad = statistics.global.cad.count === 0;
|
||||
hide.atemp = statistics.global.atemp.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]);
|
||||
@@ -144,11 +144,11 @@
|
||||
{$_('quantities.time')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-1.5 {hide.surface ? 'hidden' : ''}">
|
||||
<Checkbox id="export-surface" bind:checked={exportOptions.surface} />
|
||||
<Label for="export-surface" class="flex flex-row items-center gap-1">
|
||||
<BrickWall size="16" />
|
||||
{$_('quantities.surface')}
|
||||
<div class="flex flex-row items-center gap-1.5 {hide.extensions ? 'hidden' : ''}">
|
||||
<Checkbox id="export-extensions" bind:checked={exportOptions.extensions} />
|
||||
<Label for="export-extensions" class="flex flex-row items-center gap-1">
|
||||
<Earth size="16" />
|
||||
{$_('quantities.osm_extensions')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}">
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
<Card.Root
|
||||
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"
|
||||
>
|
||||
<Card.Content
|
||||
@@ -38,15 +38,15 @@
|
||||
>
|
||||
<Tooltip label={$_('quantities.distance')}>
|
||||
<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" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip label={$_('quantities.elevation_gain_loss')}>
|
||||
<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" />
|
||||
<MoveDownRight size="18" class="mx-1" />
|
||||
<MoveDownRight size="16" class="mx-1" />
|
||||
<WithUnits value={statistics.global.elevation.loss} type="elevation" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
@@ -58,7 +58,7 @@
|
||||
)} / {$_('quantities.total')})"
|
||||
>
|
||||
<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} />
|
||||
<span class="mx-1">/</span>
|
||||
<WithUnits value={statistics.global.speed.total} type="speed" />
|
||||
@@ -71,7 +71,7 @@
|
||||
label="{$_('quantities.time')} ({$_('quantities.moving')} / {$_('quantities.total')})"
|
||||
>
|
||||
<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" />
|
||||
<span class="mx-1">/</span>
|
||||
<WithUnits value={statistics.global.time.total} type="time" />
|
||||
|
@@ -50,6 +50,20 @@
|
||||
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({
|
||||
container: 'map',
|
||||
style: {
|
||||
@@ -334,7 +348,7 @@
|
||||
|
||||
div :global(.mapboxgl-popup) {
|
||||
@apply w-fit;
|
||||
@apply z-20;
|
||||
@apply z-50;
|
||||
}
|
||||
|
||||
div :global(.mapboxgl-popup-content) {
|
||||
|
25
website/src/lib/components/MapPopup.svelte
Normal file
25
website/src/lib/components/MapPopup.svelte
Normal 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>
|
78
website/src/lib/components/MapPopup.ts
Normal file
78
website/src/lib/components/MapPopup.ts
Normal 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);
|
||||
}
|
||||
}
|
@@ -260,9 +260,7 @@
|
||||
options.elevation.power ? 'power' : null
|
||||
].filter((dataset) => dataset !== null)}
|
||||
elevationFill={options.elevation.fill}
|
||||
panelSize={options.elevation.height}
|
||||
showControls={options.elevation.controls}
|
||||
class="py-2"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
@@ -10,7 +10,7 @@ export type EmbeddingOptions = {
|
||||
show: boolean;
|
||||
height: number;
|
||||
controls: boolean;
|
||||
fill: 'slope' | 'surface' | undefined;
|
||||
fill: 'slope' | 'surface' | 'highway' | undefined;
|
||||
speed: boolean;
|
||||
hr: boolean;
|
||||
cad: boolean;
|
||||
|
@@ -142,7 +142,7 @@
|
||||
let value = selected?.value;
|
||||
if (value === 'none') {
|
||||
options.elevation.fill = undefined;
|
||||
} else if (value === 'slope' || value === 'surface') {
|
||||
} else if (value === 'slope' || value === 'surface' || value === 'highway') {
|
||||
options.elevation.fill = value;
|
||||
}
|
||||
}}
|
||||
@@ -153,6 +153,7 @@
|
||||
<Select.Content>
|
||||
<Select.Item value="slope">{$_('quantities.slope')}</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.Content>
|
||||
</Select.Root>
|
||||
@@ -165,35 +166,35 @@
|
||||
<Checkbox id="show-speed" bind:checked={options.elevation.speed} />
|
||||
<Label for="show-speed" class="flex flex-row items-center gap-1">
|
||||
<Zap size="16" />
|
||||
{$_('chart.show_speed')}
|
||||
{$_('quantities.speed')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="show-hr" bind:checked={options.elevation.hr} />
|
||||
<Label for="show-hr" class="flex flex-row items-center gap-1">
|
||||
<HeartPulse size="16" />
|
||||
{$_('chart.show_heartrate')}
|
||||
{$_('quantities.heartrate')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="show-cad" bind:checked={options.elevation.cad} />
|
||||
<Label for="show-cad" class="flex flex-row items-center gap-1">
|
||||
<Orbit size="16" />
|
||||
{$_('chart.show_cadence')}
|
||||
{$_('quantities.cadence')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="show-temp" bind:checked={options.elevation.temp} />
|
||||
<Label for="show-temp" class="flex flex-row items-center gap-1">
|
||||
<Thermometer size="16" />
|
||||
{$_('chart.show_temperature')}
|
||||
{$_('quantities.temperature')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="show-power" bind:checked={options.elevation.power} />
|
||||
<Label for="show-power" class="flex flex-row items-center gap-1">
|
||||
<SquareActivity size="16" />
|
||||
{$_('chart.show_power')}
|
||||
{$_('quantities.power')}
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -49,17 +49,11 @@
|
||||
gpxLayers,
|
||||
map
|
||||
} from '$lib/stores';
|
||||
import {
|
||||
GPXTreeElement,
|
||||
Track,
|
||||
TrackSegment,
|
||||
type AnyGPXTreeElement,
|
||||
Waypoint,
|
||||
GPXFile
|
||||
} from 'gpx';
|
||||
import { GPXTreeElement, Track, type AnyGPXTreeElement, Waypoint, GPXFile } from 'gpx';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import MetadataDialog from './MetadataDialog.svelte';
|
||||
import StyleDialog from './StyleDialog.svelte';
|
||||
import { waypointPopup } from '$lib/components/gpx-layer/GPXLayerPopup';
|
||||
|
||||
export let node: GPXTreeElement<AnyGPXTreeElement> | Waypoint[] | Waypoint;
|
||||
export let item: ListItem;
|
||||
@@ -179,7 +173,7 @@
|
||||
if (layer && file) {
|
||||
let waypoint = file.wpt[item.getWaypointIndex()];
|
||||
if (waypoint) {
|
||||
layer.showWaypointPopup(waypoint);
|
||||
waypointPopup?.setItem({ item: waypoint, fileId: item.getFileId() });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +182,7 @@
|
||||
if (item instanceof ListWaypointItem) {
|
||||
let layer = gpxLayers.get(item.getFileId());
|
||||
if (layer) {
|
||||
layer.hideWaypointPopup();
|
||||
waypointPopup?.setItem(null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
@@ -5,6 +5,8 @@ import { get } from "svelte/store";
|
||||
|
||||
const { distanceMarkers, distanceUnits } = settings;
|
||||
|
||||
const stops = [[100, 0], [50, 7], [25, 8, 10], [10, 10], [5, 11], [1, 13]];
|
||||
|
||||
export class DistanceMarkers {
|
||||
map: mapboxgl.Map;
|
||||
updateBinded: () => void = this.update.bind(this);
|
||||
@@ -31,30 +33,36 @@ export class DistanceMarkers {
|
||||
data: this.getDistanceMarkersGeoJSON()
|
||||
});
|
||||
}
|
||||
if (!this.map.getLayer('distance-markers')) {
|
||||
this.map.addLayer({
|
||||
id: 'distance-markers',
|
||||
type: 'symbol',
|
||||
source: 'distance-markers',
|
||||
layout: {
|
||||
'text-field': ['get', 'distance'],
|
||||
'text-size': 14,
|
||||
'text-font': ['Open Sans Bold'],
|
||||
'text-padding': 20,
|
||||
},
|
||||
paint: {
|
||||
'text-color': 'black',
|
||||
'text-halo-width': 2,
|
||||
'text-halo-color': 'white',
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.map.moveLayer('distance-markers');
|
||||
}
|
||||
stops.forEach(([d, minzoom, maxzoom]) => {
|
||||
if (!this.map.getLayer(`distance-markers-${d}`)) {
|
||||
this.map.addLayer({
|
||||
id: `distance-markers-${d}`,
|
||||
type: 'symbol',
|
||||
source: 'distance-markers',
|
||||
filter: d === 5 ? ['any', ['==', ['get', 'level'], 5], ['==', ['get', 'level'], 25]] : ['==', ['get', 'level'], d],
|
||||
minzoom: minzoom,
|
||||
maxzoom: maxzoom ?? 24,
|
||||
layout: {
|
||||
'text-field': ['get', 'distance'],
|
||||
'text-size': 14,
|
||||
'text-font': ['Open Sans Bold'],
|
||||
},
|
||||
paint: {
|
||||
'text-color': 'black',
|
||||
'text-halo-width': 2,
|
||||
'text-halo-color': 'white',
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.map.moveLayer(`distance-markers-${d}`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.map.getLayer('distance-markers')) {
|
||||
this.map.removeLayer('distance-markers');
|
||||
}
|
||||
stops.forEach(([d]) => {
|
||||
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
|
||||
return;
|
||||
@@ -73,6 +81,7 @@ export class DistanceMarkers {
|
||||
for (let i = 0; i < statistics.local.distance.total.length; i++) {
|
||||
if (statistics.local.distance.total[i] >= currentTargetDistance * (get(distanceUnits) === 'metric' ? 1 : 1.60934)) {
|
||||
let distance = currentTargetDistance.toFixed(0);
|
||||
let [level, minzoom] = stops.find(([d]) => currentTargetDistance % d === 0) ?? [0, 0];
|
||||
features.push({
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
@@ -81,6 +90,8 @@ export class DistanceMarkers {
|
||||
},
|
||||
properties: {
|
||||
distance,
|
||||
level,
|
||||
minzoom,
|
||||
}
|
||||
} as GeoJSON.Feature);
|
||||
currentTargetDistance += 1;
|
||||
|
@@ -2,11 +2,10 @@ import { currentTool, map, Tool } from "$lib/stores";
|
||||
import { settings, type GPXFileWithStatistics, dbUtils } from "$lib/db";
|
||||
import { get, type Readable } from "svelte/store";
|
||||
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 { ListTrackSegmentItem, ListWaypointItem, ListWaypointsItem, ListTrackItem, ListFileItem, ListRootItem } from "$lib/components/file-list/FileList";
|
||||
import type { Waypoint } from "gpx";
|
||||
import { getElevation, resetCursor, setGrabbingCursor, setPointerCursor, setScissorsCursor } from "$lib/utils";
|
||||
import { getClosestLinePoint, getElevation, resetCursor, setGrabbingCursor, setPointerCursor, setScissorsCursor } from "$lib/utils";
|
||||
import { selectedWaypoint } from "$lib/components/toolbar/tools/Waypoint.svelte";
|
||||
import { MapPin, Square } from "lucide-static";
|
||||
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) {
|
||||
let symbolSvg = symbol ? symbols[symbol]?.iconSvg : undefined;
|
||||
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);
|
||||
layerOnMouseEnterBinded: (e: any) => void = this.layerOnMouseEnter.bind(this);
|
||||
layerOnMouseLeaveBinded: () => void = this.layerOnMouseLeave.bind(this);
|
||||
layerOnMouseMoveBinded: (e: any) => void = this.layerOnMouseMove.bind(this);
|
||||
layerOnClickBinded: (e: any) => void = this.layerOnClick.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>) {
|
||||
this.map = map;
|
||||
@@ -113,6 +137,10 @@ export class GPXLayer {
|
||||
this.draggable = get(currentTool) === Tool.WAYPOINT;
|
||||
|
||||
this.map.on('style.import.load', this.updateBinded);
|
||||
|
||||
if (inspectKeyDown === null) {
|
||||
inspectKeyDown = new KeyDown(inspectKey);
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
@@ -157,6 +185,7 @@ export class GPXLayer {
|
||||
this.map.on('contextmenu', this.fileId, this.layerOnContextMenuBinded);
|
||||
this.map.on('mouseenter', this.fileId, this.layerOnMouseEnterBinded);
|
||||
this.map.on('mouseleave', this.fileId, this.layerOnMouseLeaveBinded);
|
||||
this.map.on('mousemove', this.fileId, this.layerOnMouseMoveBinded);
|
||||
}
|
||||
|
||||
if (get(directionMarkers)) {
|
||||
@@ -224,11 +253,11 @@ export class GPXLayer {
|
||||
}).setLngLat(waypoint.getCoordinates());
|
||||
Object.defineProperty(marker, '_waypoint', { value: waypoint, writable: true });
|
||||
let dragEndTimestamp = 0;
|
||||
marker.getElement().addEventListener('mouseover', (e) => {
|
||||
marker.getElement().addEventListener('mousemove', (e) => {
|
||||
if (marker._isDragging) {
|
||||
return;
|
||||
}
|
||||
this.showWaypointPopup(marker._waypoint);
|
||||
waypointPopup?.setItem({ item: marker._waypoint, fileId: this.fileId });
|
||||
e.stopPropagation();
|
||||
});
|
||||
marker.getElement().addEventListener('click', (e) => {
|
||||
@@ -251,14 +280,14 @@ export class GPXLayer {
|
||||
} else if (get(currentTool) === Tool.WAYPOINT) {
|
||||
selectedWaypoint.set([marker._waypoint, this.fileId]);
|
||||
} else {
|
||||
this.showWaypointPopup(marker._waypoint);
|
||||
waypointPopup?.setItem({ item: marker._waypoint, fileId: this.fileId });
|
||||
}
|
||||
e.stopPropagation();
|
||||
});
|
||||
marker.on('dragstart', () => {
|
||||
setGrabbingCursor();
|
||||
marker.getElement().style.cursor = 'grabbing';
|
||||
this.hideWaypointPopup();
|
||||
waypointPopup?.hide();
|
||||
});
|
||||
marker.on('dragend', (e) => {
|
||||
resetCursor();
|
||||
@@ -307,6 +336,7 @@ export class GPXLayer {
|
||||
this.map.off('contextmenu', this.fileId, this.layerOnContextMenuBinded);
|
||||
this.map.off('mouseenter', this.fileId, this.layerOnMouseEnterBinded);
|
||||
this.map.off('mouseleave', this.fileId, this.layerOnMouseLeaveBinded);
|
||||
this.map.off('mousemove', this.fileId, this.layerOnMouseMoveBinded);
|
||||
this.map.off('style.import.load', this.updateBinded);
|
||||
|
||||
if (this.map.getLayer(this.fileId + '-direction')) {
|
||||
@@ -353,6 +383,19 @@ export class GPXLayer {
|
||||
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) {
|
||||
if (get(currentTool) === Tool.ROUTING && get(selection).hasAnyChildren(new ListRootItem(), true, ['waypoints'])) {
|
||||
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 {
|
||||
let file = get(this.file)?.file;
|
||||
if (!file) {
|
||||
|
44
website/src/lib/components/gpx-layer/GPXLayerPopup.ts
Normal file
44
website/src/lib/components/gpx-layer/GPXLayerPopup.ts
Normal 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, []));
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { map, gpxLayers } from '$lib/stores';
|
||||
import { GPXLayer } from './GPXLayer';
|
||||
import WaypointPopup from './WaypointPopup.svelte';
|
||||
import { fileObservers } from '$lib/db';
|
||||
import { DistanceMarkers } from './DistanceMarkers';
|
||||
import { StartEndMarkers } from './StartEndMarkers';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { createPopups, removePopups } from './GPXLayerPopup';
|
||||
|
||||
let distanceMarkers: DistanceMarkers | undefined = undefined;
|
||||
let startEndMarkers: StartEndMarkers | undefined = undefined;
|
||||
@@ -35,6 +35,7 @@
|
||||
if (startEndMarkers) {
|
||||
startEndMarkers.remove();
|
||||
}
|
||||
createPopups($map);
|
||||
distanceMarkers = new DistanceMarkers($map);
|
||||
startEndMarkers = new StartEndMarkers($map);
|
||||
}
|
||||
@@ -42,17 +43,14 @@
|
||||
onDestroy(() => {
|
||||
gpxLayers.forEach((layer) => layer.remove());
|
||||
gpxLayers.clear();
|
||||
|
||||
removePopups();
|
||||
if (distanceMarkers) {
|
||||
distanceMarkers.remove();
|
||||
distanceMarkers = undefined;
|
||||
}
|
||||
|
||||
if (startEndMarkers) {
|
||||
startEndMarkers.remove();
|
||||
startEndMarkers = undefined;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<WaypointPopup />
|
||||
|
36
website/src/lib/components/gpx-layer/TrackpointPopup.svelte
Normal file
36
website/src/lib/components/gpx-layer/TrackpointPopup.svelte
Normal 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)}° {trackpoint.item
|
||||
.getLongitude()
|
||||
.toFixed(6)}°
|
||||
</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>
|
@@ -2,23 +2,20 @@
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
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 { Dot, ExternalLink, Trash2 } from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { Tool, currentTool } from '$lib/stores';
|
||||
import { getSymbolKey, symbols } from '$lib/assets/symbols';
|
||||
import { _ } from 'svelte-i18n';
|
||||
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(() => {
|
||||
waypointPopup.setDOMContent(popupElement);
|
||||
popupElement.classList.remove('hidden');
|
||||
});
|
||||
|
||||
$: symbolKey = $currentPopupWaypoint ? getSymbolKey($currentPopupWaypoint[0].sym) : undefined;
|
||||
$: symbolKey = waypoint ? getSymbolKey(waypoint.item.sym) : undefined;
|
||||
|
||||
function sanitize(text: string | undefined): string {
|
||||
if (text === undefined) {
|
||||
@@ -34,68 +31,63 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={popupElement} class="hidden">
|
||||
{#if $currentPopupWaypoint}
|
||||
<Card.Root class="border-none shadow-md text-base max-w-80 p-2">
|
||||
<Card.Header class="p-0">
|
||||
<Card.Title class="text-md">
|
||||
{#if $currentPopupWaypoint[0].link && $currentPopupWaypoint[0].link.attributes && $currentPopupWaypoint[0].link.attributes.href}
|
||||
<a href={$currentPopupWaypoint[0].link.attributes.href} target="_blank">
|
||||
{$currentPopupWaypoint[0].name ?? $currentPopupWaypoint[0].link.attributes.href}
|
||||
<ExternalLink size="12" class="inline-block mb-1.5" />
|
||||
</a>
|
||||
<Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]">
|
||||
<Card.Header class="p-0">
|
||||
<Card.Title class="text-md">
|
||||
{#if waypoint.item.link && waypoint.item.link.attributes && waypoint.item.link.attributes.href}
|
||||
<a href={waypoint.item.link.attributes.href} target="_blank">
|
||||
{waypoint.item.name ?? waypoint.item.link.attributes.href}
|
||||
<ExternalLink size="12" class="inline-block mb-1.5" />
|
||||
</a>
|
||||
{:else}
|
||||
{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}
|
||||
{$currentPopupWaypoint[0].name ?? $_('gpx.waypoint')}
|
||||
<span class="w-4 inline-block" />
|
||||
{/if}
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content class="flex flex-col p-0 text-sm">
|
||||
<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}
|
||||
<span class="w-4 inline-block" />
|
||||
{/if}
|
||||
{$_(`gpx.symbol.${symbolKey}`)}
|
||||
</span>
|
||||
<Dot size="16" />
|
||||
{/if}
|
||||
{$currentPopupWaypoint[0].getLatitude().toFixed(6)}° {$currentPopupWaypoint[0]
|
||||
.getLongitude()
|
||||
.toFixed(6)}°
|
||||
{#if $currentPopupWaypoint[0].ele !== undefined}
|
||||
<Dot size="16" />
|
||||
<WithUnits value={$currentPopupWaypoint[0].ele} type="elevation" />
|
||||
{/if}
|
||||
</div>
|
||||
{#if $currentPopupWaypoint[0].desc}
|
||||
<span class="whitespace-pre-wrap">{@html sanitize($currentPopupWaypoint[0].desc)}</span>
|
||||
{/if}
|
||||
{#if $currentPopupWaypoint[0].cmt && $currentPopupWaypoint[0].cmt !== $currentPopupWaypoint[0].desc}
|
||||
<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>
|
||||
{$_(`gpx.symbol.${symbolKey}`)}
|
||||
</span>
|
||||
<Dot size="16" />
|
||||
{/if}
|
||||
{waypoint.item.getLatitude().toFixed(6)}° {waypoint.item.getLongitude().toFixed(6)}°
|
||||
{#if waypoint.item.ele !== undefined}
|
||||
<Dot size="16" />
|
||||
<WithUnits value={waypoint.item.ele} type="elevation" />
|
||||
{/if}
|
||||
</div>
|
||||
<ScrollArea class="flex flex-col" viewportClasses="max-h-[30dvh]">
|
||||
{#if waypoint.item.desc}
|
||||
<span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.desc)}</span>
|
||||
{/if}
|
||||
{#if waypoint.item.cmt && waypoint.item.cmt !== waypoint.item.desc}
|
||||
<span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.cmt)}</span>
|
||||
{/if}
|
||||
</ScrollArea>
|
||||
{#if $currentTool === Tool.WAYPOINT}
|
||||
<Button
|
||||
class="mt-2 w-full px-2 py-1 h-8 justify-start"
|
||||
variant="outline"
|
||||
on:click={() => deleteWaypoint(waypoint.fileId, waypoint.item._data.index)}
|
||||
>
|
||||
<Trash2 size="16" class="mr-1" />
|
||||
{$_('menu.delete')}
|
||||
<Shortcut shift={true} click={true} />
|
||||
</Button>
|
||||
{/if}
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<style lang="postcss">
|
||||
div :global(a) {
|
||||
|
@@ -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, []));
|
||||
}
|
@@ -1,435 +1,422 @@
|
||||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import * as RadioGroup from '$lib/components/ui/radio-group';
|
||||
import {
|
||||
CirclePlus,
|
||||
CircleX,
|
||||
Minus,
|
||||
Pencil,
|
||||
Plus,
|
||||
Save,
|
||||
Trash2,
|
||||
Move,
|
||||
Map,
|
||||
Layers2
|
||||
} from 'lucide-svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { settings } from '$lib/db';
|
||||
import { defaultBasemap, type CustomLayer } from '$lib/assets/layers';
|
||||
import { map } from '$lib/stores';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import Sortable from 'sortablejs/Sortable';
|
||||
import { customBasemapUpdate } from './utils';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Separator } from '$lib/components/ui/separator';
|
||||
import * as RadioGroup from '$lib/components/ui/radio-group';
|
||||
import {
|
||||
CirclePlus,
|
||||
CircleX,
|
||||
Minus,
|
||||
Pencil,
|
||||
Plus,
|
||||
Save,
|
||||
Trash2,
|
||||
Move,
|
||||
Map,
|
||||
Layers2
|
||||
} from 'lucide-svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { settings } from '$lib/db';
|
||||
import { defaultBasemap, type CustomLayer } from '$lib/assets/layers';
|
||||
import { map } from '$lib/stores';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import Sortable from 'sortablejs/Sortable';
|
||||
import { customBasemapUpdate } from './utils';
|
||||
|
||||
const {
|
||||
customLayers,
|
||||
selectedBasemapTree,
|
||||
selectedOverlayTree,
|
||||
currentBasemap,
|
||||
previousBasemap,
|
||||
currentOverlays,
|
||||
previousOverlays,
|
||||
customBasemapOrder,
|
||||
customOverlayOrder
|
||||
} = settings;
|
||||
const {
|
||||
customLayers,
|
||||
selectedBasemapTree,
|
||||
selectedOverlayTree,
|
||||
currentBasemap,
|
||||
previousBasemap,
|
||||
currentOverlays,
|
||||
previousOverlays,
|
||||
customBasemapOrder,
|
||||
customOverlayOrder
|
||||
} = settings;
|
||||
|
||||
let name: string = '';
|
||||
let tileUrls: string[] = [''];
|
||||
let maxZoom: number = 20;
|
||||
let layerType: 'basemap' | 'overlay' = 'basemap';
|
||||
let resourceType: 'raster' | 'vector' = 'raster';
|
||||
let name: string = '';
|
||||
let tileUrls: string[] = [''];
|
||||
let maxZoom: number = 20;
|
||||
let layerType: 'basemap' | 'overlay' = 'basemap';
|
||||
let resourceType: 'raster' | 'vector' = 'raster';
|
||||
|
||||
let basemapContainer: HTMLElement;
|
||||
let overlayContainer: HTMLElement;
|
||||
let basemapContainer: HTMLElement;
|
||||
let overlayContainer: HTMLElement;
|
||||
|
||||
let basemapSortable: Sortable;
|
||||
let overlaySortable: Sortable;
|
||||
let basemapSortable: Sortable;
|
||||
let overlaySortable: Sortable;
|
||||
|
||||
onMount(() => {
|
||||
if ($customBasemapOrder.length === 0) {
|
||||
$customBasemapOrder = Object.keys($customLayers).filter(
|
||||
(id) => $customLayers[id].layerType === 'basemap'
|
||||
);
|
||||
}
|
||||
if ($customOverlayOrder.length === 0) {
|
||||
$customOverlayOrder = Object.keys($customLayers).filter(
|
||||
(id) => $customLayers[id].layerType === 'overlay'
|
||||
);
|
||||
}
|
||||
onMount(() => {
|
||||
if ($customBasemapOrder.length === 0) {
|
||||
$customBasemapOrder = Object.keys($customLayers).filter(
|
||||
(id) => $customLayers[id].layerType === 'basemap'
|
||||
);
|
||||
}
|
||||
if ($customOverlayOrder.length === 0) {
|
||||
$customOverlayOrder = Object.keys($customLayers).filter(
|
||||
(id) => $customLayers[id].layerType === 'overlay'
|
||||
);
|
||||
}
|
||||
|
||||
basemapSortable = Sortable.create(basemapContainer, {
|
||||
onSort: (e) => {
|
||||
$customBasemapOrder = basemapSortable.toArray();
|
||||
$selectedBasemapTree.basemaps['custom'] = $customBasemapOrder.reduce((acc, id) => {
|
||||
acc[id] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
});
|
||||
overlaySortable = Sortable.create(overlayContainer, {
|
||||
onSort: (e) => {
|
||||
$customOverlayOrder = overlaySortable.toArray();
|
||||
$selectedOverlayTree.overlays['custom'] = $customOverlayOrder.reduce((acc, id) => {
|
||||
acc[id] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
});
|
||||
basemapSortable = Sortable.create(basemapContainer, {
|
||||
onSort: (e) => {
|
||||
$customBasemapOrder = basemapSortable.toArray();
|
||||
$selectedBasemapTree.basemaps['custom'] = $customBasemapOrder.reduce((acc, id) => {
|
||||
acc[id] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
});
|
||||
overlaySortable = Sortable.create(overlayContainer, {
|
||||
onSort: (e) => {
|
||||
$customOverlayOrder = overlaySortable.toArray();
|
||||
$selectedOverlayTree.overlays['custom'] = $customOverlayOrder.reduce((acc, id) => {
|
||||
acc[id] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
});
|
||||
|
||||
basemapSortable.sort($customBasemapOrder);
|
||||
overlaySortable.sort($customOverlayOrder);
|
||||
});
|
||||
basemapSortable.sort($customBasemapOrder);
|
||||
overlaySortable.sort($customOverlayOrder);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
basemapSortable.destroy();
|
||||
overlaySortable.destroy();
|
||||
});
|
||||
onDestroy(() => {
|
||||
basemapSortable.destroy();
|
||||
overlaySortable.destroy();
|
||||
});
|
||||
|
||||
$: if (tileUrls[0].length > 0) {
|
||||
if (
|
||||
tileUrls[0].includes('.json') ||
|
||||
(tileUrls[0].includes('api.mapbox.com/styles') && !tileUrls[0].includes('tiles'))
|
||||
) {
|
||||
resourceType = 'vector';
|
||||
} else {
|
||||
resourceType = 'raster';
|
||||
}
|
||||
}
|
||||
$: if (tileUrls[0].length > 0) {
|
||||
if (
|
||||
tileUrls[0].includes('.json') ||
|
||||
(tileUrls[0].includes('api.mapbox.com/styles') && !tileUrls[0].includes('tiles'))
|
||||
) {
|
||||
resourceType = 'vector';
|
||||
} else {
|
||||
resourceType = 'raster';
|
||||
}
|
||||
}
|
||||
|
||||
function createLayer() {
|
||||
if (selectedLayerId && $customLayers[selectedLayerId].layerType !== layerType) {
|
||||
deleteLayer(selectedLayerId);
|
||||
}
|
||||
function createLayer() {
|
||||
if (selectedLayerId && $customLayers[selectedLayerId].layerType !== layerType) {
|
||||
deleteLayer(selectedLayerId);
|
||||
}
|
||||
|
||||
if (typeof maxZoom === 'string') {
|
||||
maxZoom = parseInt(maxZoom);
|
||||
}
|
||||
if (typeof maxZoom === 'string') {
|
||||
maxZoom = parseInt(maxZoom);
|
||||
}
|
||||
let is512 = tileUrls.some((url) => url.includes('512'));
|
||||
|
||||
let layerId = selectedLayerId ?? getLayerId();
|
||||
let layer: CustomLayer = {
|
||||
id: layerId,
|
||||
name: name,
|
||||
tileUrls: tileUrls.map((url) => decodeURI(url.trim())),
|
||||
maxZoom: maxZoom,
|
||||
layerType: layerType,
|
||||
resourceType: resourceType,
|
||||
value: ''
|
||||
};
|
||||
let layerId = selectedLayerId ?? getLayerId();
|
||||
let layer: CustomLayer = {
|
||||
id: layerId,
|
||||
name: name,
|
||||
tileUrls: tileUrls.map((url) => decodeURI(url.trim())),
|
||||
maxZoom: maxZoom,
|
||||
layerType: layerType,
|
||||
resourceType: resourceType,
|
||||
value: ''
|
||||
};
|
||||
|
||||
if (resourceType === 'vector') {
|
||||
layer.value = layer.tileUrls[0];
|
||||
} else {
|
||||
layer.value = {
|
||||
version: 8,
|
||||
sources: {
|
||||
[layerId]: {
|
||||
type: 'raster',
|
||||
tiles: layer.tileUrls,
|
||||
tileSize: 256,
|
||||
maxzoom: maxZoom
|
||||
}
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: layerId,
|
||||
type: 'raster',
|
||||
source: layerId
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
$customLayers[layerId] = layer;
|
||||
addLayer(layerId);
|
||||
selectedLayerId = undefined;
|
||||
setDataFromSelectedLayer();
|
||||
}
|
||||
if (resourceType === 'vector') {
|
||||
layer.value = layer.tileUrls[0];
|
||||
} else {
|
||||
layer.value = {
|
||||
version: 8,
|
||||
sources: {
|
||||
[layerId]: {
|
||||
type: 'raster',
|
||||
tiles: layer.tileUrls,
|
||||
tileSize: is512 ? 512 : 256,
|
||||
maxzoom: maxZoom
|
||||
}
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: layerId,
|
||||
type: 'raster',
|
||||
source: layerId
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
$customLayers[layerId] = layer;
|
||||
addLayer(layerId);
|
||||
selectedLayerId = undefined;
|
||||
setDataFromSelectedLayer();
|
||||
}
|
||||
|
||||
function getLayerId() {
|
||||
for (let id = 0; ; id++) {
|
||||
if (!$customLayers.hasOwnProperty(`custom-${id}`)) {
|
||||
return `custom-${id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getLayerId() {
|
||||
for (let id = 0; ; id++) {
|
||||
if (!$customLayers.hasOwnProperty(`custom-${id}`)) {
|
||||
return `custom-${id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addLayer(layerId: string) {
|
||||
if (layerType === 'basemap') {
|
||||
selectedBasemapTree.update(($tree) => {
|
||||
if (!$tree.basemaps.hasOwnProperty('custom')) {
|
||||
$tree.basemaps['custom'] = {};
|
||||
}
|
||||
$tree.basemaps['custom'][layerId] = true;
|
||||
return $tree;
|
||||
});
|
||||
function addLayer(layerId: string) {
|
||||
if (layerType === 'basemap') {
|
||||
selectedBasemapTree.update(($tree) => {
|
||||
if (!$tree.basemaps.hasOwnProperty('custom')) {
|
||||
$tree.basemaps['custom'] = {};
|
||||
}
|
||||
$tree.basemaps['custom'][layerId] = true;
|
||||
return $tree;
|
||||
});
|
||||
|
||||
if ($currentBasemap === layerId) {
|
||||
$customBasemapUpdate++;
|
||||
} else {
|
||||
$currentBasemap = layerId;
|
||||
}
|
||||
if ($currentBasemap === layerId) {
|
||||
$customBasemapUpdate++;
|
||||
} else {
|
||||
$currentBasemap = layerId;
|
||||
}
|
||||
|
||||
if (!$customBasemapOrder.includes(layerId)) {
|
||||
$customBasemapOrder = [...$customBasemapOrder, layerId];
|
||||
}
|
||||
} else {
|
||||
selectedOverlayTree.update(($tree) => {
|
||||
if (!$tree.overlays.hasOwnProperty('custom')) {
|
||||
$tree.overlays['custom'] = {};
|
||||
}
|
||||
$tree.overlays['custom'][layerId] = true;
|
||||
return $tree;
|
||||
});
|
||||
if (!$customBasemapOrder.includes(layerId)) {
|
||||
$customBasemapOrder = [...$customBasemapOrder, layerId];
|
||||
}
|
||||
} else {
|
||||
selectedOverlayTree.update(($tree) => {
|
||||
if (!$tree.overlays.hasOwnProperty('custom')) {
|
||||
$tree.overlays['custom'] = {};
|
||||
}
|
||||
$tree.overlays['custom'][layerId] = true;
|
||||
return $tree;
|
||||
});
|
||||
|
||||
if (
|
||||
$currentOverlays.overlays['custom'] &&
|
||||
$currentOverlays.overlays['custom'][layerId] &&
|
||||
$map
|
||||
) {
|
||||
try {
|
||||
$map.removeImport(layerId);
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to remove sources and layers
|
||||
}
|
||||
}
|
||||
if (
|
||||
$currentOverlays.overlays['custom'] &&
|
||||
$currentOverlays.overlays['custom'][layerId] &&
|
||||
$map
|
||||
) {
|
||||
try {
|
||||
$map.removeImport(layerId);
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to remove sources and layers
|
||||
}
|
||||
}
|
||||
|
||||
if (!$currentOverlays.overlays.hasOwnProperty('custom')) {
|
||||
$currentOverlays.overlays['custom'] = {};
|
||||
}
|
||||
$currentOverlays.overlays['custom'][layerId] = true;
|
||||
if (!$currentOverlays.overlays.hasOwnProperty('custom')) {
|
||||
$currentOverlays.overlays['custom'] = {};
|
||||
}
|
||||
$currentOverlays.overlays['custom'][layerId] = true;
|
||||
|
||||
if (!$customOverlayOrder.includes(layerId)) {
|
||||
$customOverlayOrder = [...$customOverlayOrder, layerId];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$customOverlayOrder.includes(layerId)) {
|
||||
$customOverlayOrder = [...$customOverlayOrder, layerId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryDeleteLayer(node: any, id: string): any {
|
||||
if (node.hasOwnProperty(id)) {
|
||||
delete node[id];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
function tryDeleteLayer(node: any, id: string): any {
|
||||
if (node.hasOwnProperty(id)) {
|
||||
delete node[id];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function deleteLayer(layerId: string) {
|
||||
let layer = $customLayers[layerId];
|
||||
if (layer.layerType === 'basemap') {
|
||||
if (layerId === $currentBasemap) {
|
||||
$currentBasemap = defaultBasemap;
|
||||
}
|
||||
if (layerId === $previousBasemap) {
|
||||
$previousBasemap = defaultBasemap;
|
||||
}
|
||||
function deleteLayer(layerId: string) {
|
||||
let layer = $customLayers[layerId];
|
||||
if (layer.layerType === 'basemap') {
|
||||
if (layerId === $currentBasemap) {
|
||||
$currentBasemap = defaultBasemap;
|
||||
}
|
||||
if (layerId === $previousBasemap) {
|
||||
$previousBasemap = defaultBasemap;
|
||||
}
|
||||
|
||||
$selectedBasemapTree.basemaps['custom'] = tryDeleteLayer(
|
||||
$selectedBasemapTree.basemaps['custom'],
|
||||
layerId
|
||||
);
|
||||
if (Object.keys($selectedBasemapTree.basemaps['custom']).length === 0) {
|
||||
$selectedBasemapTree.basemaps = tryDeleteLayer(
|
||||
$selectedBasemapTree.basemaps,
|
||||
'custom'
|
||||
);
|
||||
}
|
||||
$customBasemapOrder = $customBasemapOrder.filter((id) => id !== layerId);
|
||||
} else {
|
||||
$currentOverlays.overlays['custom'][layerId] = false;
|
||||
if ($previousOverlays.overlays['custom']) {
|
||||
$previousOverlays.overlays['custom'] = tryDeleteLayer(
|
||||
$previousOverlays.overlays['custom'],
|
||||
layerId
|
||||
);
|
||||
}
|
||||
$selectedBasemapTree.basemaps['custom'] = tryDeleteLayer(
|
||||
$selectedBasemapTree.basemaps['custom'],
|
||||
layerId
|
||||
);
|
||||
if (Object.keys($selectedBasemapTree.basemaps['custom']).length === 0) {
|
||||
$selectedBasemapTree.basemaps = tryDeleteLayer($selectedBasemapTree.basemaps, 'custom');
|
||||
}
|
||||
$customBasemapOrder = $customBasemapOrder.filter((id) => id !== layerId);
|
||||
} else {
|
||||
$currentOverlays.overlays['custom'][layerId] = false;
|
||||
if ($previousOverlays.overlays['custom']) {
|
||||
$previousOverlays.overlays['custom'] = tryDeleteLayer(
|
||||
$previousOverlays.overlays['custom'],
|
||||
layerId
|
||||
);
|
||||
}
|
||||
|
||||
$selectedOverlayTree.overlays['custom'] = tryDeleteLayer(
|
||||
$selectedOverlayTree.overlays['custom'],
|
||||
layerId
|
||||
);
|
||||
if (Object.keys($selectedOverlayTree.overlays['custom']).length === 0) {
|
||||
$selectedOverlayTree.overlays = tryDeleteLayer(
|
||||
$selectedOverlayTree.overlays,
|
||||
'custom'
|
||||
);
|
||||
}
|
||||
$customOverlayOrder = $customOverlayOrder.filter((id) => id !== layerId);
|
||||
$selectedOverlayTree.overlays['custom'] = tryDeleteLayer(
|
||||
$selectedOverlayTree.overlays['custom'],
|
||||
layerId
|
||||
);
|
||||
if (Object.keys($selectedOverlayTree.overlays['custom']).length === 0) {
|
||||
$selectedOverlayTree.overlays = tryDeleteLayer($selectedOverlayTree.overlays, 'custom');
|
||||
}
|
||||
$customOverlayOrder = $customOverlayOrder.filter((id) => id !== layerId);
|
||||
|
||||
if (
|
||||
$currentOverlays.overlays['custom'] &&
|
||||
$currentOverlays.overlays['custom'][layerId] &&
|
||||
$map
|
||||
) {
|
||||
try {
|
||||
$map.removeImport(layerId);
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to remove sources and layers
|
||||
}
|
||||
}
|
||||
}
|
||||
$customLayers = tryDeleteLayer($customLayers, layerId);
|
||||
}
|
||||
if (
|
||||
$currentOverlays.overlays['custom'] &&
|
||||
$currentOverlays.overlays['custom'][layerId] &&
|
||||
$map
|
||||
) {
|
||||
try {
|
||||
$map.removeImport(layerId);
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to remove sources and layers
|
||||
}
|
||||
}
|
||||
}
|
||||
$customLayers = tryDeleteLayer($customLayers, layerId);
|
||||
}
|
||||
|
||||
let selectedLayerId: string | undefined = undefined;
|
||||
let selectedLayerId: string | undefined = undefined;
|
||||
|
||||
function setDataFromSelectedLayer() {
|
||||
if (selectedLayerId) {
|
||||
const layer = $customLayers[selectedLayerId];
|
||||
name = layer.name;
|
||||
tileUrls = layer.tileUrls;
|
||||
maxZoom = layer.maxZoom;
|
||||
layerType = layer.layerType;
|
||||
resourceType = layer.resourceType;
|
||||
} else {
|
||||
name = '';
|
||||
tileUrls = [''];
|
||||
maxZoom = 20;
|
||||
layerType = 'basemap';
|
||||
resourceType = 'raster';
|
||||
}
|
||||
}
|
||||
function setDataFromSelectedLayer() {
|
||||
if (selectedLayerId) {
|
||||
const layer = $customLayers[selectedLayerId];
|
||||
name = layer.name;
|
||||
tileUrls = layer.tileUrls;
|
||||
maxZoom = layer.maxZoom;
|
||||
layerType = layer.layerType;
|
||||
resourceType = layer.resourceType;
|
||||
} else {
|
||||
name = '';
|
||||
tileUrls = [''];
|
||||
maxZoom = 20;
|
||||
layerType = 'basemap';
|
||||
resourceType = 'raster';
|
||||
}
|
||||
}
|
||||
|
||||
$: selectedLayerId, setDataFromSelectedLayer();
|
||||
$: selectedLayerId, setDataFromSelectedLayer();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
{#if $customBasemapOrder.length > 0}
|
||||
<div class="flex flex-row items-center gap-1 font-semibold mb-2">
|
||||
<Map size="16" />
|
||||
{$_('layers.label.basemaps')}
|
||||
<div class="grow">
|
||||
<Separator />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
bind:this={basemapContainer}
|
||||
class="ml-1.5 flex flex-col gap-1 {$customBasemapOrder.length > 0 ? 'mb-2' : ''}"
|
||||
>
|
||||
{#each $customBasemapOrder as id (id)}
|
||||
<div class="flex flex-row items-center gap-2" data-id={id}>
|
||||
<Move size="12" />
|
||||
<span class="grow">{$customLayers[id].name}</span>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
|
||||
<Pencil size="16" />
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
|
||||
<Trash2 size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $customOverlayOrder.length > 0}
|
||||
<div class="flex flex-row items-center gap-1 font-semibold mb-2">
|
||||
<Layers2 size="16" />
|
||||
{$_('layers.label.overlays')}
|
||||
<div class="grow">
|
||||
<Separator />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
bind:this={overlayContainer}
|
||||
class="ml-1.5 flex flex-col gap-1 {$customOverlayOrder.length > 0 ? 'mb-2' : ''}"
|
||||
>
|
||||
{#each $customOverlayOrder as id (id)}
|
||||
<div class="flex flex-row items-center gap-2" data-id={id}>
|
||||
<Move size="12" />
|
||||
<span class="grow">{$customLayers[id].name}</span>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
|
||||
<Pencil size="16" />
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
|
||||
<Trash2 size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $customBasemapOrder.length > 0}
|
||||
<div class="flex flex-row items-center gap-1 font-semibold mb-2">
|
||||
<Map size="16" />
|
||||
{$_('layers.label.basemaps')}
|
||||
<div class="grow">
|
||||
<Separator />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
bind:this={basemapContainer}
|
||||
class="ml-1.5 flex flex-col gap-1 {$customBasemapOrder.length > 0 ? 'mb-2' : ''}"
|
||||
>
|
||||
{#each $customBasemapOrder as id (id)}
|
||||
<div class="flex flex-row items-center gap-2" data-id={id}>
|
||||
<Move size="12" />
|
||||
<span class="grow">{$customLayers[id].name}</span>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
|
||||
<Pencil size="16" />
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
|
||||
<Trash2 size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $customOverlayOrder.length > 0}
|
||||
<div class="flex flex-row items-center gap-1 font-semibold mb-2">
|
||||
<Layers2 size="16" />
|
||||
{$_('layers.label.overlays')}
|
||||
<div class="grow">
|
||||
<Separator />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
bind:this={overlayContainer}
|
||||
class="ml-1.5 flex flex-col gap-1 {$customOverlayOrder.length > 0 ? 'mb-2' : ''}"
|
||||
>
|
||||
{#each $customOverlayOrder as id (id)}
|
||||
<div class="flex flex-row items-center gap-2" data-id={id}>
|
||||
<Move size="12" />
|
||||
<span class="grow">{$customLayers[id].name}</span>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = id)} class="p-1 h-7">
|
||||
<Pencil size="16" />
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => deleteLayer(id)} class="p-1 h-7">
|
||||
<Trash2 size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header class="p-3">
|
||||
<Card.Title class="text-base">
|
||||
{#if selectedLayerId}
|
||||
{$_('layers.custom_layers.edit')}
|
||||
{:else}
|
||||
{$_('layers.custom_layers.new')}
|
||||
{/if}
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content class="p-3 pt-0">
|
||||
<fieldset class="flex flex-col gap-2">
|
||||
<Label for="name">{$_('menu.metadata.name')}</Label>
|
||||
<Input bind:value={name} id="name" class="h-8" />
|
||||
<Label for="url">{$_('layers.custom_layers.urls')}</Label>
|
||||
{#each tileUrls as url, i}
|
||||
<div class="flex flex-row gap-2">
|
||||
<Input
|
||||
bind:value={tileUrls[i]}
|
||||
id="url"
|
||||
class="h-8"
|
||||
placeholder={$_('layers.custom_layers.url_placeholder')}
|
||||
/>
|
||||
{#if tileUrls.length > 1}
|
||||
<Button
|
||||
on:click={() =>
|
||||
(tileUrls = tileUrls.filter((_, index) => index !== i))}
|
||||
variant="outline"
|
||||
class="p-1 h-8"
|
||||
>
|
||||
<Minus size="16" />
|
||||
</Button>
|
||||
{/if}
|
||||
{#if i === tileUrls.length - 1}
|
||||
<Button
|
||||
on:click={() => (tileUrls = [...tileUrls, ''])}
|
||||
variant="outline"
|
||||
class="p-1 h-8"
|
||||
>
|
||||
<Plus size="16" />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if resourceType === 'raster'}
|
||||
<Label for="maxZoom">{$_('layers.custom_layers.max_zoom')}</Label>
|
||||
<Input
|
||||
type="number"
|
||||
bind:value={maxZoom}
|
||||
id="maxZoom"
|
||||
min={0}
|
||||
max={22}
|
||||
class="h-8"
|
||||
/>
|
||||
{/if}
|
||||
<Label>{$_('layers.custom_layers.layer_type')}</Label>
|
||||
<RadioGroup.Root bind:value={layerType} class="flex flex-row">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="basemap" id="basemap" />
|
||||
<Label for="basemap">{$_('layers.custom_layers.basemap')}</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="overlay" id="overlay" />
|
||||
<Label for="overlay">{$_('layers.custom_layers.overlay')}</Label>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
{#if selectedLayerId}
|
||||
<div class="mt-2 flex flex-row gap-2">
|
||||
<Button variant="outline" on:click={createLayer} class="grow">
|
||||
<Save size="16" class="mr-1" />
|
||||
{$_('layers.custom_layers.update')}
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = undefined)}>
|
||||
<CircleX size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<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>
|
||||
<Card.Root>
|
||||
<Card.Header class="p-3">
|
||||
<Card.Title class="text-base">
|
||||
{#if selectedLayerId}
|
||||
{$_('layers.custom_layers.edit')}
|
||||
{:else}
|
||||
{$_('layers.custom_layers.new')}
|
||||
{/if}
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content class="p-3 pt-0">
|
||||
<fieldset class="flex flex-col gap-2">
|
||||
<Label for="name">{$_('menu.metadata.name')}</Label>
|
||||
<Input bind:value={name} id="name" class="h-8" />
|
||||
<Label for="url">{$_('layers.custom_layers.urls')}</Label>
|
||||
{#each tileUrls as url, i}
|
||||
<div class="flex flex-row gap-2">
|
||||
<Input
|
||||
bind:value={tileUrls[i]}
|
||||
id="url"
|
||||
class="h-8"
|
||||
placeholder={$_('layers.custom_layers.url_placeholder')}
|
||||
/>
|
||||
{#if tileUrls.length > 1}
|
||||
<Button
|
||||
on:click={() => (tileUrls = tileUrls.filter((_, index) => index !== i))}
|
||||
variant="outline"
|
||||
class="p-1 h-8"
|
||||
>
|
||||
<Minus size="16" />
|
||||
</Button>
|
||||
{/if}
|
||||
{#if i === tileUrls.length - 1}
|
||||
<Button
|
||||
on:click={() => (tileUrls = [...tileUrls, ''])}
|
||||
variant="outline"
|
||||
class="p-1 h-8"
|
||||
>
|
||||
<Plus size="16" />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if resourceType === 'raster'}
|
||||
<Label for="maxZoom">{$_('layers.custom_layers.max_zoom')}</Label>
|
||||
<Input type="number" bind:value={maxZoom} id="maxZoom" min={0} max={22} class="h-8" />
|
||||
{/if}
|
||||
<Label>{$_('layers.custom_layers.layer_type')}</Label>
|
||||
<RadioGroup.Root bind:value={layerType} class="flex flex-row">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="basemap" id="basemap" />
|
||||
<Label for="basemap">{$_('layers.custom_layers.basemap')}</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="overlay" id="overlay" />
|
||||
<Label for="overlay">{$_('layers.custom_layers.overlay')}</Label>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
{#if selectedLayerId}
|
||||
<div class="mt-2 flex flex-row gap-2">
|
||||
<Button variant="outline" on:click={createLayer} class="grow">
|
||||
<Save size="16" class="mr-1" />
|
||||
{$_('layers.custom_layers.update')}
|
||||
</Button>
|
||||
<Button variant="outline" on:click={() => (selectedLayerId = undefined)}>
|
||||
<CircleX size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<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>
|
||||
|
@@ -13,7 +13,6 @@
|
||||
import { get, writable } from 'svelte/store';
|
||||
import { customBasemapUpdate, getLayers } from './utils';
|
||||
import { OverpassLayer } from './OverpassLayer';
|
||||
import OverpassPopup from './OverpassPopup.svelte';
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let overpassLayer: OverpassLayer;
|
||||
@@ -34,7 +33,7 @@
|
||||
if ($map) {
|
||||
let basemap = basemaps.hasOwnProperty($currentBasemap)
|
||||
? basemaps[$currentBasemap]
|
||||
: $customLayers[$currentBasemap]?.value ?? basemaps[defaultBasemap];
|
||||
: ($customLayers[$currentBasemap]?.value ?? basemaps[defaultBasemap]);
|
||||
$map.removeImport('basemap');
|
||||
if (typeof basemap === 'string') {
|
||||
$map.addImport({ id: 'basemap', url: basemap }, 'overlays');
|
||||
@@ -85,18 +84,21 @@
|
||||
}
|
||||
|
||||
function updateOverlays() {
|
||||
if ($map && $currentOverlays) {
|
||||
if ($map && $currentOverlays && $opacities) {
|
||||
let overlayLayers = getLayers($currentOverlays);
|
||||
try {
|
||||
let activeOverlays = $map
|
||||
.getStyle()
|
||||
.imports.filter((i) => i.id !== 'basemap' && i.id !== 'overlays');
|
||||
let toRemove = activeOverlays.filter((i) => !overlayLayers[i.id]);
|
||||
toRemove.forEach((i) => {
|
||||
$map.removeImport(i.id);
|
||||
let activeOverlays = $map.getStyle().imports.reduce((acc, i) => {
|
||||
if (!['basemap', 'overlays', 'glyphs-and-sprite'].includes(i.id)) {
|
||||
acc[i.id] = i;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
let toRemove = Object.keys(activeOverlays).filter((id) => !overlayLayers[id]);
|
||||
toRemove.forEach((id) => {
|
||||
$map.removeImport(id);
|
||||
});
|
||||
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);
|
||||
toAdd.forEach((id) => {
|
||||
addOverlay(id);
|
||||
@@ -107,7 +109,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if ($map && $currentOverlays) {
|
||||
$: if ($map && $currentOverlays && $opacities) {
|
||||
updateOverlays();
|
||||
}
|
||||
|
||||
@@ -130,7 +132,9 @@
|
||||
});
|
||||
currentBasemap.subscribe((value) => {
|
||||
// Updates coming from the database, or from the user swapping basemaps
|
||||
selectedBasemap.set(value);
|
||||
if (value !== get(selectedBasemap)) {
|
||||
selectedBasemap.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
let open = false;
|
||||
@@ -209,8 +213,6 @@
|
||||
</div>
|
||||
</CustomControl>
|
||||
|
||||
<OverpassPopup />
|
||||
|
||||
<svelte:window
|
||||
on:click={(e) => {
|
||||
if (open && !cancelEvents && !container.contains(e.target)) {
|
||||
|
@@ -157,15 +157,16 @@
|
||||
max={1}
|
||||
step={0.1}
|
||||
disabled={$selectedOverlay === undefined}
|
||||
onValueChange={() => {
|
||||
onValueChange={(value) => {
|
||||
if ($selectedOverlay) {
|
||||
$opacities[$selectedOverlay.value] = $overlayOpacity[0];
|
||||
if ($map) {
|
||||
if ($map.getLayer($selectedOverlay.value)) {
|
||||
$map.removeLayer($selectedOverlay.value);
|
||||
$currentOverlays = $currentOverlays;
|
||||
if ($map && isSelected($currentOverlays, $selectedOverlay.value)) {
|
||||
try {
|
||||
$map.removeImport($selectedOverlay.value);
|
||||
} catch (e) {
|
||||
// No reliable way to check if the map is ready to remove sources and layers
|
||||
}
|
||||
}
|
||||
$opacities[$selectedOverlay.value] = value[0];
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import SphericalMercator from "@mapbox/sphericalmercator";
|
||||
import { getLayers } from "./utils";
|
||||
import mapboxgl from "mapbox-gl";
|
||||
import { get, writable } from "svelte/store";
|
||||
import { liveQuery } from "dexie";
|
||||
import { db, settings } from "$lib/db";
|
||||
import { overpassQueryData } from "$lib/assets/layers";
|
||||
import { MapPopup } from "$lib/components/MapPopup";
|
||||
|
||||
const {
|
||||
currentOverpassQueries
|
||||
@@ -14,14 +14,6 @@ const mercator = new SphericalMercator({
|
||||
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: [] });
|
||||
|
||||
liveQuery(() => db.overpassdata.toArray()).subscribe((pois) => {
|
||||
@@ -34,6 +26,7 @@ export class OverpassLayer {
|
||||
queryZoom = 12;
|
||||
expirationTime = 7 * 24 * 3600 * 1000;
|
||||
map: mapboxgl.Map;
|
||||
popup: MapPopup;
|
||||
|
||||
currentQueries: Set<string> = new Set();
|
||||
nextQueries: Map<string, { x: number, y: number, queries: string[] }> = new Map();
|
||||
@@ -42,10 +35,15 @@ export class OverpassLayer {
|
||||
queryIfNeededBinded = this.queryIfNeeded.bind(this);
|
||||
updateBinded = this.update.bind(this);
|
||||
onHoverBinded = this.onHover.bind(this);
|
||||
maybeHidePopupBinded = this.maybeHidePopup.bind(this);
|
||||
|
||||
constructor(map: mapboxgl.Map) {
|
||||
this.map = map;
|
||||
this.popup = new MapPopup(map, {
|
||||
closeButton: false,
|
||||
focusAfterOpen: false,
|
||||
maxWidth: undefined,
|
||||
offset: 15,
|
||||
});
|
||||
}
|
||||
|
||||
add() {
|
||||
@@ -125,27 +123,12 @@ export class OverpassLayer {
|
||||
}
|
||||
|
||||
onHover(e: any) {
|
||||
overpassPopupPOI.set({
|
||||
...e.features[0].properties,
|
||||
sym: overpassQueryData[e.features[0].properties.query].symbol ?? ''
|
||||
this.popup.setItem({
|
||||
item: {
|
||||
...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]) {
|
||||
|
@@ -1,102 +1,95 @@
|
||||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { overpassPopup, overpassPopupPOI } from './OverpassLayer';
|
||||
import { selection } from '$lib/components/file-list/Selection';
|
||||
import { PencilLine, MapPin } from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
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;
|
||||
|
||||
onMount(() => {
|
||||
overpassPopup.setDOMContent(popupElement);
|
||||
popupElement.classList.remove('hidden');
|
||||
});
|
||||
export let poi: PopupItem<any>;
|
||||
|
||||
let tags = {};
|
||||
let name = '';
|
||||
$: if ($overpassPopupPOI) {
|
||||
tags = JSON.parse($overpassPopupPOI.tags);
|
||||
$: if (poi) {
|
||||
tags = JSON.parse(poi.item.tags);
|
||||
if (tags.name !== undefined && tags.name !== '') {
|
||||
name = tags.name;
|
||||
} else {
|
||||
name = $_(`layers.label.${$overpassPopupPOI.query}`);
|
||||
name = $_(`layers.label.${poi.item.query}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={popupElement} class="hidden">
|
||||
{#if $overpassPopupPOI}
|
||||
<Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]">
|
||||
<Card.Header class="p-0">
|
||||
<Card.Title class="text-md">
|
||||
<div class="flex flex-row gap-3">
|
||||
<div class="flex flex-col">
|
||||
{name}
|
||||
<div class="text-muted-foreground text-sm font-normal">
|
||||
{$overpassPopupPOI.lat.toFixed(6)}° {$overpassPopupPOI.lon.toFixed(6)}°
|
||||
</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>
|
||||
<Card.Root class="border-none shadow-md text-base p-2 max-w-[50dvw]">
|
||||
<Card.Header class="p-0">
|
||||
<Card.Title class="text-md">
|
||||
<div class="flex flex-row gap-3">
|
||||
<div class="flex flex-col">
|
||||
{name}
|
||||
<div class="text-muted-foreground text-sm font-normal">
|
||||
{poi.item.lat.toFixed(6)}° {poi.item.lon.toFixed(6)}°
|
||||
</div>
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
</div>
|
||||
<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']}
|
||||
<div class="w-full rounded-md overflow-clip my-2 max-w-96 mx-auto">
|
||||
<!-- svelte-ignore a11y-missing-attribute -->
|
||||
<img src={tags.image ?? tags['image:0']} />
|
||||
</div>
|
||||
{/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">
|
||||
{#each Object.entries(tags) as [key, value]}
|
||||
{#if key !== 'name' && !key.includes('image')}
|
||||
<span class="font-mono">{key}</span>
|
||||
{#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>
|
||||
{:else if key === 'phone' || key === 'contact:phone'}
|
||||
<a href={'tel:' + value} class="text-link underline">{value}</a>
|
||||
{:else if key === 'email' || key === 'contact:email'}
|
||||
<a href={'mailto:' + value} class="text-link underline">{value}</a>
|
||||
{:else}
|
||||
<span>{value}</span>
|
||||
{/if}
|
||||
<div class="grid grid-cols-[auto_auto] gap-x-3">
|
||||
{#each Object.entries(tags) as [key, value]}
|
||||
{#if key !== 'name' && !key.includes('image')}
|
||||
<span class="font-mono">{key}</span>
|
||||
{#if key === 'website' || key.startsWith('website:') || key === 'contact:website' || key === 'contact:facebook' || key === 'contact:instagram' || key === 'contact:twitter'}
|
||||
<a href={value} target="_blank" class="text-link underline">{value}</a>
|
||||
{:else if key === 'phone' || key === 'contact:phone'}
|
||||
<a href={'tel:' + value} class="text-link underline">{value}</a>
|
||||
{:else if key === 'email' || key === 'contact:email'}
|
||||
<a href={'mailto:' + value} class="text-link underline">{value}</a>
|
||||
{:else}
|
||||
<span>{value}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<Button
|
||||
class="mt-2"
|
||||
variant="outline"
|
||||
disabled={$selection.size === 0}
|
||||
on:click={() => {
|
||||
let desc = Object.entries(tags)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n');
|
||||
dbUtils.addOrUpdateWaypoint({
|
||||
attributes: {
|
||||
lat: $overpassPopupPOI.lat,
|
||||
lon: $overpassPopupPOI.lon
|
||||
},
|
||||
name: name,
|
||||
desc: desc,
|
||||
cmt: desc,
|
||||
sym: $overpassPopupPOI.sym
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MapPin size="16" class="mr-1" />
|
||||
{$_('toolbar.waypoint.add')}
|
||||
</Button>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<Button
|
||||
class="mt-2"
|
||||
variant="outline"
|
||||
disabled={$selection.size === 0}
|
||||
on:click={() => {
|
||||
let desc = Object.entries(tags)
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join('\n');
|
||||
dbUtils.addOrUpdateWaypoint({
|
||||
attributes: {
|
||||
lat: poi.item.lat,
|
||||
lon: poi.item.lon
|
||||
},
|
||||
name: name,
|
||||
desc: desc,
|
||||
cmt: desc,
|
||||
sym: poi.item.sym
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MapPin size="16" class="mr-1" />
|
||||
{$_('toolbar.waypoint.add')}
|
||||
</Button>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
@@ -1,16 +1,17 @@
|
||||
import mapboxgl from "mapbox-gl";
|
||||
import { Viewer } from 'mapillary-js/dist/mapillary.module';
|
||||
import mapboxgl, { type LayerSpecification, type VectorSourceSpecification } from "mapbox-gl";
|
||||
import { Viewer, type ViewerBearingEvent } from 'mapillary-js/dist/mapillary.module';
|
||||
import 'mapillary-js/dist/mapillary.css';
|
||||
import { resetCursor, setPointerCursor } from "$lib/utils";
|
||||
import type { Writable } from "svelte/store";
|
||||
|
||||
const mapillarySource = {
|
||||
const mapillarySource: VectorSourceSpecification = {
|
||||
type: 'vector',
|
||||
tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_computed_public/2/{z}/{x}/{y}?access_token=MLY|4381405525255083|3204871ec181638c3c31320490f03011'],
|
||||
minzoom: 6,
|
||||
maxzoom: 14,
|
||||
};
|
||||
|
||||
const mapillarySequenceLayer = {
|
||||
const mapillarySequenceLayer: LayerSpecification = {
|
||||
id: 'mapillary-sequence',
|
||||
type: 'line',
|
||||
source: 'mapillary',
|
||||
@@ -26,7 +27,7 @@ const mapillarySequenceLayer = {
|
||||
},
|
||||
};
|
||||
|
||||
const mapillaryImageLayer = {
|
||||
const mapillaryImageLayer: LayerSpecification = {
|
||||
id: 'mapillary-image',
|
||||
type: 'circle',
|
||||
source: 'mapillary',
|
||||
@@ -40,35 +41,56 @@ const mapillaryImageLayer = {
|
||||
|
||||
export class MapillaryLayer {
|
||||
map: mapboxgl.Map;
|
||||
popup: mapboxgl.Popup;
|
||||
marker: mapboxgl.Marker;
|
||||
viewer: Viewer;
|
||||
|
||||
active = false;
|
||||
popupOpen: Writable<boolean>;
|
||||
|
||||
addBinded = this.add.bind(this);
|
||||
onMouseEnterBinded = this.onMouseEnter.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.viewer = new Viewer({
|
||||
accessToken: 'MLY|4381405525255083|3204871ec181638c3c31320490f03011',
|
||||
container,
|
||||
});
|
||||
container.classList.remove('hidden');
|
||||
|
||||
this.popup = new mapboxgl.Popup({
|
||||
closeButton: false,
|
||||
maxWidth: container.style.width,
|
||||
}).setDOMContent(container);
|
||||
const element = document.createElement('div');
|
||||
element.className = 'mapboxgl-user-location mapboxgl-user-location-show-heading';
|
||||
const dot = document.createElement('div');
|
||||
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 () => {
|
||||
if (this.popup.isOpen()) {
|
||||
if (this.active) {
|
||||
popupOpen.set(true);
|
||||
let latLng = await this.viewer.getPosition();
|
||||
this.popup.setLngLat(latLng);
|
||||
if (!this.map.getBounds().contains(latLng)) {
|
||||
this.marker.setLngLat(latLng).addTo(this.map);
|
||||
if (!this.map.getBounds()?.contains(latLng)) {
|
||||
this.map.panTo(latLng);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.viewer.on('bearing', (e: ViewerBearingEvent) => {
|
||||
if (this.active) {
|
||||
this.marker.setRotation(e.bearing);
|
||||
}
|
||||
});
|
||||
|
||||
this.popupOpen = popupOpen;
|
||||
}
|
||||
|
||||
add() {
|
||||
@@ -101,15 +123,19 @@ export class MapillaryLayer {
|
||||
this.map.removeSource('mapillary');
|
||||
}
|
||||
|
||||
this.popup.remove();
|
||||
this.marker.remove();
|
||||
this.popupOpen.set(false);
|
||||
}
|
||||
|
||||
closePopup() {
|
||||
this.popup.remove();
|
||||
this.active = false;
|
||||
this.marker.remove();
|
||||
this.popupOpen.set(false);
|
||||
}
|
||||
|
||||
onMouseEnter(e: mapboxgl.MapLayerMouseEvent) {
|
||||
this.popup.addTo(this.map).setLngLat(e.lngLat);
|
||||
onMouseEnter(e: mapboxgl.MapMouseEvent) {
|
||||
this.active = true;
|
||||
|
||||
this.viewer.resize();
|
||||
this.viewer.moveTo(e.features[0].properties.id);
|
||||
|
||||
|
@@ -8,16 +8,18 @@
|
||||
import { map, streetViewEnabled } from '$lib/stores';
|
||||
import { settings } from '$lib/db';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const { streetViewSource } = settings;
|
||||
|
||||
let googleRedirect: GoogleRedirect;
|
||||
let mapillaryLayer: MapillaryLayer;
|
||||
let mapillaryOpen = writable(false);
|
||||
let container: HTMLElement;
|
||||
|
||||
$: if ($map) {
|
||||
googleRedirect = new GoogleRedirect($map);
|
||||
mapillaryLayer = new MapillaryLayer($map, container);
|
||||
mapillaryLayer = new MapillaryLayer($map, container, mapillaryOpen);
|
||||
}
|
||||
|
||||
$: if (mapillaryLayer) {
|
||||
@@ -53,7 +55,9 @@
|
||||
|
||||
<div
|
||||
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-no-static-element-interactions -->
|
||||
|
@@ -11,15 +11,18 @@
|
||||
import { selection } from '$lib/components/file-list/Selection';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
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 { _, locale } from 'svelte-i18n';
|
||||
import { dbUtils, getFile } from '$lib/db';
|
||||
import { Group } from 'lucide-svelte';
|
||||
import { getURLForLanguage } from '$lib/utils';
|
||||
import Shortcut from '$lib/components/Shortcut.svelte';
|
||||
import { gpxStatistics } from '$lib/stores';
|
||||
|
||||
let canMergeTraces = false;
|
||||
let canMergeContents = false;
|
||||
let removeGaps = false;
|
||||
|
||||
$: if ($selection.size > 1) {
|
||||
canMergeTraces = true;
|
||||
@@ -56,22 +59,31 @@
|
||||
|
||||
<div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}">
|
||||
<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} />
|
||||
{$_('toolbar.merge.merge_traces')}
|
||||
</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} />
|
||||
{$_('toolbar.merge.merge_contents')}
|
||||
</Label>
|
||||
</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
|
||||
variant="outline"
|
||||
class="whitespace-normal h-fit"
|
||||
disabled={(mergeType === MergeType.TRACES && !canMergeTraces) ||
|
||||
(mergeType === MergeType.CONTENTS && !canMergeContents)}
|
||||
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" />
|
||||
|
@@ -3,6 +3,7 @@
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as RadioGroup from '$lib/components/ui/radio-group';
|
||||
import Help from '$lib/components/Help.svelte';
|
||||
import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte';
|
||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||
@@ -19,16 +20,22 @@
|
||||
RouteOff,
|
||||
Repeat,
|
||||
SquareArrowUpLeft,
|
||||
SquareArrowOutDownRight
|
||||
SquareArrowOutDownRight,
|
||||
Timer
|
||||
} 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 { brouterProfiles, routingProfileSelectItem } from './Routing';
|
||||
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import { RoutingControls } from './RoutingControls';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
import { fileObservers } from '$lib/db';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { getOrderedSelection, selection } from '$lib/components/file-list/Selection';
|
||||
@@ -40,6 +47,7 @@
|
||||
type ListItem
|
||||
} from '$lib/components/file-list/FileList';
|
||||
import { flyAndScale, getURLForLanguage, resetCursor, setCrosshairCursor } from '$lib/utils';
|
||||
import { TimestampsMode } from '$lib/types';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { TrackPoint } from 'gpx';
|
||||
|
||||
@@ -49,7 +57,7 @@
|
||||
export let popupElement: HTMLElement | undefined = undefined;
|
||||
let selectedItem: ListItem | null = null;
|
||||
|
||||
const { privateRoads, routing } = settings;
|
||||
const { privateRoads, routing, timestampsMode } = settings;
|
||||
|
||||
$: if ($map && popup && popupElement) {
|
||||
// remove controls for deleted files
|
||||
@@ -161,7 +169,7 @@
|
||||
</Select.Root>
|
||||
</Label>
|
||||
<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" />
|
||||
{$_('toolbar.routing.allow_private')}
|
||||
</span>
|
||||
@@ -169,6 +177,28 @@
|
||||
</Label>
|
||||
</div>
|
||||
{/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 class="flex flex-row flex-wrap justify-center gap-1">
|
||||
<ButtonWithTooltip
|
||||
|
@@ -3,7 +3,6 @@ import { TrackPoint, distance } from "gpx";
|
||||
import { derived, get, writable } from "svelte/store";
|
||||
import { settings } from "$lib/db";
|
||||
import { _, isLoading, locale } from "svelte-i18n";
|
||||
import { map } from "$lib/stores";
|
||||
import { getElevation } from "$lib/utils";
|
||||
|
||||
const { routing, routingProfile, privateRoads } = settings;
|
||||
@@ -66,7 +65,7 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
|
||||
const latIdx = messages[0].indexOf("Latitude");
|
||||
const tagIdx = messages[0].indexOf("WayTags");
|
||||
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++) {
|
||||
let coord = coordinates[i];
|
||||
@@ -83,25 +82,26 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
|
||||
coordinates[i][1] == Number(messages[messageIdx][latIdx]) / 1000000) {
|
||||
messageIdx++;
|
||||
|
||||
if (messageIdx == messages.length) surface = undefined;
|
||||
else surface = getSurface(messages[messageIdx][tagIdx]);
|
||||
if (messageIdx == messages.length) tags = {};
|
||||
else tags = getTags(messages[messageIdx][tagIdx]);
|
||||
}
|
||||
|
||||
if (surface) {
|
||||
route[route.length - 1].setSurface(surface);
|
||||
}
|
||||
route[route.length - 1].setExtensions(tags);
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
function getSurface(message: string): string | undefined {
|
||||
function getTags(message: string): { [key: string]: string } {
|
||||
const fields = message.split(" ");
|
||||
for (let i = 0; i < fields.length; i++) if (fields[i].startsWith("surface=")) {
|
||||
return fields[i].substring(8);
|
||||
let tags: { [key: string]: string } = {};
|
||||
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[]> {
|
||||
let route: TrackPoint[] = [];
|
||||
|
@@ -2,15 +2,16 @@ import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedP
|
||||
import { get, writable, type Readable } from "svelte/store";
|
||||
import mapboxgl from "mapbox-gl";
|
||||
import { route } from "./Routing";
|
||||
|
||||
import { toast } from "svelte-sonner";
|
||||
|
||||
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 { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
|
||||
import { currentTool, streetViewEnabled, Tool } from "$lib/stores";
|
||||
import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils";
|
||||
import { TimestampsMode } from "$lib/types";
|
||||
|
||||
const { streetViewSource, timestampsMode } = settings;
|
||||
|
||||
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
|
||||
if (get(streetViewEnabled)) {
|
||||
if (get(streetViewEnabled) && get(streetViewSource) === 'google') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -574,9 +575,11 @@ export class RoutingControls {
|
||||
}
|
||||
|
||||
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._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
|
||||
response[0].time = anchors[0].point.time;
|
||||
anchors[0].point = response[0]; // replace the first anchor
|
||||
anchors[0].point._data.index = segment.trkpt.length - 1;
|
||||
} 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
|
||||
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._data.index = segment.trkpt.length - 1;
|
||||
} else {
|
||||
@@ -608,20 +612,40 @@ export class RoutingControls {
|
||||
let startTime = anchors[0].point.time;
|
||||
|
||||
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;
|
||||
for (let i = 1; i < response.length; i++) {
|
||||
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;
|
||||
let newTime = newDistance / stats.global.speed.moving * 3600;
|
||||
if (get(timestampsMode) === TimestampsMode.PRESERVE_AVERAGE_SPEED || replacingTime === 0) {
|
||||
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 replacingTime = newTime - remainingTime;
|
||||
let newDistance = stats.global.distance.moving + replacingDistance - replacedDistance;
|
||||
let newTime = newDistance / stats.global.speed.moving * 3600;
|
||||
|
||||
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];
|
||||
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 = 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;
|
||||
@@ -637,6 +661,41 @@ export class RoutingControls {
|
||||
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() {
|
||||
this.remove();
|
||||
this.unsubscribes.forEach((unsubscribe) => unsubscribe());
|
||||
|
@@ -1,31 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { ScrollArea as ScrollAreaPrimitive } from "bits-ui";
|
||||
import { Scrollbar } from "./index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { ScrollArea as ScrollAreaPrimitive } from 'bits-ui';
|
||||
import { Scrollbar } from './index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
type $$Props = ScrollAreaPrimitive.Props & {
|
||||
orientation?: "vertical" | "horizontal" | "both";
|
||||
orientation?: 'vertical' | 'horizontal' | 'both';
|
||||
scrollbarXClasses?: string;
|
||||
scrollbarYClasses?: string;
|
||||
viewportClasses?: string;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
let className: $$Props['class'] = undefined;
|
||||
export { className as class };
|
||||
export let orientation = "vertical";
|
||||
export let scrollbarXClasses: string = "";
|
||||
export let scrollbarYClasses: string = "";
|
||||
export let orientation = 'vertical';
|
||||
export let scrollbarXClasses: string = '';
|
||||
export let scrollbarYClasses: string = '';
|
||||
export let viewportClasses: string = '';
|
||||
</script>
|
||||
|
||||
<ScrollAreaPrimitive.Root {...$$restProps} class={cn("relative overflow-hidden", className)}>
|
||||
<ScrollAreaPrimitive.Viewport class="h-full w-full rounded-[inherit]">
|
||||
<ScrollAreaPrimitive.Root {...$$restProps} class={cn('relative overflow-hidden', className)}>
|
||||
<ScrollAreaPrimitive.Viewport class={cn('h-full w-full rounded-[inherit]', viewportClasses)}>
|
||||
<ScrollAreaPrimitive.Content>
|
||||
<slot />
|
||||
</ScrollAreaPrimitive.Content>
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
{#if orientation === "vertical" || orientation === "both"}
|
||||
{#if orientation === 'vertical' || orientation === 'both'}
|
||||
<Scrollbar orientation="vertical" class={scrollbarYClasses} />
|
||||
{/if}
|
||||
{#if orientation === "horizontal" || orientation === "both"}
|
||||
{#if orientation === 'horizontal' || orientation === 'both'}
|
||||
<Scrollbar orientation="horizontal" class={scrollbarXClasses} />
|
||||
{/if}
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
|
@@ -9,8 +9,8 @@ import { ListFileItem, ListItem, ListTrackItem, ListLevel, ListTrackSegmentItem,
|
||||
import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify';
|
||||
import { SplitType } from '$lib/components/toolbar/tools/scissors/Scissors.svelte';
|
||||
import { getClosestLinePoint, getElevation } from '$lib/utils';
|
||||
import { TimestampsMode } from '$lib/types';
|
||||
import { browser } from '$app/environment';
|
||||
import type mapboxgl from 'mapbox-gl';
|
||||
|
||||
enableMapSet();
|
||||
enablePatches();
|
||||
@@ -91,6 +91,7 @@ export const settings = {
|
||||
routing: dexieSettingStore('routing', true),
|
||||
routingProfile: dexieSettingStore('routingProfile', 'bike'),
|
||||
privateRoads: dexieSettingStore('privateRoads', false),
|
||||
timestampsMode: dexieSettingStore('timestampsMode', TimestampsMode.PRESERVE_AVERAGE_SPEED),
|
||||
currentBasemap: dexieSettingStore('currentBasemap', defaultBasemap),
|
||||
previousBasemap: dexieSettingStore('previousBasemap', defaultBasemap),
|
||||
selectedBasemapTree: dexieSettingStore('selectedBasemapTree', defaultBasemapTree),
|
||||
@@ -574,7 +575,7 @@ export const dbUtils = {
|
||||
});
|
||||
});
|
||||
},
|
||||
mergeSelection: (mergeTraces: boolean) => {
|
||||
mergeSelection: (mergeTraces: boolean, removeGaps: boolean) => {
|
||||
applyGlobal((draft) => {
|
||||
let first = true;
|
||||
let target: ListItem = new ListRootItem();
|
||||
@@ -649,7 +650,7 @@ export const dbUtils = {
|
||||
let s = new TrackSegment();
|
||||
toMerge.trk.map((track) => {
|
||||
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]];
|
||||
@@ -658,7 +659,7 @@ export const dbUtils = {
|
||||
if (toMerge.trkseg.length > 0) {
|
||||
let s = new TrackSegment();
|
||||
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];
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Soubory a statistiky
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -9,29 +9,29 @@ title: Erste Schritte
|
||||
# { title }
|
||||
|
||||
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." />
|
||||
|
||||
Wie im obigen Screenshot dargestellt, ist die Oberflä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.
|
||||
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 Benutzeroberfläche verschaffen.
|
||||
|
||||
## Menü
|
||||
|
||||
At the top of the interface, you will find the [main menu](./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.
|
||||
Am oberen Rand der Benutzeroberfläche findest du das [Hauptmenü](./menu).
|
||||
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
|
||||
|
||||
At the bottom of the interface, you will find the list of files currently open in the application.
|
||||
You can click on a file to select it and display its statistics below the list.
|
||||
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.
|
||||
Am unteren Rand der Benutzeroberfläche finden Sie die Liste der aktuell geöffneten Dateien der Anwendung.
|
||||
Sie können auf eine Datei klicken, um sie auszuwählen und ihre Statistiken unter der Liste anzuzeigen.
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Finally, on the right side of the interface, you will find the [map controls](./map-controls).
|
||||
These controls allow you to navigate the map, zoom in and out, and switch between different map styles.
|
||||
Schließlich findest du am rechten Rand der Benutzeroberfläche die [Kartensteuerungen](./map-controls).
|
||||
Mit diesen Steuerelementen können Sie auf der Karte navigieren, vergrößern und zwischen verschiedenen Kartenstilen wechseln.
|
||||
|
@@ -11,7 +11,7 @@ title: Kartensteuerungen
|
||||
# { title }
|
||||
|
||||
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
|
||||
|
||||
|
@@ -8,10 +8,10 @@ title: Menü
|
||||
|
||||
# { 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>
|
||||
|
||||
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>
|
||||
|
@@ -18,7 +18,7 @@ title: Werkzeugleiste
|
||||
|
||||
# { 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.
|
||||
|
||||
<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).
|
||||
|
||||
In den folgenden Abschnitten werden die einzelnen Tools detailliert beschrieben.
|
||||
Die folgenden Abschnitten beschreiben jedes Werkzeug im Detail.
|
||||
|
@@ -10,17 +10,17 @@ title: Extrahieren
|
||||
|
||||
# <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">
|
||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||
</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.
|
||||
|
||||
<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>
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,9 +73,9 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### Additional data
|
||||
|
||||
Using the buttons on the 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
|
||||
- **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.
|
||||
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** 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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Archivos y estadísticas
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ Puede usar el ratón para acercar o alejar el perfil de elevación y moverse hac
|
||||
|
||||
### 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
|
||||
- **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>.
|
||||
- Información de la **pendiente** calculada a partir de los datos de elevación, o
|
||||
- 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**.
|
||||
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Fichiers et statistiques
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ Vous pouvez également utiliser la molette de la souris pour zoomer ou dézoomer
|
||||
|
||||
### 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 **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 **pente** calculées à partir des données d'altitude, ou
|
||||
- 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**.
|
||||
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: FAQ
|
||||
title: GYIK
|
||||
---
|
||||
|
||||
<script>
|
||||
@@ -10,7 +10,7 @@ title: FAQ
|
||||
|
||||
### 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).
|
||||
However, donations are appreciated and help keep the website running.
|
||||
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</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.
|
||||
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
|
||||
|
||||
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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -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.
|
||||
|
||||
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! ❤️
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Integration
|
||||
title: Integráció
|
||||
---
|
||||
|
||||
<script>
|
||||
|
@@ -12,6 +12,6 @@ The main menu, located at the top of the interface, provides access to actions,
|
||||
|
||||
<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>
|
||||
|
@@ -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).
|
||||
|
||||
The next sections describe each tool in detail.
|
||||
A következő szakaszok részletesen ismertetik az egyes eszközöket.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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**.
|
||||
|
||||
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.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Azione sui File
|
||||
title: Azioni sui File
|
||||
---
|
||||
|
||||
<script lang="ts">
|
||||
@@ -17,7 +17,7 @@ Crea un nuovo file vuoto.
|
||||
|
||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Apri...
|
||||
|
||||
Open files from your computer.
|
||||
Apre i file dal tuo computer.
|
||||
|
||||
<DocsNote>
|
||||
|
||||
@@ -33,7 +33,7 @@ Crea una copia dei file attualmente selezionati.
|
||||
|
||||
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.
|
||||
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Puslapis nerastas
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Bestanden en statistieken
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ Je kunt het muiswiel ook gebruiken om in en uit te zoomen op het hoogte profiel,
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **helling** informatie berekend uit de hoogtegegevens, of
|
||||
- **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**.
|
||||
|
||||
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**.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Arquivos e estatísticas
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ Você também pode usar a roda do mouse para aumentar e diminuir o zoom no perfi
|
||||
|
||||
### 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
|
||||
- **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>.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Файлы и статистика
|
||||
---
|
||||
|
||||
<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';
|
||||
</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" /> информация, вычисленная на основе данных о высоте, или
|
||||
- **поверхность** <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>.
|
||||
- **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.
|
||||
Это доступно только для файлов, созданных с помощью **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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -73,10 +73,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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.
|
||||
|
@@ -3,7 +3,7 @@ title: Files and statistics
|
||||
---
|
||||
|
||||
<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';
|
||||
</script>
|
||||
|
||||
@@ -74,10 +74,10 @@ You can also use the mouse wheel to zoom in and out on the elevation profile, an
|
||||
|
||||
### 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
|
||||
- **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.
|
||||
- **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.
|
||||
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
4
website/src/lib/types.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum TimestampsMode {
|
||||
PRESERVE_TIMESTAMPS = 'preserve_timestamps',
|
||||
PRESERVE_AVERAGE_SPEED = 'preserve_average_speed',
|
||||
};
|
@@ -12,6 +12,7 @@ import mapboxgl from "mapbox-gl";
|
||||
import tilebelt from "@mapbox/tilebelt";
|
||||
import { PUBLIC_MAPBOX_TOKEN } from "$env/static/public";
|
||||
import PNGReader from "png.js";
|
||||
import type { DateFormatter } from "@internationalized/date";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
@@ -216,3 +217,15 @@ export function getURLForLanguage(lang: string | null | undefined, path: string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
});
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Wood",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Dirt",
|
||||
"ground": "Ground",
|
||||
"earth": "Earth",
|
||||
"snow": "Snow",
|
||||
"ice": "Ice",
|
||||
"salt": "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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "No pavimentat",
|
||||
"asphalt": "Asfalt",
|
||||
"concrete": "Formigó",
|
||||
"chipseal": "Camí asfaltat",
|
||||
"cobblestone": "Llambordes",
|
||||
"unhewn_cobblestone": "Llambordes grosses",
|
||||
"paving_stones": "Camí de pedres",
|
||||
"stepping_stones": "Empedrat",
|
||||
"sett": "Establir",
|
||||
"metal": "Metall",
|
||||
"wood": "Fusta",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Terra",
|
||||
"ground": "Terreny",
|
||||
"earth": "Planeta Terra",
|
||||
"snow": "Neu",
|
||||
"ice": "Gel",
|
||||
"salt": "Sal",
|
||||
"mud": "Fang",
|
||||
"sand": "Sorra",
|
||||
"woodchips": "Estella forestal",
|
||||
"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": {
|
||||
"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",
|
||||
@@ -173,6 +214,7 @@
|
||||
"merge_traces": "Connectar les traçades",
|
||||
"merge_contents": "Unir els continguts i mantenir les traçades desconnectades",
|
||||
"merge_selection": "Combinar la selecció",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Unir els elements",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distancia",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Pendent",
|
||||
"surface": "Superfície",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Nezpevněné",
|
||||
"asphalt": "Asfalt",
|
||||
"concrete": "Beton",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Dlažební kostky",
|
||||
"unhewn_cobblestone": "Hrubá dlažba",
|
||||
"paving_stones": "Dlažba",
|
||||
"stepping_stones": "Nášlapné kameny",
|
||||
"sett": "Dlažební kostky",
|
||||
"metal": "Kov",
|
||||
"wood": "Dřevo",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Hlína",
|
||||
"ground": "Pozemek",
|
||||
"earth": "Země",
|
||||
"snow": "Sníh",
|
||||
"ice": "Led",
|
||||
"salt": "Sůl",
|
||||
"mud": "Bláto",
|
||||
"sand": "Písek",
|
||||
"woodchips": "Dřevěné štěpky",
|
||||
"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": {
|
||||
"from": "Počáteční 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_contents": "Sloučit obsah a zachovat trasy oddělené",
|
||||
"merge_selection": "Sloučit výběr",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Sloučit položky",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topografická",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satelitní",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topografická",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Zobrazit sklon svahu",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Vzdálenost",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Energie",
|
||||
"slope": "Sklon",
|
||||
"surface": "Povrch",
|
||||
"highway": "Category",
|
||||
"time": "Čas",
|
||||
"moving": "V pohybu",
|
||||
"total": "Celkem"
|
||||
"total": "Celkem",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Wood",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Dirt",
|
||||
"ground": "Ground",
|
||||
"earth": "Earth",
|
||||
"snow": "Snow",
|
||||
"ice": "Ice",
|
||||
"salt": "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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"metadata": {
|
||||
"home_title": "der online GPX Datei Editor",
|
||||
"app_title": "app",
|
||||
"app_title": "App",
|
||||
"embed_title": "der online GPX Datei Editor",
|
||||
"help_title": "hilfe",
|
||||
"404_title": "Seite nicht gefunden",
|
||||
@@ -33,8 +33,8 @@
|
||||
"select_all": "Alle auswählen",
|
||||
"view": "Ansicht",
|
||||
"elevation_profile": "Höhenprofil",
|
||||
"vertical_file_view": "Vertical file list",
|
||||
"switch_basemap": "Switch to previous basemap",
|
||||
"vertical_file_view": "Vertikale Dateiliste",
|
||||
"switch_basemap": "Zur vorherigen Basemap wechseln",
|
||||
"toggle_overlays": "Toggle overlays",
|
||||
"toggle_3d": "3D umschalten",
|
||||
"settings": "Einstellungen",
|
||||
@@ -49,21 +49,21 @@
|
||||
"language": "Sprache",
|
||||
"mode": "Design",
|
||||
"system": "System",
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"street_view_source": "Street view source",
|
||||
"light": "Hell",
|
||||
"dark": "Dunkel",
|
||||
"street_view_source": "Street View Quelle",
|
||||
"mapillary": "Mapillary",
|
||||
"google": "Google",
|
||||
"toggle_street_view": "Street view",
|
||||
"toggle_street_view": "Street View",
|
||||
"layers": "Map layers...",
|
||||
"distance_markers": "Entfernungsmarkierungen",
|
||||
"direction_markers": "Direction arrows",
|
||||
"help": "Hilfe",
|
||||
"more": "More...",
|
||||
"more": "Mehr...",
|
||||
"donate": "Spenden",
|
||||
"ctrl": "Strg",
|
||||
"click": "Klick",
|
||||
"drag": "Drag",
|
||||
"drag": "Ziehen",
|
||||
"metadata": {
|
||||
"button": "Info...",
|
||||
"name": "Bezeichnung",
|
||||
@@ -77,83 +77,124 @@
|
||||
"width": "Breite"
|
||||
},
|
||||
"hide": "Verbergen",
|
||||
"unhide": "Unhide",
|
||||
"unhide": "Einblenden",
|
||||
"center": "Center",
|
||||
"open_in": "Open in"
|
||||
},
|
||||
"toolbar": {
|
||||
"routing": {
|
||||
"tooltip": "Plan or edit a route",
|
||||
"tooltip": "Route planen oder bearbeiten",
|
||||
"activity": "Aktivität",
|
||||
"use_routing": "Routenführung",
|
||||
"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": {
|
||||
"button": "Umkehren",
|
||||
"tooltip": "Reverse the direction of the route"
|
||||
"tooltip": "Die Richtung der Route umkehren"
|
||||
},
|
||||
"route_back_to_start": {
|
||||
"button": "Back to start",
|
||||
"tooltip": "Connect the last point of the route with the starting point"
|
||||
"button": "Zurück zum Start",
|
||||
"tooltip": "Den letzten Punkt der Route mit dem Startpunkt verbinden"
|
||||
},
|
||||
"round_trip": {
|
||||
"button": "Round trip",
|
||||
"tooltip": "Return to the starting point by the same route"
|
||||
"button": "Rundfahrt",
|
||||
"tooltip": "Kehre mit derselben Route zum Startpunkt zurück"
|
||||
},
|
||||
"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": "Click on the map to add a new anchor point, or drag existing ones to change the route.",
|
||||
"activities": {
|
||||
"bike": "Rad",
|
||||
"racing_bike": "Road bike",
|
||||
"bike": "Fahrrad",
|
||||
"racing_bike": "Rennrad",
|
||||
"gravel_bike": "Gravel Bike",
|
||||
"mountain_bike": "Mountainbike",
|
||||
"foot": "Laufen/Wandern",
|
||||
"motorcycle": "Moped",
|
||||
"water": "Water",
|
||||
"motorcycle": "Motorrad",
|
||||
"water": "Wasser",
|
||||
"railway": "Railway"
|
||||
},
|
||||
"surface": {
|
||||
"unknown": "Unknown",
|
||||
"unknown": "Unbekannt",
|
||||
"paved": "Gepflastert",
|
||||
"unpaved": "Unbefestigt",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Beton",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Kopfsteinpflaster",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"paving_stones": "Verbundsteine",
|
||||
"sett": "Behauenes Steinpflaster",
|
||||
"metal": "Metall",
|
||||
"wood": "Holz",
|
||||
"compacted": "Compacted gravel",
|
||||
"fine_gravel": "Fine gravel",
|
||||
"compacted": "verdichtet",
|
||||
"fine_gravel": "Feiner Schotter",
|
||||
"gravel": "Schotter",
|
||||
"pebblestone": "Kieselsteine",
|
||||
"rock": "Fels",
|
||||
"dirt": "Dreck",
|
||||
"ground": "Boden",
|
||||
"earth": "Erde",
|
||||
"snow": "Schnee",
|
||||
"ice": "Eis",
|
||||
"salt": "Salz",
|
||||
"mud": "Matsch",
|
||||
"sand": "Sand",
|
||||
"woodchips": "Holzhäcksel",
|
||||
"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": {
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"scissors": {
|
||||
"tooltip": "Crop or split",
|
||||
"crop": "Crop",
|
||||
"tooltip": "Schneiden oder Teilen",
|
||||
"crop": "Schneiden",
|
||||
"split_as": "Split the trace into",
|
||||
"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."
|
||||
@@ -161,11 +202,11 @@
|
||||
"time": {
|
||||
"tooltip": "Manage time data",
|
||||
"start": "Start",
|
||||
"end": "End",
|
||||
"end": "Ziel",
|
||||
"total_time": "Zeit in Bewegung",
|
||||
"pick_date": "Pick a date",
|
||||
"artificial": "Create realistic time data",
|
||||
"update": "Update time data",
|
||||
"pick_date": "Datum auswählen",
|
||||
"artificial": "Erstelle realistische Zeitdaten",
|
||||
"update": "Aktualisiere Zeitdaten",
|
||||
"help": "Use the form to set new time data.",
|
||||
"help_invalid_selection": "Select a single trace to manage its time data."
|
||||
},
|
||||
@@ -173,7 +214,8 @@
|
||||
"merge_traces": "Connect the traces",
|
||||
"merge_contents": "Merge the contents and keep the traces disconnected",
|
||||
"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_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.",
|
||||
@@ -195,8 +237,8 @@
|
||||
"tooltip": "Create and edit points of interest",
|
||||
"icon": "Icon",
|
||||
"link": "Link",
|
||||
"longitude": "Longitude",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Längengrad",
|
||||
"latitude": "Breitengrad",
|
||||
"create": "Create point of interest",
|
||||
"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.",
|
||||
@@ -204,15 +246,15 @@
|
||||
},
|
||||
"reduce": {
|
||||
"tooltip": "Reduce the number of GPS points",
|
||||
"tolerance": "Tolerance",
|
||||
"number_of_points": "Number of GPS points",
|
||||
"tolerance": "Toleranz",
|
||||
"number_of_points": "Anzahl der GPS-Punkte",
|
||||
"button": "Minify",
|
||||
"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."
|
||||
},
|
||||
"clean": {
|
||||
"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_inside": "Delete inside selection",
|
||||
"delete_outside": "Delete outside selection",
|
||||
@@ -243,19 +285,19 @@
|
||||
"basemaps": "Basiskarte",
|
||||
"overlays": "Ebenen",
|
||||
"custom": "Custom",
|
||||
"world": "World",
|
||||
"countries": "Countries",
|
||||
"belgium": "Belgium",
|
||||
"world": "Welt",
|
||||
"countries": "Länder",
|
||||
"belgium": "Belgien",
|
||||
"bulgaria": "Bulgarien",
|
||||
"finland": "Finland",
|
||||
"france": "France",
|
||||
"new_zealand": "New Zealand",
|
||||
"norway": "Norway",
|
||||
"spain": "Spain",
|
||||
"sweden": "Sweden",
|
||||
"switzerland": "Switzerland",
|
||||
"united_kingdom": "United Kingdom",
|
||||
"united_states": "United States",
|
||||
"finland": "Finnland",
|
||||
"france": "Frankreich",
|
||||
"new_zealand": "Neuseeland",
|
||||
"norway": "Norwegen",
|
||||
"spain": "Spanien",
|
||||
"sweden": "Schweden",
|
||||
"switzerland": "Schweiz",
|
||||
"united_kingdom": "Großbritannien",
|
||||
"united_states": "USA",
|
||||
"mapboxOutdoors": "Mapbox Outdoors",
|
||||
"mapboxSatellite": "Mapbox Satellit",
|
||||
"openStreetMap": "OpenStreetMap",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -294,50 +337,50 @@
|
||||
"ignSlope": "IGN Slope",
|
||||
"ignSkiTouring": "IGN Ski Touring",
|
||||
"waymarked_trails": "Waymarked Trails",
|
||||
"waymarkedTrailsHiking": "Hiking",
|
||||
"waymarkedTrailsCycling": "Cycling",
|
||||
"waymarkedTrailsHiking": "Wandern",
|
||||
"waymarkedTrailsCycling": "Radfahren",
|
||||
"waymarkedTrailsMTB": "MTB",
|
||||
"waymarkedTrailsSkating": "Skating",
|
||||
"waymarkedTrailsHorseRiding": "Horse Riding",
|
||||
"waymarkedTrailsWinter": "Winter",
|
||||
"points_of_interest": "Points of interest",
|
||||
"food": "Food",
|
||||
"bakery": "Bakery",
|
||||
"bakery": "Bäckerei",
|
||||
"food-store": "Food Store",
|
||||
"eat-and-drink": "Eat and Drink",
|
||||
"amenities": "Amenities",
|
||||
"toilets": "Toilets",
|
||||
"water": "Water",
|
||||
"shower": "Shower",
|
||||
"shelter": "Shelter",
|
||||
"motorized": "Cars and Motorcycles",
|
||||
"fuel-station": "Fuel Station",
|
||||
"toilets": "Toiletten",
|
||||
"water": "Trinkwasser",
|
||||
"shower": "Dusche",
|
||||
"shelter": "Unterstand",
|
||||
"motorized": "Autos und Motorräder",
|
||||
"fuel-station": "Tankstelle",
|
||||
"parking": "Parking",
|
||||
"garage": "Garage",
|
||||
"barrier": "Barrier",
|
||||
"tourism": "Tourism",
|
||||
"barrier": "Barriere",
|
||||
"tourism": "Tourismus",
|
||||
"attraction": "Attraction",
|
||||
"viewpoint": "Viewpoint",
|
||||
"viewpoint": "Aussichtspunkt",
|
||||
"hotel": "Hotel",
|
||||
"campsite": "Campsite",
|
||||
"hut": "Hut",
|
||||
"picnic": "Picnic Area",
|
||||
"summit": "Summit",
|
||||
"pass": "Pass",
|
||||
"campsite": "Campingplatz",
|
||||
"hut": "Hütte",
|
||||
"picnic": "Picknickplatz",
|
||||
"summit": "Gipfel",
|
||||
"pass": "Gebirgspass",
|
||||
"climbing": "Climbing",
|
||||
"bicycle": "Bicycle",
|
||||
"bicycle": "Fahrrad",
|
||||
"bicycle-parking": "Bicycle Parking",
|
||||
"bicycle-rental": "Bicycle Rental",
|
||||
"bicycle-rental": "Fahrradverleih",
|
||||
"bicycle-shop": "Fahrradgeschäft",
|
||||
"public-transport": "Öffentliche Verkehrsmittel",
|
||||
"railway-station": "Bahnhof",
|
||||
"tram-stop": "Straßenbahnhaltestelle",
|
||||
"bus-stop": "Bushaltestelle",
|
||||
"ferry": "Ferry"
|
||||
"ferry": "Fähre"
|
||||
},
|
||||
"color": {
|
||||
"blue": "Blau",
|
||||
"bluered": "Blue Red",
|
||||
"bluered": "Blau Rot",
|
||||
"gray": "Grau",
|
||||
"hot": "Heiß",
|
||||
"purple": "Lila",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distanz",
|
||||
@@ -361,14 +397,16 @@
|
||||
"temperature": "Temperatur",
|
||||
"speed": "Geschwindigkeit",
|
||||
"pace": "Tempo",
|
||||
"heartrate": "Heart rate",
|
||||
"heartrate": "Herzfrequenz",
|
||||
"cadence": "Trittfrequenz",
|
||||
"power": "Leistung",
|
||||
"slope": "Gefälle",
|
||||
"surface": "Oberfläche",
|
||||
"highway": "Category",
|
||||
"time": "Zeit",
|
||||
"moving": "Moving",
|
||||
"total": "Gesamt"
|
||||
"moving": "Bewegung",
|
||||
"total": "Gesamt",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
@@ -389,8 +427,8 @@
|
||||
"power": "W"
|
||||
},
|
||||
"gpx": {
|
||||
"file": "File",
|
||||
"files": "Files",
|
||||
"file": "Datei",
|
||||
"files": "Dateien",
|
||||
"track": "Strecke",
|
||||
"tracks": "Strecken",
|
||||
"segment": "Abschnitt",
|
||||
@@ -401,56 +439,56 @@
|
||||
"alert": "Alert",
|
||||
"anchor": "Anchor",
|
||||
"bank": "Bank",
|
||||
"beach": "Beach",
|
||||
"beach": "Strand",
|
||||
"bike_trail": "Bike Trail",
|
||||
"binoculars": "Binoculars",
|
||||
"bridge": "Bridge",
|
||||
"building": "Building",
|
||||
"campground": "Campsite",
|
||||
"car": "Car",
|
||||
"bridge": "Brücke",
|
||||
"building": "Gebäude",
|
||||
"campground": "Campingplatz",
|
||||
"car": "Auto",
|
||||
"car_repair": "Garage",
|
||||
"convenience_store": "Convenience Store",
|
||||
"crossing": "Crossing",
|
||||
"department_store": "Department Store",
|
||||
"drinking_water": "Water",
|
||||
"drinking_water": "Trinkwasser",
|
||||
"exit": "Exit",
|
||||
"lodge": "Hut",
|
||||
"lodging": "Accommodation",
|
||||
"forest": "Forest",
|
||||
"gas_station": "Fuel Station",
|
||||
"forest": "Wald",
|
||||
"gas_station": "Tankstelle",
|
||||
"ground_transportation": "Ground Transportation",
|
||||
"hotel": "Hotel",
|
||||
"house": "House",
|
||||
"information": "Information",
|
||||
"park": "Park",
|
||||
"parking_area": "Parking",
|
||||
"pharmacy": "Pharmacy",
|
||||
"picnic_area": "Picnic Area",
|
||||
"parking_area": "Parkplatz",
|
||||
"pharmacy": "Apotheke",
|
||||
"picnic_area": "Picknickplatz",
|
||||
"restaurant": "Restaurant",
|
||||
"restricted_area": "Restricted Area",
|
||||
"restroom": "Toilets",
|
||||
"road": "Road",
|
||||
"restroom": "Toiletten",
|
||||
"road": "Straße",
|
||||
"scenic_area": "Scenic Area",
|
||||
"shelter": "Shelter",
|
||||
"shopping_center": "Shopping Center",
|
||||
"shower": "Shower",
|
||||
"summit": "Summit",
|
||||
"telephone": "Telephone",
|
||||
"shelter": "Unterstand",
|
||||
"shopping_center": "Einkaufszentrum",
|
||||
"shower": "Dusche",
|
||||
"summit": "Gipfel",
|
||||
"telephone": "Telefon",
|
||||
"tunnel": "Tunnel",
|
||||
"water_source": "Water Source"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
"website": "Website",
|
||||
"website": "Webseite",
|
||||
"home": "Home",
|
||||
"app": "App",
|
||||
"contact": "Contact",
|
||||
"contact": "Kontakt",
|
||||
"reddit": "Reddit",
|
||||
"x": "X",
|
||||
"facebook": "Facebook",
|
||||
"github": "GitHub",
|
||||
"crowdin": "Crowdin",
|
||||
"email": "Email",
|
||||
"email": "E-Mail",
|
||||
"contribute": "Contribute",
|
||||
"supported_by": "supported by",
|
||||
"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."
|
||||
},
|
||||
"docs": {
|
||||
"translate": "Improve the translation on Crowdin",
|
||||
"translate": "Verbessere die Übersetzung auf Crowdin",
|
||||
"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": "Suche",
|
||||
"clear": "Clear",
|
||||
"cancel": "Abbrechen",
|
||||
"recent": "Recent searches",
|
||||
"no_recent": "No recent searches",
|
||||
"save": "Save this search",
|
||||
"remove": "Remove this search from history",
|
||||
"favorites": "Favorites",
|
||||
"remove_favorite": "Remove this search from favorites",
|
||||
"recent": "Letzte Suchanfragen",
|
||||
"no_recent": "Keine kürzlichen Suchanfragen",
|
||||
"save": "Diese Suchanfrage speichern",
|
||||
"remove": "Diese Suchanfrage aus dem Verlauf entfernen",
|
||||
"favorites": "Favoriten",
|
||||
"remove_favorite": "Diese Suchanfrage aus Favoriten entfernen",
|
||||
"to_select": "to select",
|
||||
"to_navigate": "to navigate",
|
||||
"to_close": "to close",
|
||||
@@ -506,7 +544,7 @@
|
||||
"preview": "Vorschau",
|
||||
"code": "Integration code"
|
||||
},
|
||||
"webgl2_required": "WebGL 2 is required to display the map.",
|
||||
"enable_webgl2": "Learn how to enable WebGL 2 in your browser",
|
||||
"page_not_found": "page not found"
|
||||
"webgl2_required": "WebGL 2 ist erforderlich, um die Karte anzuzeigen.",
|
||||
"enable_webgl2": "Erfahren Sie, wie Sie WebGL 2 in Ihrem Browser aktivieren",
|
||||
"page_not_found": "Seite nicht gefunden"
|
||||
}
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Μη ασφαλτοστρωμένο",
|
||||
"asphalt": "Άσφαλτος",
|
||||
"concrete": "Τσιμέντο",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Μέταλλο",
|
||||
"wood": "Ξύλο",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Βρωμιά",
|
||||
"ground": "Χώμα",
|
||||
"earth": "Γη",
|
||||
"snow": "Χιόνι",
|
||||
"ice": "Πάγος",
|
||||
"salt": "Αλάτι",
|
||||
"mud": "Λάσπη",
|
||||
"sand": "Άμμος",
|
||||
"woodchips": "Woodchips",
|
||||
"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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Απόσταση",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Πλαγιά",
|
||||
"surface": "Επιφάνεια",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Σύνολο"
|
||||
"total": "Σύνολο",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "μέτρα",
|
||||
|
@@ -88,6 +88,8 @@
|
||||
"use_routing": "Routing",
|
||||
"use_routing_tooltip": "Connect anchor points via road network, or in a straight line if disabled",
|
||||
"allow_private": "Allow private roads",
|
||||
"preserve_average_speed": "Maintain average speed",
|
||||
"preserve_timestamps": "Adjust timestamps to fill gaps",
|
||||
"reverse": {
|
||||
"button": "Reverse",
|
||||
"tooltip": "Reverse the direction of the route"
|
||||
@@ -119,11 +121,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Wood",
|
||||
@@ -135,15 +134,59 @@
|
||||
"dirt": "Dirt",
|
||||
"ground": "Ground",
|
||||
"earth": "Earth",
|
||||
"snow": "Snow",
|
||||
"ice": "Ice",
|
||||
"salt": "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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +316,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +390,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +404,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Sin pavimento",
|
||||
"asphalt": "Asfalto",
|
||||
"concrete": "Hormigón",
|
||||
"chipseal": "Pavimento delgado",
|
||||
"cobblestone": "Adoquinado",
|
||||
"unhewn_cobblestone": "Adoquín sin labrar",
|
||||
"paving_stones": "Adoquines",
|
||||
"stepping_stones": "Peldaños",
|
||||
"sett": "Adoquín",
|
||||
"metal": "Metal",
|
||||
"wood": "Madera",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Tierra",
|
||||
"ground": "Tierra",
|
||||
"earth": "Tierra natural",
|
||||
"snow": "Nevado",
|
||||
"ice": "Helado",
|
||||
"salt": "Salado",
|
||||
"mud": "Barro",
|
||||
"sand": "Arena",
|
||||
"woodchips": "Virutas de madera",
|
||||
"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": {
|
||||
"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",
|
||||
@@ -173,6 +214,7 @@
|
||||
"merge_traces": "Conectar los trazados",
|
||||
"merge_contents": "Combinar los contenidos y mantener los trazados desconectados",
|
||||
"merge_selection": "Combinar selección",
|
||||
"remove_gaps": "Eliminar intervalos vacíos de tiempo entre trazas",
|
||||
"tooltip": "Combinar elementos",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satélite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satélite",
|
||||
"ordnanceSurvey": "Encuesta Ordnance",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Mostrar datos de pendiente",
|
||||
"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"
|
||||
"settings": "Configuración del perfil de elevación"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distancia",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Potencia",
|
||||
"slope": "Pendiente",
|
||||
"surface": "Superficie",
|
||||
"highway": "Categoría",
|
||||
"time": "Tiempo",
|
||||
"moving": "Movimiento",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "Datos OpenStreetMap"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Päällystämätön",
|
||||
"asphalt": "Asfaltti",
|
||||
"concrete": "Betoni",
|
||||
"chipseal": "Öljysora",
|
||||
"cobblestone": "Mukulakivi",
|
||||
"unhewn_cobblestone": "Luonnonmukainen mukulakivi",
|
||||
"paving_stones": "Katukivetys",
|
||||
"stepping_stones": "Astinkivet",
|
||||
"sett": "Kivetys",
|
||||
"metal": "Metalli",
|
||||
"wood": "Puu",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Maa",
|
||||
"ground": "Maa",
|
||||
"earth": "Maa",
|
||||
"snow": "Lumi",
|
||||
"ice": "Jää",
|
||||
"salt": "Suola",
|
||||
"mud": "Muta",
|
||||
"sand": "Hiekka",
|
||||
"woodchips": "Hake",
|
||||
"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": {
|
||||
"from": "Aloituspiste 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_contents": "Yhdistä reitit samaan tiedostoon",
|
||||
"merge_selection": "Yhdistä valitut",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Yhdistä tiedostot",
|
||||
"help_merge_traces": "Yhdistäminen luo valituista reiteistä yhden yhtenäisen reitin.",
|
||||
"help_cannot_merge_traces": "Valitse useampia reittejä yhdistääksesi ne.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Maastokartta",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Ilmakuva",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Maastokartta",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Kaltevuus",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Sans revêtement",
|
||||
"asphalt": "Asphalte",
|
||||
"concrete": "Béton",
|
||||
"chipseal": "Enduit superficiel routier",
|
||||
"cobblestone": "Pavés",
|
||||
"unhewn_cobblestone": "Pavé non taillé",
|
||||
"paving_stones": "Pavage en pierres",
|
||||
"stepping_stones": "Pierres de gué",
|
||||
"sett": "Pavés",
|
||||
"metal": "Métal",
|
||||
"wood": "Bois",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Sol en érosion",
|
||||
"ground": "Sol",
|
||||
"earth": "Terre",
|
||||
"snow": "Neige",
|
||||
"ice": "Glace",
|
||||
"salt": "Sel",
|
||||
"mud": "Boue",
|
||||
"sand": "Sable",
|
||||
"woodchips": "Plaquette forestière",
|
||||
"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": {
|
||||
"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",
|
||||
@@ -173,6 +214,7 @@
|
||||
"merge_traces": "Connecter les traces",
|
||||
"merge_contents": "Fusionner les contenus et garder les traces déconnectées",
|
||||
"merge_selection": "Fusionner la sélection",
|
||||
"remove_gaps": "Supprimer les écarts de temps entre les traces",
|
||||
"tooltip": "Fusionner les éléments",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Afficher les données de pente",
|
||||
"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"
|
||||
"settings": "Réglages du profil altimétrique"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -365,10 +401,12 @@
|
||||
"cadence": "Cadence",
|
||||
"power": "Puissance",
|
||||
"slope": "Pente",
|
||||
"surface": "Surface",
|
||||
"surface": "Revêtement",
|
||||
"highway": "Catégorie",
|
||||
"time": "Temps",
|
||||
"moving": "En mouvement",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "Données d'OpenStreetMap"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Wood",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Dirt",
|
||||
"ground": "Ground",
|
||||
"earth": "Earth",
|
||||
"snow": "Snow",
|
||||
"ice": "Ice",
|
||||
"salt": "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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"embed_title": "az online GPX szerkesztő",
|
||||
"help_title": "súgó",
|
||||
"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": {
|
||||
"new": "Új",
|
||||
@@ -33,7 +33,7 @@
|
||||
"select_all": "Összes kijelölése",
|
||||
"view": "Nézet",
|
||||
"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",
|
||||
"toggle_overlays": "Átfedés váltása",
|
||||
"toggle_3d": "3D nézet bekapcsolása",
|
||||
@@ -54,7 +54,7 @@
|
||||
"street_view_source": "Utcakép nézet forrása",
|
||||
"mapillary": "Mapillary",
|
||||
"google": "Google",
|
||||
"toggle_street_view": "Street view",
|
||||
"toggle_street_view": "Utcakép nézet",
|
||||
"layers": "Térképrétegek...",
|
||||
"distance_markers": "Távolsági km szakaszok mutatása",
|
||||
"direction_markers": "Menetirány mutatása",
|
||||
@@ -86,11 +86,11 @@
|
||||
"tooltip": "Útvonal tervezése vagy szerkesztése",
|
||||
"activity": "Tevékenység",
|
||||
"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",
|
||||
"reverse": {
|
||||
"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": {
|
||||
"button": "Vissza a starthoz",
|
||||
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Földes",
|
||||
"asphalt": "Aszfalt",
|
||||
"concrete": "Beton",
|
||||
"chipseal": "Törmelékes",
|
||||
"cobblestone": "Macskaköves",
|
||||
"unhewn_cobblestone": "Vágatlan nagy kavics",
|
||||
"paving_stones": "Térkő",
|
||||
"stepping_stones": "Szikla lépcső",
|
||||
"sett": "Kőlap",
|
||||
"metal": "Fém",
|
||||
"wood": "Fa",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Piszok",
|
||||
"ground": "Föld",
|
||||
"earth": "Föld",
|
||||
"snow": "Hó",
|
||||
"ice": "Jég",
|
||||
"salt": "Só",
|
||||
"mud": "Sár",
|
||||
"sand": "Homok",
|
||||
"woodchips": "Faforgács",
|
||||
"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": {
|
||||
"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",
|
||||
@@ -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."
|
||||
},
|
||||
"time": {
|
||||
"tooltip": "Manage time data",
|
||||
"tooltip": "Idő beállítása",
|
||||
"start": "Rajt",
|
||||
"end": "End",
|
||||
"end": "Befejezés",
|
||||
"total_time": "Mozgási idő",
|
||||
"pick_date": "Pick a date",
|
||||
"artificial": "Create realistic time data",
|
||||
"update": "Update time data",
|
||||
"help": "Use the form to set new time data.",
|
||||
"help_invalid_selection": "Select a single trace to manage its time data."
|
||||
"pick_date": "Válassz dátumot",
|
||||
"artificial": "Valósághű időadatok hozzáadása",
|
||||
"update": "Használd a formot új idő beállításához.",
|
||||
"help": "Használd a form-ot az új idő beállításához.",
|
||||
"help_invalid_selection": "Válasszon ki egyetlen nyomvonalat az időadatainak kezeléséhez."
|
||||
},
|
||||
"merge": {
|
||||
"merge_traces": "Connect the traces",
|
||||
"merge_traces": "Kösd össze az útvonalakat",
|
||||
"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",
|
||||
"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.",
|
||||
@@ -184,10 +226,10 @@
|
||||
"tooltip": "Extract contents to separate items",
|
||||
"button": "Extract",
|
||||
"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": {
|
||||
"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_no_selection": "Select a file item to request elevation data."
|
||||
},
|
||||
@@ -196,23 +238,23 @@
|
||||
"icon": "Icon",
|
||||
"link": "Link",
|
||||
"longitude": "Longitude",
|
||||
"latitude": "Latitude",
|
||||
"create": "Create point of interest",
|
||||
"latitude": "Szélesség",
|
||||
"create": "POI fájlba mentése",
|
||||
"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."
|
||||
},
|
||||
"reduce": {
|
||||
"tooltip": "Reduce the number of GPS points",
|
||||
"tolerance": "Tolerance",
|
||||
"number_of_points": "Number of GPS points",
|
||||
"tolerance": "Tűréshatár",
|
||||
"number_of_points": "GPS pontok száma",
|
||||
"button": "Minify",
|
||||
"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."
|
||||
},
|
||||
"clean": {
|
||||
"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_inside": "Delete inside selection",
|
||||
"delete_outside": "Delete outside selection",
|
||||
@@ -222,14 +264,14 @@
|
||||
}
|
||||
},
|
||||
"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.",
|
||||
"selection": "Layer selection",
|
||||
"custom_layers": {
|
||||
"title": "Custom layers",
|
||||
"new": "New custom layer",
|
||||
"edit": "Edit custom layer",
|
||||
"urls": "URL(s)",
|
||||
"urls": "Webcím(ek)",
|
||||
"url_placeholder": "WMTS, WMS vagy Mapbox stílus JSON",
|
||||
"max_zoom": "Max nagyítás",
|
||||
"layer_type": "Réteg típus",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Műhold",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Hadifelmérés",
|
||||
"norwayTopo": "Norvégia topográfiai térképe 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -321,8 +364,8 @@
|
||||
"hotel": "Hotel",
|
||||
"campsite": "Kemping",
|
||||
"hut": "Hut",
|
||||
"picnic": "Picnic Area",
|
||||
"summit": "Summit",
|
||||
"picnic": "Piknikező hely",
|
||||
"summit": "Csúcs",
|
||||
"pass": "Pass",
|
||||
"climbing": "Climbing",
|
||||
"bicycle": "Kerékpár",
|
||||
@@ -333,7 +376,7 @@
|
||||
"railway-station": "Vasútállomás",
|
||||
"tram-stop": "Villamos megálló",
|
||||
"bus-stop": "Buszmegálló",
|
||||
"ferry": "Ferry"
|
||||
"ferry": "Komp"
|
||||
},
|
||||
"color": {
|
||||
"blue": "Kék",
|
||||
@@ -341,18 +384,11 @@
|
||||
"gray": "Szürke",
|
||||
"hot": "Legérdekesebb",
|
||||
"purple": "Lila",
|
||||
"orange": "Orange"
|
||||
"orange": "Narancssárga"
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Távolság",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Erő",
|
||||
"slope": "Erőkifejtési szintkép színekkel",
|
||||
"surface": "Szintkép",
|
||||
"highway": "Category",
|
||||
"time": "Idő",
|
||||
"moving": "Moving",
|
||||
"total": "Összes"
|
||||
"total": "Összes",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
@@ -383,7 +421,7 @@
|
||||
"minutes_per_kilometer": "min/km",
|
||||
"minutes_per_mile": "min/mi",
|
||||
"minutes_per_nautical_mile": "min/nm",
|
||||
"knots": "kn",
|
||||
"knots": "csomó",
|
||||
"heartrate": "bpm",
|
||||
"cadence": "rpm",
|
||||
"power": "W"
|
||||
@@ -499,14 +537,14 @@
|
||||
"manual_camera": "Manual camera",
|
||||
"manual_camera_description": "You can move the map below to adjust the camera position.",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude",
|
||||
"longitude": "Hosszúság",
|
||||
"zoom": "Zoom",
|
||||
"pitch": "Pitch",
|
||||
"bearing": "Bearing",
|
||||
"pitch": "Dőlésszög",
|
||||
"bearing": "Irányszög",
|
||||
"preview": "Előnézet",
|
||||
"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",
|
||||
"page_not_found": "page not found"
|
||||
}
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Non asfaltato",
|
||||
"asphalt": "Asfalto",
|
||||
"concrete": "Calcestruzzo",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Acciottolato",
|
||||
"unhewn_cobblestone": "Ciottolame",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Pavé",
|
||||
"metal": "Metallo",
|
||||
"wood": "Legno",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Terra",
|
||||
"ground": "Terreno",
|
||||
"earth": "Terra",
|
||||
"snow": "Neve",
|
||||
"ice": "Ghiaccio",
|
||||
"salt": "Sale",
|
||||
"mud": "Fango",
|
||||
"sand": "Sabbia",
|
||||
"woodchips": "Cippato",
|
||||
"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": {
|
||||
"from": "Il punto di partenza è troppo lontano dalla strada più vicina",
|
||||
"via": "The via point is too far from the nearest road",
|
||||
@@ -173,12 +214,13 @@
|
||||
"merge_traces": "Collega le tracce",
|
||||
"merge_contents": "Unisci i contenuti e mantieni le tracce disconnesse",
|
||||
"merge_selection": "Selezione unione",
|
||||
"remove_gaps": "Rimuovere le differenze di tempo tra le tracce",
|
||||
"tooltip": "Unisci gli elementi insieme",
|
||||
"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_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.",
|
||||
"selection_tip": "Tip: use {KEYBOARD_SHORTCUT} to add items to the selection."
|
||||
"selection_tip": "Suggerimento: usa {KEYBOARD_SHORTCUT} per aggiungere elementi alla selezione."
|
||||
},
|
||||
"extract": {
|
||||
"tooltip": "Estrae i contenuti per separare gli elementi",
|
||||
@@ -188,8 +230,8 @@
|
||||
},
|
||||
"elevation": {
|
||||
"button": "Richiedi dati elevazione",
|
||||
"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": "Richiedere dati di altitudine cancellerà i dati di altitudine attuali, se presenti, e li rimpiazzerà con quelli provenienti da Mapbox.",
|
||||
"help_no_selection": "Seleziona un file per richiedere i dati di altitudine."
|
||||
},
|
||||
"waypoint": {
|
||||
"tooltip": "Crea e modifica punti di interesse",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "Satellitare IGN",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Sondaggio Ordnance",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Mostra dati pendenza",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distanza",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Potenza",
|
||||
"slope": "Pendenza",
|
||||
"surface": "Superficie",
|
||||
"highway": "Category",
|
||||
"time": "Dati temporali",
|
||||
"moving": "Movimento",
|
||||
"total": "Totale"
|
||||
"total": "Totale",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "비포장 도로",
|
||||
"asphalt": "아스팔트",
|
||||
"concrete": "콘크리트",
|
||||
"chipseal": "칩씰",
|
||||
"cobblestone": "조약돌",
|
||||
"unhewn_cobblestone": "거친 조약돌",
|
||||
"paving_stones": "포장석",
|
||||
"stepping_stones": "디딤돌",
|
||||
"sett": "정형 자갈",
|
||||
"metal": "금속",
|
||||
"wood": "목재",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "흙길",
|
||||
"ground": "지면",
|
||||
"earth": "자연 지면",
|
||||
"snow": "눈",
|
||||
"ice": "얼음",
|
||||
"salt": "소금",
|
||||
"mud": "진흙",
|
||||
"sand": "모래",
|
||||
"woodchips": "목재 칩",
|
||||
"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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN 위성",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "경사 정보 표시",
|
||||
"show_surface": "지면 정보 표시",
|
||||
"show_speed": "속도 정보 표시",
|
||||
"show_pace": "페이스 정보 표시",
|
||||
"show_heartrate": "심박수 정보 표시",
|
||||
"show_cadence": "케이던스 정보 표시",
|
||||
"show_temperature": "온도 정보 표시",
|
||||
"show_power": "파워 정보 표시"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "거리",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "파워",
|
||||
"slope": "경사",
|
||||
"surface": "표면",
|
||||
"highway": "Category",
|
||||
"time": "시간",
|
||||
"moving": "이동 중",
|
||||
"total": "전체"
|
||||
"total": "전체",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Negrįstas",
|
||||
"asphalt": "Asfaltas",
|
||||
"concrete": "Betonas",
|
||||
"chipseal": "Žvyrkelis",
|
||||
"cobblestone": "Grįstas akmenimis",
|
||||
"unhewn_cobblestone": "Grįstas nešlifuotais akmenimis",
|
||||
"paving_stones": "Plytelės",
|
||||
"stepping_stones": "Plytelės su tarpais",
|
||||
"sett": "Trinkelės",
|
||||
"metal": "Metalo",
|
||||
"wood": "Medžio",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Purvas",
|
||||
"ground": "Žemė",
|
||||
"earth": "Žemė",
|
||||
"snow": "Sniegas",
|
||||
"ice": "Ledas",
|
||||
"salt": "Druska",
|
||||
"mud": "Purvas",
|
||||
"sand": "Smėlis",
|
||||
"woodchips": "Medžio drožlės",
|
||||
"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": {
|
||||
"from": "Pradžios 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_contents": "Sujungti turinį ir laikyti trasas atskirai",
|
||||
"merge_selection": "Sujungti pasirinkimą",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Sujungti elementus",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Rodyti nuolydžio duomenis",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Atstumas",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Jėga",
|
||||
"slope": "Nuolydis",
|
||||
"surface": "Paviršius",
|
||||
"highway": "Category",
|
||||
"time": "Laikas",
|
||||
"moving": "Judėjimas",
|
||||
"total": "Bendras"
|
||||
"total": "Bendras",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Cobblestone",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Wood",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Dirt",
|
||||
"ground": "Ground",
|
||||
"earth": "Earth",
|
||||
"snow": "Snow",
|
||||
"ice": "Ice",
|
||||
"salt": "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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Onverhard",
|
||||
"asphalt": "Asfalt",
|
||||
"concrete": "Beton",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Klinkers",
|
||||
"unhewn_cobblestone": "Ruwe kasseien",
|
||||
"paving_stones": "Straatstenen",
|
||||
"stepping_stones": "Stapstenen",
|
||||
"sett": "Instellen",
|
||||
"metal": "Metaal",
|
||||
"wood": "Hout",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Onverhard",
|
||||
"ground": "Ondergrond",
|
||||
"earth": "Aarde",
|
||||
"snow": "Sneeuw",
|
||||
"ice": "IJs",
|
||||
"salt": "Zout",
|
||||
"mud": "Modder",
|
||||
"sand": "Zand",
|
||||
"woodchips": "Houtsnippers",
|
||||
"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": {
|
||||
"from": "Het startpunt 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_contents": "Voeg de inhoud samen en houd de sporen gescheiden",
|
||||
"merge_selection": "Voeg selectie samen",
|
||||
"remove_gaps": "Verwijder tijdsprongen tussen sporen",
|
||||
"tooltip": "Items samenvoegen",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satelliet",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satelliet",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Toon richtingsgegevens",
|
||||
"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"
|
||||
"settings": "Instellingen hoogteprofiel"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Afstand",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Kracht",
|
||||
"slope": "Helling",
|
||||
"surface": "Oppervlak",
|
||||
"highway": "Categorie",
|
||||
"time": "Tijd",
|
||||
"moving": "Beweging",
|
||||
"total": "Totaal"
|
||||
"total": "Totaal",
|
||||
"osm_extensions": "OpenStreetMap gegevens"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Uasfaltert",
|
||||
"asphalt": "Asfalt",
|
||||
"concrete": "Betong",
|
||||
"chipseal": "Grov asfalt",
|
||||
"cobblestone": "Brostein",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metall",
|
||||
"wood": "Treverk",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Jord",
|
||||
"ground": "Bakke",
|
||||
"earth": "Jord",
|
||||
"snow": "Snø",
|
||||
"ice": "Is",
|
||||
"salt": "Salt",
|
||||
"mud": "Gjørme",
|
||||
"sand": "Sand",
|
||||
"woodchips": "Treflis",
|
||||
"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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Slå sammen valgte",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Slå sammen elementer",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Avstand",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Skråning",
|
||||
"surface": "Overflate",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Totalt"
|
||||
"total": "Totalt",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Nieutwardzona",
|
||||
"asphalt": "Asfalt",
|
||||
"concrete": "Beton",
|
||||
"chipseal": "Nawierzchnia utrwalana powierzchniowo",
|
||||
"cobblestone": "Bruk",
|
||||
"unhewn_cobblestone": "Bruk",
|
||||
"paving_stones": "Płyta",
|
||||
"stepping_stones": "Bruk",
|
||||
"sett": "Bruk",
|
||||
"metal": "Metal",
|
||||
"wood": "Drewno",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Ziemia",
|
||||
"ground": "Teren",
|
||||
"earth": "Ziemia",
|
||||
"snow": "Śnieg",
|
||||
"ice": "Lód",
|
||||
"salt": "Sól",
|
||||
"mud": "Błoto",
|
||||
"sand": "Piasek",
|
||||
"woodchips": "Zrębki",
|
||||
"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": {
|
||||
"from": "Punkt początkowy 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_contents": "Scal zawartość, ale utrzymaj rozłączone ślady",
|
||||
"merge_selection": "Scal zaznaczenie",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Scal elementy razem",
|
||||
"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ć.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Pokaż dane nachylenia",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Dystans",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Moc",
|
||||
"slope": "Nachylenie",
|
||||
"surface": "Powierzchnia",
|
||||
"highway": "Category",
|
||||
"time": "Czas",
|
||||
"moving": "W ruchu",
|
||||
"total": "Łącznie"
|
||||
"total": "Łącznie",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Não pavimentado",
|
||||
"asphalt": "Asfalto",
|
||||
"concrete": "Cimento",
|
||||
"chipseal": "Pedriscos",
|
||||
"cobblestone": "Empedrado",
|
||||
"unhewn_cobblestone": "Paralelepípedo bruto",
|
||||
"paving_stones": "Paralelepípedo",
|
||||
"stepping_stones": "Caminho de pedras",
|
||||
"sett": "Pedra portuguesa",
|
||||
"metal": "Metal",
|
||||
"wood": "Madeira",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Terra",
|
||||
"ground": "Chão",
|
||||
"earth": "Terra",
|
||||
"snow": "Neve",
|
||||
"ice": "Gelo",
|
||||
"salt": "Sal",
|
||||
"mud": "Lama",
|
||||
"sand": "Areia",
|
||||
"woodchips": "Cavacos de madeira",
|
||||
"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": {
|
||||
"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",
|
||||
@@ -173,6 +214,7 @@
|
||||
"merge_traces": "Conecte as trilhas",
|
||||
"merge_contents": "Mesclar o conteúdo e manter as trilhas desconectadas",
|
||||
"merge_selection": "Unir seleção",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Unir itens",
|
||||
"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.",
|
||||
@@ -271,8 +313,9 @@
|
||||
"ignFrPlan": "IGN Plan",
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "Satélite IGN",
|
||||
"ignEs": "IGN",
|
||||
"ignFrSatellite": "IGN Satélite",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satélite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -291,7 +334,7 @@
|
||||
"swisstopoMountainBikeClosures": "swisstopo MTB Closures",
|
||||
"swisstopoSkiTouring": "swisstopo Ski Touring",
|
||||
"ignFrCadastre": "IGN Cadastre",
|
||||
"ignSlope": "Inclinação IGN",
|
||||
"ignSlope": "IGN Inclinação",
|
||||
"ignSkiTouring": "IGN Ski Touring",
|
||||
"waymarked_trails": "Trilhas demarcadas",
|
||||
"waymarkedTrailsHiking": "Caminhada",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Mostrar dados de inclinação",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distância",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Potência",
|
||||
"slope": "Inclinação",
|
||||
"surface": "Superfície",
|
||||
"highway": "Category",
|
||||
"time": "Tempo",
|
||||
"moving": "Movimento",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Não pavimentado",
|
||||
"asphalt": "Asfalto",
|
||||
"concrete": "Cimento",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Empedrado",
|
||||
"unhewn_cobblestone": "Unhewn cobblestone",
|
||||
"paving_stones": "Paving stones",
|
||||
"stepping_stones": "Stepping stones",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Madeira",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Terra",
|
||||
"ground": "Chão",
|
||||
"earth": "Terra",
|
||||
"snow": "Neve",
|
||||
"ice": "Gelo",
|
||||
"salt": "Sal",
|
||||
"mud": "Lama",
|
||||
"sand": "Areia",
|
||||
"woodchips": "Woodchips",
|
||||
"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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distância",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Potência",
|
||||
"slope": "Slope",
|
||||
"surface": "Superfície",
|
||||
"highway": "Category",
|
||||
"time": "Tempo",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
@@ -119,11 +119,8 @@
|
||||
"unpaved": "Unpaved",
|
||||
"asphalt": "Asphalt",
|
||||
"concrete": "Concrete",
|
||||
"chipseal": "Chipseal",
|
||||
"cobblestone": "Pavaj",
|
||||
"unhewn_cobblestone": "Pavaj neșlefuit",
|
||||
"paving_stones": "Pavaj din pietre",
|
||||
"stepping_stones": "Pietre de pașit",
|
||||
"sett": "Sett",
|
||||
"metal": "Metal",
|
||||
"wood": "Lemn",
|
||||
@@ -135,15 +132,59 @@
|
||||
"dirt": "Noroi",
|
||||
"ground": "Sol",
|
||||
"earth": "Pământ",
|
||||
"snow": "Zăpadă",
|
||||
"ice": "Gheață",
|
||||
"salt": "Sare",
|
||||
"mud": "Noroi",
|
||||
"sand": "Nisip",
|
||||
"woodchips": "Woodchips",
|
||||
"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": {
|
||||
"from": "The start 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_contents": "Merge the contents and keep the traces disconnected",
|
||||
"merge_selection": "Merge selection",
|
||||
"remove_gaps": "Remove time gaps between traces",
|
||||
"tooltip": "Merge items together",
|
||||
"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.",
|
||||
@@ -272,7 +314,8 @@
|
||||
"ignFrTopo": "IGN Topo",
|
||||
"ignFrScan25": "IGN SCAN25",
|
||||
"ignFrSatellite": "IGN Satellite",
|
||||
"ignEs": "IGN",
|
||||
"ignEs": "IGN Topo",
|
||||
"ignEsSatellite": "IGN Satellite",
|
||||
"ordnanceSurvey": "Ordnance Survey",
|
||||
"norwayTopo": "Topografisk Norgeskart 4",
|
||||
"swedenTopo": "Lantmäteriet Topo",
|
||||
@@ -345,14 +388,7 @@
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"show_slope": "Show slope data",
|
||||
"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"
|
||||
"settings": "Elevation profile settings"
|
||||
},
|
||||
"quantities": {
|
||||
"distance": "Distance",
|
||||
@@ -366,9 +402,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user