// Center on a default point var map = L.map('map', { zoomControl: false, doubleClickZoom: false }).setView([53.866237, 10.676289], 18); // Add OSM tiles L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map); var userIcon = L.icon({ iconUrl: '/maps-arrow.svg', // Add a motorcycle icon to your static folder iconSize: [40, 40] }); // Get users location if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position) { var lat = position.coords.latitude; var lon = position.coords.longitude; map.setView([lat, lon], 14); L.marker([lat, lon], {icon: userIcon}).addTo(map).bindPopup('You are here!'); }); } // Custom Bootstrap zoom controls document.addEventListener('DOMContentLoaded', function() { var zoomInBtn = document.getElementById('zoomInBtn'); var zoomOutBtn = document.getElementById('zoomOutBtn'); var themeToggle = document.getElementById('themeToggle'); var clearRouteBtn = document.getElementById('clearRouteBtn'); var twistiness = document.getElementById('twistiness'); var twistinessValue = document.getElementById('twistinessValue'); var highwayPref = document.getElementById('highwayPref'); var highwayPrefValue = document.getElementById('highwayPrefValue'); var exportModeSel = document.getElementById('exportMode'); var voiceToggle = document.getElementById('voiceToggle'); var roundTripToggle = document.getElementById('roundTripToggle'); var roundTripKm = document.getElementById('roundTripKm'); var roundTripBtn = document.getElementById('roundTripBtn'); var roundTripNoRepeat = document.getElementById('roundTripNoRepeat'); var roundTripDir = document.getElementById('roundTripDir'); var roundTripScenic = document.getElementById('roundTripScenic'); var roundTripIsochrone = document.getElementById('roundTripIsochrone'); var isochroneMinutes = document.getElementById('isochroneMinutes'); if (zoomInBtn && zoomOutBtn) { zoomInBtn.addEventListener('click', function() { map.zoomIn(); }); zoomOutBtn.addEventListener('click', function() { map.zoomOut(); }); } // Theme toggle with persistence (Dracula-like) function applyTheme(theme) { if (theme === 'dark') { document.documentElement.setAttribute('data-theme', 'dark'); if (themeToggle) themeToggle.textContent = '☀️'; } else { document.documentElement.removeAttribute('data-theme'); if (themeToggle) themeToggle.textContent = '🌙'; } } var savedTheme = localStorage.getItem('freemoto-theme'); if (!savedTheme || savedTheme === 'auto') { var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; applyTheme(prefersDark ? 'dark' : 'light'); if (!savedTheme) localStorage.setItem('freemoto-theme', 'auto'); } else { applyTheme(savedTheme); } if (themeToggle) { themeToggle.addEventListener('click', function() { var next = (localStorage.getItem('freemoto-theme') || 'light') === 'dark' ? 'light' : 'dark'; localStorage.setItem('freemoto-theme', next); applyTheme(next); }); } // Clear route button if (clearRouteBtn && typeof window.resetMarkers === 'function') { clearRouteBtn.addEventListener('click', function() { window.resetMarkers(); }); } // Twistiness slider function applyTwistiness(val) { if (twistinessValue) twistinessValue.textContent = String(val); localStorage.setItem('freemoto-twistiness', String(val)); } var savedTwist = parseInt(localStorage.getItem('freemoto-twistiness') || '50', 10); if (!isNaN(savedTwist) && twistiness) { twistiness.value = savedTwist; applyTwistiness(savedTwist); } if (twistiness) { twistiness.addEventListener('input', function(e){ var v = parseInt(e.target.value, 10); applyTwistiness(v); }); twistiness.addEventListener('change', function(){ if (typeof window.recalculateRoute === 'function') { window.recalculateRoute(); } }); } // Highway preference slider (0..100 -> 0..1 use_highways) function applyHighwayPref(val) { if (highwayPrefValue) highwayPrefValue.textContent = String(val); localStorage.setItem('freemoto-highways', String(val)); } var savedHigh = parseInt(localStorage.getItem('freemoto-highways') || '50', 10); if (!isNaN(savedHigh) && highwayPref) { highwayPref.value = savedHigh; applyHighwayPref(savedHigh); } if (highwayPref) { highwayPref.addEventListener('input', function(e){ var v = parseInt(e.target.value, 10); applyHighwayPref(v); }); highwayPref.addEventListener('change', function(){ if (typeof window.recalculateRoute === 'function') { window.recalculateRoute(); } }); } // Persist export mode if (exportModeSel) { var savedMode = localStorage.getItem('freemoto-export-mode') || 'both'; exportModeSel.value = savedMode; exportModeSel.addEventListener('change', function(){ localStorage.setItem('freemoto-export-mode', exportModeSel.value); }); } // Persist voice toggle if (voiceToggle) { var savedVoice = localStorage.getItem('freemoto-voice') === '1'; voiceToggle.checked = savedVoice; voiceToggle.addEventListener('change', function(){ localStorage.setItem('freemoto-voice', voiceToggle.checked ? '1' : '0'); }); } // Round Trip settings persistence if (roundTripToggle) { var savedRT = localStorage.getItem('freemoto-roundtrip') === '1'; roundTripToggle.checked = savedRT; roundTripToggle.addEventListener('change', function(){ localStorage.setItem('freemoto-roundtrip', roundTripToggle.checked ? '1' : '0'); }); } if (roundTripKm) { var savedKm = parseInt(localStorage.getItem('freemoto-roundtrip-km') || '100', 10); if (!isNaN(savedKm)) roundTripKm.value = savedKm; roundTripKm.addEventListener('change', function(){ var v = parseInt(roundTripKm.value, 10); if (!isNaN(v)) localStorage.setItem('freemoto-roundtrip-km', String(v)); if (roundTripToggle && roundTripToggle.checked && typeof window.createRoundTrip === 'function') { window.createRoundTrip(); } }); } if (roundTripBtn) { roundTripBtn.addEventListener('click', function(){ if (typeof window.createRoundTrip === 'function') { window.createRoundTrip(); } }); } if (roundTripNoRepeat) { var savedNR = localStorage.getItem('freemoto-roundtrip-norepeat') === '1'; roundTripNoRepeat.checked = savedNR; roundTripNoRepeat.addEventListener('change', function(){ localStorage.setItem('freemoto-roundtrip-norepeat', roundTripNoRepeat.checked ? '1' : '0'); }); } // Direction preference persistence and live update if (roundTripDir) { var savedDir = localStorage.getItem('freemoto-roundtrip-dir') || 'any'; roundTripDir.value = savedDir; roundTripDir.addEventListener('change', function(){ localStorage.setItem('freemoto-roundtrip-dir', roundTripDir.value); if (roundTripToggle && roundTripToggle.checked && typeof window.createRoundTrip === 'function') { // Regenerate the round trip to reflect new direction window.createRoundTrip(); } }); } // Scenic optimizer toggle if (roundTripScenic) { var savedScenic = localStorage.getItem('freemoto-roundtrip-scenic') === '1'; roundTripScenic.checked = savedScenic; roundTripScenic.addEventListener('change', function(){ localStorage.setItem('freemoto-roundtrip-scenic', roundTripScenic.checked ? '1' : '0'); if (roundTripToggle && roundTripToggle.checked && typeof window.createRoundTrip === 'function') { window.createRoundTrip(); } }); } // Isochrone toggle and minutes if (roundTripIsochrone) { var savedIso = localStorage.getItem('freemoto-roundtrip-isochrone') === '1'; roundTripIsochrone.checked = savedIso; roundTripIsochrone.addEventListener('change', function(){ localStorage.setItem('freemoto-roundtrip-isochrone', roundTripIsochrone.checked ? '1' : '0'); if (roundTripToggle && roundTripToggle.checked && typeof window.createRoundTrip === 'function') { window.createRoundTrip(); } }); } if (isochroneMinutes) { var savedMin = parseInt(localStorage.getItem('freemoto-isochrone-minutes') || '60', 10); if (!isNaN(savedMin)) isochroneMinutes.value = savedMin; isochroneMinutes.addEventListener('change', function(){ var v = parseInt(isochroneMinutes.value, 10); if (!isNaN(v)) localStorage.setItem('freemoto-isochrone-minutes', String(v)); if (roundTripToggle && roundTripToggle.checked && typeof window.createRoundTrip === 'function') { window.createRoundTrip(); } }); } // Swap start/end like Google Maps (function(){ var swapBtn = document.getElementById('swapBtn'); if (!swapBtn) return; function swapInputs() { var s = document.getElementById('sourceInput'); var d = document.getElementById('destInput'); if (!s || !d) return; // Swap visible values var tmpVal = s.value; s.value = d.value; d.value = tmpVal; // Swap lat/lon datasets var sLat = s.dataset.lat, sLon = s.dataset.lon; s.dataset.lat = d.dataset.lat || ''; s.dataset.lon = d.dataset.lon || ''; d.dataset.lat = sLat || ''; d.dataset.lon = sLon || ''; // If both look valid, trigger plot var sourceLat = parseFloat(s.dataset.lat); var sourceLon = parseFloat(s.dataset.lon); var destLat = parseFloat(d.dataset.lat); var destLon = parseFloat(d.dataset.lon); if (!isNaN(sourceLat) && !isNaN(sourceLon) && !isNaN(destLat) && !isNaN(destLon)) { var plot = document.getElementById('plotRouteBtn'); if (plot) plot.click(); } } swapBtn.addEventListener('click', swapInputs); })(); // Recenter FAB behavior (function(){ var recenter = document.getElementById('recenterBtn'); if (!recenter) return; recenter.addEventListener('click', function(){ if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position){ var lat = position.coords.latitude; var lon = position.coords.longitude; map.setView([lat, lon], Math.max(map.getZoom(), 14)); }); } }); })(); // Mobile panel toggle (portrait) try { var panel = document.querySelector('.nav-panel'); var toggleBtn = document.getElementById('panelToggle'); function isSmallPortrait() { var mqW = window.matchMedia('(max-width: 576px)'); var mqP = window.matchMedia('(orientation: portrait)'); return (mqW.matches && mqP.matches); } // Initialize collapsed state on load for small portrait if (panel && isSmallPortrait()) { panel.classList.add('collapsed'); if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'false'); } // Auto-collapse panel when user hits Plot on small portrait var plotBtn = document.getElementById('plotRouteBtn'); if (plotBtn) { plotBtn.addEventListener('click', function(){ if (panel && isSmallPortrait()) { panel.classList.add('collapsed'); if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'false'); } }); } if (toggleBtn && panel) { toggleBtn.addEventListener('click', function() { panel.classList.toggle('collapsed'); var expanded = !panel.classList.contains('collapsed'); toggleBtn.setAttribute('aria-expanded', expanded ? 'true' : 'false'); }); } // When orientation/viewport changes, ensure panel doesn't exceed screen window.addEventListener('resize', function(){ if (!panel) return; if (isSmallPortrait()) { // Keep collapsed if it would cover map too much if (!panel.classList.contains('collapsed')) panel.classList.add('collapsed'); if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'false'); } }); } catch (_) {} });