TimeZoneGPXAPI example
by Mapycz
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Simple map in Leaflet</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha256-sA+zWATbFveLLNqWO2gtiw3HL/lh1giY/Inf1BJ0z14=" crossorigin="" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg=" crossorigin=""></script>
</head>
<body>
<div class="app">
<div id="map"></div>
<aside>
<h1>Activities (sorted by UTC)</h1>
<div class="hint">
Displaying <b>local time</b> and <b>UTC offset</b> at start location. Order is determined by <b>UTC time</b>.
</div>
<button class="zoom-all-btn" onclick="zoomToAll()">π Show all activities</button>
<div id="list" class="list" aria-live="polite"></div>
</aside>
</div>
</body>
</html>
CSS
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; color: #111; }
.app {
display: grid;
grid-template-columns: 1fr 360px;
grid-template-rows: 100vh;
width: 100vw; height: 100vh;
}
#map { width: 100%; height: 100%; }
aside {
border-left: 1px solid #e5e7eb;
background: #fafafa;
padding: 12px;
overflow: auto;
}
h1 { font-size: 16px; margin: 0 0 8px; }
.hint { font-size: 12px; color: #555; margin-bottom: 12px; }
.list { display: flex; flex-direction: column; gap: 8px; }
.item {
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 10px 12px;
cursor: pointer;
transition: box-shadow .15s ease, border-color .15s ease;
}
.item:hover { box-shadow: 0 2px 12px rgba(0,0,0,.06); border-color: #d1d5db; }
.item.active { border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.15); }
.row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.name { font-weight: 600; }
.meta { font-size: 12px; color: #444; }
.tz { font-size: 12px; color: #6b7280; }
.zoom-all-btn {
background: #2563eb;
color: white;
border: none;
border-radius: 8px;
padding: 8px 16px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
margin-bottom: 12px;
width: 100%;
transition: background-color .15s ease;
}
.zoom-all-btn:hover { background: #1d4ed8; }
.zoom-all-btn:active { background: #1e40af; }
@media (max-width: 900px) {
.app { grid-template-columns: 1fr 280px; grid-template-rows: 100vh; }
aside { width: 280px; }
}
@media (max-width: 600px) {
.app { grid-template-columns: 1fr 240px; grid-template-rows: 100vh; }
aside { width: 240px; font-size: 14px; }
...
JavaScript
// replace with your own API keyyyy
const API_KEY =
"eyJpIjoyNTcsImMiOjE2Njc0ODU2MjN9.c_UlvdpHGTI_Jb-TNMYlDYuIkCLJaUpi911RdlwPsAY"
// === MAIN TUTORIAL FUNCTION ===
// This demonstrates the complete workflow of timezone-aware GPX activity processing
async function runTimeZoneDemo() {
console.log('π Starting TimeZone Demo...');
// Step 1: Initialize map and draw activity routes
console.log('π Step 1: Initialize map and draw routes');
const map = initializeMap();
const layerManager = drawActivityRoutes(map, activities);
// Step 2: Fetch timezone information for all activities
console.log('π Step 2: Fetch timezone data for start locations');
const activitiesWithTimezones = await enrichActivitiesWithTimezones(activities);
// Step 3: Sort activities by UTC time (not local time!)
console.log('π Step 3: Sort activities by UTC time');
const sortedActivities = sortActivitiesByUtc(activitiesWithTimezones);
// Step 4: Render the activity list with local times
console.log('π Step 4: Render activity list');
renderActivityList(sortedActivities, layerManager);
// Step 5: Show all activities on map by default
console.log('πΊοΈ Step 5: Display all activities');
zoomToAllActivities(layerManager);
console.log('β
Demo completed! Key insight: Activities sorted by UTC, not local time.');
return { map, layerManager, activities: sortedActivities };
}
// === Helper Functions ===
function pad2(n){ return String(n).padStart(2,'0'); }
function formatUtcOffset(offsetSeconds) {
const sign = offsetSeconds >= 0 ? '+' : '-';
const abs = Math.abs(offsetSeconds);
const h = Math.floor(abs / 3600);
const m = Math.floor((abs % 3600) / 60);
return `UTC${sign}${pad2(h)}:${pad2(m)}`;
}
function formatLocal(dt, locale='en-GB') {
// format: DD. MM. YYYY HH:mm
// NOTE:...