import { ActivityStats } from '../types'; export const parseGpxFile = async (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { try { const text = e.target?.result as string; const parser = new DOMParser(); const xmlDoc = parser.parseFromString(text, 'text/xml'); const trkpts = Array.from(xmlDoc.getElementsByTagName('trkpt')); if (trkpts.length === 0) { // Fallback for rtept if no trkpt const rtepts = Array.from(xmlDoc.getElementsByTagName('rtept')); if (rtepts.length === 0) { throw new Error('No track points found in GPX'); } } let totalDistance = 0; let totalTime = 0; let elevationGain = 0; let startTime: Date | null = null; let endTime: Date | null = null; let lastEle: number | null = null; for (let i = 0; i < trkpts.length; i++) { const lat1 = parseFloat(trkpts[i].getAttribute('lat') || '0'); const lon1 = parseFloat(trkpts[i].getAttribute('lon') || '0'); const ele = parseFloat(trkpts[i].getElementsByTagName('ele')[0]?.textContent || '0'); const timeStr = trkpts[i].getElementsByTagName('time')[0]?.textContent; if (i > 0) { const lat2 = parseFloat(trkpts[i - 1].getAttribute('lat') || '0'); const lon2 = parseFloat(trkpts[i - 1].getAttribute('lon') || '0'); totalDistance += getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2); // Elevation gain if (lastEle !== null && ele > lastEle) { elevationGain += (ele - lastEle); } } if (timeStr) { const time = new Date(timeStr); if (!startTime) startTime = time; endTime = time; } if (!isNaN(ele)) lastEle = ele; } if (startTime && endTime) { totalTime = (endTime.getTime() - startTime.getTime()); // ms } resolve({ distance: `${totalDistance.toFixed(2)} km`, duration: msToTime(totalTime), elevation: `${Math.round(elevationGain)}m`, }); } catch (error) { reject(error); } }; reader.onerror = () => reject(new Error('Error reading file')); reader.readAsText(file); }); }; // Haversine formula function getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number) { const R = 6371; // Radius of the earth in km const dLat = deg2rad(lat2 - lat1); const dLon = deg2rad(lon2 - lon1); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const d = R * c; // Distance in km return d; } function deg2rad(deg: number) { return deg * (Math.PI / 180); } function msToTime(duration: number) { if (duration <= 0) return "0h 00m"; const minutes = Math.floor((duration / (1000 * 60)) % 60); const hours = Math.floor((duration / (1000 * 60 * 60)) % 24); return `${hours}h ${minutes}m`; }