diff options
-rwxr-xr-x | index.html | 226 |
1 files changed, 81 insertions, 145 deletions
@@ -1,160 +1,96 @@ <!DOCTYPE html> -<html lang="en"> +<html> <head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Calimoto GPX to Google Maps - Smart Routing</title> - <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/> + <title>GPX to Google Directions</title> <style> - body { - font-family: Arial, sans-serif; - margin: 1em; - } - label, select, input[type="file"] { - margin-bottom: 1em; - display: block; - width: 100%; - font-size: 1rem; - padding: 10px; - } - #map { - width: 100%; - height: 40vh; - margin-top: 1em; - border: 1px solid #ccc; - } - a { - word-break: break-word; - color: #007BFF; - text-decoration: none; - } - a:hover { - text-decoration: underline; - } + body { font-family: Arial, sans-serif; margin: 2rem; } + input[type="file"] { margin: 1rem 0; } + #output { margin-top: 1rem; word-break: break-word; max-width: 100%; } </style> </head> <body> -<h1>Calimoto GPX to Google Maps Directions</h1> -<div class="container"> - <label for="gpxfile">Upload GPX File:</label> - <input type="file" id="gpxfile" accept=".gpx"/> - <div id="result"></div> - <div id="map"></div> -</div> -<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> -<script> - let map = L.map('map').setView([46.962153, 7.446944], 13); - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors' - }).addTo(map); - let routeLine; - - function getDistance(lat1, lon1, lat2, lon2) { - const toRad = deg => deg * Math.PI / 180; - const R = 6371e3; // meters - const dLat = toRad(lat2 - lat1); - const dLon = toRad(lon2 - lon1); - const a = Math.sin(dLat/2)**2 + - Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * - Math.sin(dLon/2)**2; - const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - return R * c; - } - - function downsampleWaypoints(coords, max = 21) { - if (coords.length <= max) return coords; - const interval = coords.length / max; - const result = []; - for (let i = 0; i < max; i++) { - const index = Math.round(i * interval); - if (index < coords.length) result.push(coords[index]); + <h2>Upload GPX File</h2> + <input type="file" id="gpxFile" accept=".gpx" /> + <div id="output"></div> + + <script> + function haversine(lat1, lon1, lat2, lon2) { + const R = 6371000; // meters + const toRad = x => x * Math.PI / 180; + const dLat = toRad(lat2 - lat1); + const dLon = toRad(lon2 - lon1); + const a = Math.sin(dLat/2)**2 + + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * + Math.sin(dLon/2)**2; + return 2 * R * Math.asin(Math.sqrt(a)); } - return result; - } - - document.getElementById('gpxfile').addEventListener('change', function (event) { - const file = event.target.files[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = function (e) { - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(e.target.result, "application/xml"); - - const routePoints = xmlDoc.getElementsByTagName('rtept'); - if (routePoints.length < 3) { - document.getElementById('result').innerHTML = "Not enough <rtept> points."; - return; + + function interpolatePoints(points, targetCount) { + const distances = [0]; + for (let i = 1; i < points.length; i++) { + const d = haversine(points[i-1].lat, points[i-1].lon, points[i].lat, points[i].lon); + distances.push(distances[i-1] + d); } - const coords = []; - for (let i = 0; i < routePoints.length; i++) { - const lat = routePoints[i].getAttribute('lat'); - const lon = routePoints[i].getAttribute('lon'); - coords.push(lat + "," + lon); + const totalDistance = distances[distances.length - 1]; + const interval = totalDistance / (targetCount - 1); + const result = []; + + let targetDist = 0; + let j = 0; + + for (let i = 0; i < targetCount; i++) { + while (j < distances.length - 1 && distances[j+1] < targetDist) j++; + + const d1 = distances[j]; + const d2 = distances[j+1]; + const p1 = points[j]; + const p2 = points[j+1]; + + const ratio = (targetDist - d1) / (d2 - d1); + const lat = p1.lat + ratio * (p2.lat - p1.lat); + const lon = p1.lon + ratio * (p2.lon - p1.lon); + result.push({ lat, lon }); + + targetDist += interval; } - const endCoord = coords[coords.length - 1]; - - navigator.geolocation.getCurrentPosition(function (position) { - const userLat = position.coords.latitude; - const userLon = position.coords.longitude; - let closestIndex = 0; - let minDist = Infinity; - - for (let i = 0; i < coords.length; i++) { - const [lat, lon] = coords[i].split(',').map(Number); - const dist = getDistance(userLat, userLon, lat, lon); - if (dist < minDist) { - minDist = dist; - closestIndex = i; - } - } + return result; + } + + document.getElementById('gpxFile').addEventListener('change', function(event) { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = function(e) { + const parser = new DOMParser(); + const xml = parser.parseFromString(e.target.result, "application/xml"); + const rtepts = Array.from(xml.getElementsByTagName('rtept')); - // After finding closestIndex - const lookahead = 10; - let forwardIndex = closestIndex; - - for (let i = closestIndex + 1; i < Math.min(closestIndex + lookahead, coords.length); i++) { - const [lat, lon] = coords[i].split(',').map(Number); - const dist = getDistance(userLat, userLon, lat, lon); - // Prefer slightly farther point if it's still reasonably close and farther along - if (dist < minDist * 1.5) { - forwardIndex = i; - minDist = dist; - } + if (rtepts.length < 2) { + document.getElementById('output').textContent = "GPX file must contain at least 2 <rtept> points."; + return; } - const remainingCoords = coords.slice(forwardIndex); - const selectedCoords = downsampleWaypoints(remainingCoords); - - const startCoord = "Current+Location"; - const leafletStartCoord = `${userLat},${userLon}`; - const fullCoords = [startCoord, ...selectedCoords, endCoord]; - - const baseUrl = "https://www.google.com/maps/dir/"; - const url = baseUrl + fullCoords.join('/'); - - document.getElementById('result').innerHTML = ` - <p><strong>Directions Link:</strong></p> - <p><a href="${url}" target="_blank">${url}</a></p> - `; - - // Draw preview - const latLngs = [leafletStartCoord, ...selectedCoords, endCoord].map(pt => { - const [lat, lon] = pt.split(',').map(Number); - return [lat, lon]; - }); - - if (routeLine) map.removeLayer(routeLine); - routeLine = L.polyline(latLngs, {color: 'blue', weight: 4}).addTo(map); - map.fitBounds(routeLine.getBounds()); - }, function (error) { - document.getElementById('result').innerHTML = "Error fetching location: " + error.message; - }); - }; - reader.readAsText(file); - }); -</script> + const points = rtepts.map(pt => ({ + lat: parseFloat(pt.getAttribute('lat')), + lon: parseFloat(pt.getAttribute('lon')) + })); + + const maxPoints = 25; + const sampled = interpolatePoints(points, maxPoints); + + const waypoints = sampled.map(p => `${p.lat},${p.lon}`).join('/'); + + const directionsUrl = `https://www.google.com/maps/dir/${waypoints}`; + + document.getElementById('output').innerHTML = + `<strong>Google Directions URL:</strong><br><a href="${directionsUrl}" target="_blank">${directionsUrl}</a>`; + }; + + reader.readAsText(file); + }); + </script> </body> -</html>
\ No newline at end of file +</html> |