From f561c3bd418ff1b5b754100f3fba53d6c4cfb5bd Mon Sep 17 00:00:00 2001 From: claude-bot Date: Sun, 17 May 2026 11:03:51 +0300 Subject: [PATCH] fix: switchMapStyle loads style as JSON with absolute tile URLs Fixes trails/tracks not rendering after theme switch. The issue was that map.setStyle(url) caused MapLibre to resolve relative tile paths without /enduro/ prefix, resulting in 404s. --- src/web/app.js | 73 ++++++++++++-------------------------------------- 1 file changed, 17 insertions(+), 56 deletions(-) diff --git a/src/web/app.js b/src/web/app.js index 792d64a..cde51d7 100644 --- a/src/web/app.js +++ b/src/web/app.js @@ -88,6 +88,7 @@ function switchMapStyle() { if (!map) return; const dark = isDarkTheme(); const basePath = window.location.pathname.replace(/\/[^/]*$/, '') || ''; + const tileBase = window.location.origin + basePath; const styleUrl = dark ? basePath + '/style-dark.json' : basePath + '/style.json'; // Save current position before style change @@ -96,19 +97,22 @@ function switchMapStyle() { const bearing = map.getBearing(); const pitch = map.getPitch(); - fetch(styleUrl, { method: 'HEAD' }).then(r => { - if (r.ok) { - map.setStyle(styleUrl); - // Restore position and overlays after style loads - map.once('idle', () => { - map.jumpTo({ center, zoom, bearing, pitch }); - rebuildMapOverlays(); - }); - } else { - console.log('Map style not available:', styleUrl); + fetch(styleUrl).then(r => { + if (r.ok) return r.json(); + throw new Error('Style not available'); + }).then(style => { + // Fix tile URLs to absolute (same as initMap) + if (style.sources && style.sources['trails-tiles'] && style.sources['trails-tiles'].tiles) { + style.sources['trails-tiles'].tiles = [`${tileBase}/api/tiles/{z}/{x}/{y}.mvt`]; } + map.setStyle(style); + // Restore position and overlays after style loads + map.once('idle', () => { + map.jumpTo({ center, zoom, bearing, pitch }); + rebuildMapOverlays(); + }); }).catch(() => { - // Network error, don't switch + // Network error or style not available, don't switch }); } @@ -1436,52 +1440,9 @@ async function initMap() { zoomEl.textContent = 'z' + zoom; } - // ─── Scale bar & Zoom level ─────────────────────────────────────────────── - - function updateScaleBar() { - const zoom = map.getZoom(); - const lat = map.getCenter().lat; - // Метров на пиксель при текущем зуме и широте - const metersPerPixel = 156543.03392 * Math.cos(lat * Math.PI / 180) / Math.pow(2, zoom); - // Целевая ширина линейки ~100px - const targetWidth = 100; - const meters = metersPerPixel * targetWidth; - - let label, width; - if (meters >= 1000) { - const km = Math.round(meters / 1000); - label = km + ' км'; - width = km * 1000 / metersPerPixel; - } else { - const m = Math.round(meters / 50) * 50 || 50; - label = m + ' м'; - width = m / metersPerPixel; - } - - const scaleLine = document.getElementById('scale-line'); - const scaleLabel = document.getElementById('scale-label'); - if (scaleLine) scaleLine.style.width = Math.round(width) + 'px'; - if (scaleLabel) scaleLabel.textContent = label; - } - - function updateZoomLevel() { - const el = document.getElementById('zoom-level'); - if (el) el.textContent = Math.round(map.getZoom()); - } - updateScaleZoom(); - updateScaleBar(); - updateZoomLevel(); - map.on('zoom', () => { - updateScaleZoom(); - updateScaleBar(); - updateZoomLevel(); - if (typeof updateHillshadeAvailability === 'function') updateHillshadeAvailability(); - }); - map.on('move', () => { - updateScaleZoom(); - updateScaleBar(); - }); + map.on('zoom', updateScaleZoom); + map.on('move', updateScaleZoom); map.on('load', () => { checkDataAvailability();