mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 15:43:25 +00:00
add highway info to elevation profile, closes #65
This commit is contained in:
@@ -775,12 +775,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;
|
||||
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] = {};
|
||||
}
|
||||
statistics.global.surface[surface] += dist;
|
||||
if (statistics.global.extensions[key][value] === undefined) {
|
||||
statistics.global.extensions[key][value] = 0;
|
||||
}
|
||||
statistics.global.extensions[key][value] += dist;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,11 +1079,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;
|
||||
setExtensions(extensions: Record<string, string>) {
|
||||
if (Object.keys(extensions).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSurface(surface: string): void {
|
||||
if (!this.extensions) {
|
||||
this.extensions = {};
|
||||
}
|
||||
@@ -1089,7 +1092,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 {
|
||||
@@ -1119,8 +1128,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;
|
||||
@@ -1270,7 +1282,7 @@ export class GPXStatistics {
|
||||
avg: number,
|
||||
count: number,
|
||||
},
|
||||
surface: Record<string, number>,
|
||||
extensions: Record<string, Record<string, number>>,
|
||||
};
|
||||
local: {
|
||||
points: TrackPoint[],
|
||||
@@ -1341,7 +1353,7 @@ export class GPXStatistics {
|
||||
avg: 0,
|
||||
count: 0,
|
||||
},
|
||||
surface: {},
|
||||
extensions: {},
|
||||
};
|
||||
this.local = {
|
||||
points: [],
|
||||
@@ -1411,11 +1423,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 = {
|
||||
|
64
website/src/lib/assets/colors.ts
Normal file
64
website/src/lib/assets/colors.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
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 const highwayColors: { [key: string]: string } = {
|
||||
"missing": "#d1d1d1",
|
||||
"residential": "#73b2ff",
|
||||
"service": "#b3b3cc",
|
||||
"track": "#946f43",
|
||||
"unclassified": "#e0e0e0",
|
||||
"footway": "#a3c989",
|
||||
"tertiary": "#ffdd7f",
|
||||
"path": "#a3c989",
|
||||
"secondary": "#ffd75f",
|
||||
"primary": "#ff6e5c",
|
||||
"cycleway": "#ffbb6e",
|
||||
"trunk": "#ff5e4d",
|
||||
"living_street": "#9de2ff",
|
||||
"motorway": "#ff4d33",
|
||||
"motorway_link": "#ff947f",
|
||||
"steps": "#8d91a2",
|
||||
"road": "#e0e0e0",
|
||||
"pedestrian": "#c1c8e4",
|
||||
"trunk_link": "#ff947f",
|
||||
"primary_link": "#ff8d7b",
|
||||
"secondary_link": "#ffcb66",
|
||||
"tertiary_link": "#ffdd8b",
|
||||
"construction": "#e09a4a",
|
||||
"bridleway": "#a3c989",
|
||||
"platform": "#c4c4c4",
|
||||
"proposed": "#e0e0e0",
|
||||
"raceway": "#ff0000",
|
||||
"rest_area": "#73b2ff",
|
||||
"abandoned": "#e0e0e0",
|
||||
"services": "#ffe066",
|
||||
"corridor": "#c4c4c4",
|
||||
"bus_stop": "#ffe6e6",
|
||||
"busway": "#ffe6e6",
|
||||
"elevator": "#c4c4c4",
|
||||
"via_ferrata": "#8d91a2"
|
||||
};
|
@@ -1,26 +0,0 @@
|
||||
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',
|
||||
}
|
@@ -16,9 +16,10 @@
|
||||
Zap,
|
||||
Circle,
|
||||
Check,
|
||||
ChartNoAxesColumn
|
||||
ChartNoAxesColumn,
|
||||
Construction
|
||||
} from 'lucide-svelte';
|
||||
import { surfaceColors } from '$lib/assets/surfaces';
|
||||
import { surfaceColors, highwayColors } from '$lib/assets/colors';
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import {
|
||||
getCadenceWithUnits,
|
||||
@@ -43,7 +44,7 @@
|
||||
export let gpxStatistics: Writable<GPXStatistics>;
|
||||
export let slicedGPXStatistics: Writable<[GPXStatistics, number, number] | undefined>;
|
||||
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;
|
||||
@@ -151,7 +152,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)}`,
|
||||
@@ -164,6 +168,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)}`);
|
||||
}
|
||||
@@ -353,7 +368,7 @@
|
||||
segment: data.local.slope.segment[index],
|
||||
length: data.local.slope.length[index]
|
||||
},
|
||||
surface: point.getSurface(),
|
||||
extensions: point.getExtensions(),
|
||||
coordinates: point.getCoordinates(),
|
||||
index: index
|
||||
};
|
||||
@@ -448,10 +463,15 @@
|
||||
}
|
||||
|
||||
function surfaceFillCallback(context) {
|
||||
let surface = context.p0.raw.surface;
|
||||
let surface = context.p0.raw.extensions.surface;
|
||||
return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing;
|
||||
}
|
||||
|
||||
function highwayFillCallback(context) {
|
||||
let highway = context.p0.raw.extensions.highway;
|
||||
return highwayColors[highway] ? highwayColors[highway] : highwayColors.missing;
|
||||
}
|
||||
|
||||
$: if (chart) {
|
||||
if (elevationFill === 'slope') {
|
||||
chart.data.datasets[0]['segment'] = {
|
||||
@@ -461,6 +481,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'] = {};
|
||||
}
|
||||
@@ -551,7 +575,7 @@
|
||||
<ChartNoAxesColumn size="18" />
|
||||
</ButtonWithTooltip>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content class="w-fit p-0 flex flex-col divide-y" side="left" sideOffset={-32}>
|
||||
<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"
|
||||
@@ -582,6 +606,19 @@
|
||||
<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"
|
||||
|
@@ -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' : ''}">
|
||||
|
@@ -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>
|
||||
|
@@ -65,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];
|
||||
@@ -82,25 +82,25 @@ 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 tag = fields[i].split("=");
|
||||
tags[tag[0]] = tag[1];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
return tags;
|
||||
}
|
||||
|
||||
function getIntermediatePoints(points: Coordinates[]): Promise<TrackPoint[]> {
|
||||
let route: TrackPoint[] = [];
|
||||
|
@@ -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 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.
|
||||
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.
|
||||
|
@@ -139,6 +139,52 @@
|
||||
"clay": "Clay",
|
||||
"stone": "Stone"
|
||||
},
|
||||
"highway": {
|
||||
"unknown": "Unknown",
|
||||
"residential": "Residential",
|
||||
"service": "Service",
|
||||
"track": "Track",
|
||||
"unclassified": "Unclassified",
|
||||
"footway": "Footway",
|
||||
"tertiary": "Tertiary",
|
||||
"path": "Path",
|
||||
"secondary": "Secondary",
|
||||
"primary": "Primary",
|
||||
"cycleway": "Cycleway",
|
||||
"trunk": "Trunk",
|
||||
"living_street": "Living Street",
|
||||
"motorway": "Motorway",
|
||||
"motorway_link": "Motorway Link",
|
||||
"steps": "Steps",
|
||||
"road": "Road",
|
||||
"pedestrian": "Pedestrian",
|
||||
"trunk_link": "Trunk Link",
|
||||
"primary_link": "Primary Link",
|
||||
"secondary_link": "Secondary Link",
|
||||
"tertiary_link": "Tertiary Link",
|
||||
"construction": "Construction",
|
||||
"bridleway": "Bridleway",
|
||||
"platform": "Platform",
|
||||
"proposed": "Proposed",
|
||||
"raceway": "Raceway",
|
||||
"rest_area": "Rest Area",
|
||||
"abandoned": "Abandoned",
|
||||
"services": "Services",
|
||||
"corridor": "Corridor",
|
||||
"bus_stop": "Bus Stop",
|
||||
"busway": "Busway",
|
||||
"elevator": "Elevator",
|
||||
"via_ferrata": "Via Ferrata"
|
||||
},
|
||||
"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",
|
||||
@@ -355,9 +401,11 @@
|
||||
"power": "Power",
|
||||
"slope": "Slope",
|
||||
"surface": "Surface",
|
||||
"highway": "Category",
|
||||
"time": "Time",
|
||||
"moving": "Moving",
|
||||
"total": "Total"
|
||||
"total": "Total",
|
||||
"osm_extensions": "OpenStreetMap data"
|
||||
},
|
||||
"units": {
|
||||
"meters": "m",
|
||||
|
Reference in New Issue
Block a user