simple-elevation-chart
Version:
Very simple SVG-based elevation chart
86 lines (77 loc) • 2.96 kB
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>