Human: Build me an artifact with no react that uses JavaScript to convert a GPX file to an html table displaying the date, location in latitude, longitude and the location in plain text. The exact location will be determined with Google Maps API. I will provide the Google API key. This artifact will allow me to upload the GPX file. Make it mobile friendly and big and obvious.
Claude: Created an HTML/JavaScript artifact for GPX file conversion with mobile-friendly design and Google Maps API integration.
Human: it displays an error "Error: Geocoding error: TypeError: Failed to fetch"
Claude: Explained that the error was likely due to CORS restrictions and suggested using a server-side proxy approach.
Human: revert to previous version, display the date and time in human format, make the table wider. Add the possibility to export the table in CSV, with the date suitable for excel
Claude: Updated the artifact with:
- Wider container
- Improved date formatting
- CSV export functionality
- Excel-compatible date format
- Human-readable date display
Human: there should be a table for each day, to increase readability
Claude: Modified the artifact to:
- Create separate tables for each day
- Add date headers for each table
- Improve overall readability
- Update CSV export to include date and time
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GPX File Converter</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #f4f4f4;
padding: 20px;
}
.container {
max-width: 1200px;
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.daily-table-container {
margin-bottom: 20px;
}
@media (max-width: 600px) {
.container {
padding: 15px;
}
}
</style>
</head>
<body>
<div class="container text-center">
<h1 class="mb-4">GPX File Converter</h1>
<input
type="file"
id="gpxFileInput"
accept=".gpx"
class="form-control mb-3"
>
<button
id="convertBtn"
class="btn btn-primary btn-lg mb-3"
>
Convert GPX
</button>
<input
type="text"
id="googleApiKey"
placeholder="Enter Google Maps API Key"
class="form-control mb-3"
>
<div class="d-flex justify-content-end mb-2">
<button
id="exportCsvBtn"
class="btn btn-success"
disabled
>
Export to CSV
</button>
</div>
<div id="locationTablesContainer"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
const gpxFileInput = document.getElementById('gpxFileInput');
const convertBtn = document.getElementById('convertBtn');
const exportCsvBtn = document.getElementById('exportCsvBtn');
const googleApiKeyInput = document.getElementById('googleApiKey');
const locationTablesContainer = document.getElementById('locationTablesContainer');
let processedLocations = [];
function formatDate(isoString) {
if (!isoString) return {
date: 'N/A',
time: 'N/A',
excel: 'N/A',
dateKey: 'Unknown'
};
const date = new Date(isoString);
return {
date: date.toLocaleDateString(),
time: date.toLocaleTimeString(),
excel: date.toISOString().replace('T', ' ').split('.')[0],
dateKey: date.toISOString().split('T')[0]
};
}
function parseGPX(gpxText) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(gpxText, 'text/xml');
const trackPoints = xmlDoc.querySelectorAll('trkpt');
return Array.from(trackPoints).map(point => ({
lat: parseFloat(point.getAttribute('lat')),
lon: parseFloat(point.getAttribute('lon')),
time: point.querySelector('time')?.textContent
}));
}
async function getLocation(lat, lon) {
try {
const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lon}&key=${googleApiKeyInput.value}`;
const response = await fetch(url);
const data = await response.json();
return data.results[0]?.formatted_address || 'Location not found';
} catch (error) {
console.error('Geocoding error:', error);
return 'Unable to retrieve location';
}
}
convertBtn.addEventListener('click', async () => {
const file = gpxFileInput.files[0];
const apiKey = googleApiKeyInput.value;
if (!file || !apiKey) {
alert('Please select a GPX file and enter Google API Key');
return;
}
const reader = new FileReader();
reader.onload = async (e) => {
const gpxText = e.target.result;
const locations = parseGPX(gpxText);
processedLocations = [];
locationTablesContainer.innerHTML = '';
const locationsByDay = {};
for (const loc of locations) {
const formattedDate = formatDate(loc.time);
const address = await getLocation(loc.lat, loc.lon);
const processedLocation = {
date: formattedDate.date,
time: formattedDate.time,
dateExcel: formattedDate.excel,
lat: loc.lat,
lon: loc.lon,
address: address,
dateKey: formattedDate.dateKey
};
if (!locationsByDay[processedLocation.dateKey]) {
locationsByDay[processedLocation.dateKey] = [];
}
locationsByDay[processedLocation.dateKey].push(processedLocation);
processedLocations.push(processedLocation);
}
Object.keys(locationsByDay).forEach(dateKey => {
const dayLocations = locationsByDay[dateKey];
const tableContainer = document.createElement('div');
tableContainer.className = 'daily-table-container';
const dateHeader = document.createElement('h3');
dateHeader.textContent = `Locations on ${dayLocations[0].date}`;
tableContainer.appendChild(dateHeader);
const table = document.createElement('table');
table.className = 'table table-striped table-hover';
table.innerHTML = `
<thead>
<tr>
<th>Time</th>
<th>Latitude</th>
<th>Longitude</th>
<th>Location</th>
</tr>
</thead>
<tbody></tbody>
`;
const tbody = table.querySelector('tbody');
dayLocations.forEach(loc => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${loc.time}</td>
<td>${loc.lat.toFixed(6)}</td>
<td>${loc.lon.toFixed(6)}</td>
<td>${loc.address}</td>
`;
tbody.appendChild(row);
});
tableContainer.appendChild(table);
locationTablesContainer.appendChild(tableContainer);
});
exportCsvBtn.disabled = false;
};
reader.readAsText(file);
});
exportCsvBtn.addEventListener('click', () => {
const csvContent = [
'Date,Time,Latitude,Longitude,Location'
].concat(
processedLocations.map(loc =>
`"${loc.date}","${loc.time}",${loc.lat},${loc.lon},"${loc.address}"`
)
).join('\n');
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', 'gpx_locations.csv');
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
</script>
</body>
</html>
- GPX file upload
- Google Maps API integration
- Daily location tables
- CSV export
- Mobile-friendly design
- Detailed location information