Map: sidebar pills for 4 tile layers (CyclOSM/OSM/Topo/Sat); fix elevation ascend property

This commit is contained in:
Davide Scaini
2026-05-14 09:43:46 +02:00
parent 277898f46f
commit 626d145861
+36 -28
View File
@@ -30,22 +30,37 @@
'https://c.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', 'https://c.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png',
], ],
attribution: '© <a href="https://www.cyclosm.org">CyclOSM</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', attribution: '© <a href="https://www.cyclosm.org">CyclOSM</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
label: 'CyclOSM', label: 'Cycle',
}, },
osm: { osm: {
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
label: 'OSM', label: 'OSM',
}, },
topo: {
tiles: [
'https://a.tile.opentopomap.org/{z}/{x}/{y}.png',
'https://b.tile.opentopomap.org/{z}/{x}/{y}.png',
'https://c.tile.opentopomap.org/{z}/{x}/{y}.png',
],
attribution: '© <a href="https://opentopomap.org">OpenTopoMap</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
label: 'Topo',
},
satellite: {
tiles: ['https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'],
attribution: '© <a href="https://www.esri.com">Esri</a> World Imagery',
label: 'Sat',
},
}; };
const TILE_ORDER = ['cyclosm', 'osm', 'topo', 'satellite'];
let tileLayer = $state('cyclosm'); let tileLayer = $state('cyclosm');
function toggleTiles() { function setTileLayer(key) {
tileLayer = tileLayer === 'cyclosm' ? 'osm' : 'cyclosm'; tileLayer = key;
if (!map) return; if (!map) return;
const src = map.getSource('base'); const src = map.getSource('base');
if (src) src.setTiles(TILES[tileLayer].tiles); if (src) src.setTiles(TILES[key].tiles);
} }
// ── Map init ─────────────────────────────────────────────────────────────── // ── Map init ───────────────────────────────────────────────────────────────
@@ -199,7 +214,7 @@ ${trkpts}
if (!route) return null; if (!route) return null;
const p = route.properties ?? {}; const p = route.properties ?? {};
const dist = parseFloat(p['track-length'] ?? 0) / 1000; const dist = parseFloat(p['track-length'] ?? 0) / 1000;
const up = parseInt(p['filtered ascent'] ?? p.ascent ?? 0); const up = parseInt(p['filtered ascend'] ?? p.ascend ?? 0);
return { dist: dist.toFixed(1), up }; return { dist: dist.toFixed(1), up };
} }
@@ -214,6 +229,20 @@ ${trkpts}
<a href={activityUrl} class="back-link">← Activity</a> <a href={activityUrl} class="back-link">← Activity</a>
</header> </header>
<!-- Map layer selector -->
<section class="section">
<p class="label">Map</p>
<div class="pills">
{#each TILE_ORDER as key}
<button
class="pill"
class:active={tileLayer === key}
onclick={() => setTileLayer(key)}
>{TILES[key].label}</button>
{/each}
</div>
</section>
<!-- Profile selector --> <!-- Profile selector -->
<section class="section"> <section class="section">
<p class="label">Profile</p> <p class="label">Profile</p>
@@ -269,11 +298,7 @@ ${trkpts}
<!-- Map + elevation --> <!-- Map + elevation -->
<main class="map-area"> <main class="map-area">
<div class="map-wrap" bind:this={mapEl}> <div class="map-wrap" bind:this={mapEl}></div>
<button class="tile-toggle" onclick={toggleTiles} title="Switch map layer">
{TILES[tileLayer].label}
</button>
</div>
{#if route} {#if route}
<div class="elevation-wrap"> <div class="elevation-wrap">
<ElevationChart {route} /> <ElevationChart {route} />
@@ -391,24 +416,7 @@ ${trkpts}
.small { font-size: 0.75rem; margin: 0; } .small { font-size: 0.75rem; margin: 0; }
.map-area { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .map-area { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.map-wrap { flex: 1; position: relative; } .map-wrap { flex: 1; }
.tile-toggle {
position: absolute;
top: 0.5rem;
left: 0.5rem;
z-index: 10;
padding: 0.25rem 0.5rem;
border-radius: 0.375rem;
border: 1px solid var(--border);
background: var(--bg-card);
color: var(--text-4);
font-size: 0.7rem;
font-weight: 600;
cursor: pointer;
transition: all 0.15s;
}
.tile-toggle:hover { border-color: var(--accent); color: var(--accent); }
.elevation-wrap { height: 140px; flex-shrink: 0; background: var(--bg-card); border-top: 1px solid var(--border); } .elevation-wrap { height: 140px; flex-shrink: 0; background: var(--bg-card); border-top: 1px solid var(--border); }
:global(.wp-marker) { :global(.wp-marker) {