UNPKG

simple-elevation-chart

Version:

Very simple SVG-based elevation chart

86 lines (77 loc) 2.96 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>📈 Simple Elevation Chart</title> <style> elevation-chart object { width: 100%; } </style> </head> <body> <elevation-chart data-src="./tappa-10-da-villacidro-monti-mannu.geojson"></elevation-chart> <elevation-chart data-src="./Semi_shirin_yoku.geojson"></elevation-chart> <elevation-chart data-src="./Montagne_noire_blanche.geojson"></elevation-chart> <elevation-chart data-src="./Montagne_noire_blanche.gpx"></elevation-chart> <script type="module"> import { parseGPX } from "./gpxjs.js" document.querySelectorAll('elevation-chart').forEach((el) => { fetch(el.dataset.src) .then(async (response) => { if (el.dataset.src.endsWith('.gpx')) { const GPXContent = await response.text() const [parsedFile, error] = parseGPX(GPXContent) if (error) throw error const geojson = parsedFile.toGeoJSON() return geojson.features[0] } else { return response.json() } }) .then((jsonData) => { const coordinates = jsonData.geometry.coordinates const data = [] let prev let dist = 0 for (const [lon, lat, ele] of coordinates) { if (!ele) { // Some random points might not have elevation, // should we update `prev` in that case? continue } if (prev) { dist = haversineDistance(lat, lon, prev.lat, prev.lon) } data.push([ ele, dist ]) prev = { lon, lat, ele } } import('./elevation-chart.js').then(() => { // The use of an event is necessary because setting it // as a data-attr leads to race condition with the dynamic // build of the chart. const event = new CustomEvent('DataAvailable', { detail: { data } }) el.dispatchEvent(event) }) }) }) function haversineDistance(lat1, lon1, lat2, lon2) { const R = 6371 // Radius of Earth in kilometers // Convert degrees to radians const toRadians = (angle) => angle * (Math.PI / 180) const dLat = toRadians(lat2 - lat1) const dLon = toRadians(lon2 - lon1) const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2) const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) const distance = R * c * 1000 // Distance in meters return Math.round(distance) } </script> </body> </html>