-
- NÄCHSTER HALT
+ // Build next stop information if available
+ let nextStopInfo = '';
+ if (movement.nextStopovers && Array.isArray(movement.nextStopovers) && movement.nextStopovers.length > 0) {
+ const nextStop = movement.nextStopovers[0];
+ if (nextStop.stop && nextStop.stop.name) {
+ const arrivalTime = nextStop.arrival ?
+ new Date(nextStop.arrival).toLocaleTimeString('de-DE', {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ }) : '—';
+ const safeStopName = escapeHtml(nextStop.stop.name);
+ const safeArrivalTime = escapeHtml(arrivalTime);
+
+ nextStopInfo = `
+
+
+ NÄCHSTER HALT
+
+
+ ${safeStopName}
+
+
+ Ankunft: ${safeArrivalTime}
+
-
- ${nextStop.stop.name}
-
-
- Ankunft: ${arrivalTime}
-
-
- `;
+ `;
+ }
}
+
+ const popupContent = `
+
+
${safeIcon}
+
+ ${productName}
+
+
+ ${safeLineName}
+
+
+ → ${direction}
+
+ ${nextStopInfo}
+
+ `;
+ marker.bindPopup(popupContent, {
+ maxWidth: 300,
+ className: 'custom-popup'
+ });
+
+ vehicleMarkers[vehicleId] = {
+ marker: marker,
+ type: type
+ };
+ } catch (markerError) {
+ console.error('Fehler beim Erstellen des Markers:', markerError, movement);
+ // Continue with next vehicle instead of crashing
}
-
- const popupContent = `
-
-
${icon}
-
- ${productName}
-
-
- ${lineName}
-
-
- → ${direction}
-
- ${nextStopInfo}
-
- `;
- marker.bindPopup(popupContent, {
- maxWidth: 300,
- className: 'custom-popup'
- });
-
- vehicleMarkers[vehicleId] = {
- marker: marker,
- type: type
- };
}
}
});
@@ -704,16 +940,39 @@
} catch (error) {
// Handle different error types
+ let errorMessage = '';
+ let shouldRetry = false;
+
if (error.name === 'AbortError') {
console.warn('Request timeout - Fahrzeugdaten konnten nicht geladen werden');
+ errorMessage = 'Zeitüberschreitung - versuche erneut...';
+ shouldRetry = true;
} else if (error instanceof TypeError && error.message.includes('fetch')) {
console.error('Netzwerkfehler - Bitte Internetverbindung prüfen:', error);
+ errorMessage = 'Netzwerkfehler - bitte Verbindung prüfen';
+ shouldRetry = true;
} else {
console.error('Fehler beim Laden der Fahrzeugdaten:', error);
+ errorMessage = 'Fehler beim Laden der Daten';
+ shouldRetry = true;
}
- // Show user-friendly error in UI (optional)
- // You could add an error notification here
+ // Retry logic
+ if (shouldRetry && attempt < MAX_RETRIES) {
+ retryCount++;
+ console.log(`Wiederhole Anfrage (${retryCount}/${MAX_RETRIES}) in ${RETRY_DELAY/1000}s...`);
+ showErrorMessage(`${errorMessage} (Versuch ${retryCount}/${MAX_RETRIES})`);
+
+ setTimeout(() => {
+ loadRadarData(attempt + 1);
+ }, RETRY_DELAY);
+ } else if (attempt >= MAX_RETRIES) {
+ // Max retries reached
+ retryCount = 0;
+ showErrorMessage('Fehler: Maximale Anzahl Wiederholungen erreicht');
+ } else {
+ showErrorMessage(errorMessage);
+ }
} finally {
hideLoading();
}
@@ -806,7 +1065,19 @@
},
// Error callback
(error) => {
- console.warn('Standort nicht verfügbar:', error.message);
+ let errorMsg = 'Standort nicht verfügbar';
+ switch(error.code) {
+ case error.PERMISSION_DENIED:
+ errorMsg = 'Standortzugriff verweigert';
+ break;
+ case error.POSITION_UNAVAILABLE:
+ errorMsg = 'Standort nicht verfügbar';
+ break;
+ case error.TIMEOUT:
+ errorMsg = 'Standortabfrage Timeout';
+ break;
+ }
+ console.warn(errorMsg + ':', error.message);
// Load data with default Berlin view
loadRadarData();
},
@@ -856,40 +1127,57 @@
}
}
- // ===== Event Listeners =====
+ // ===== Cleanup Functions =====
/**
- * Debounced map movement handler
- * Reloads vehicle data when map stops moving
+ * Clean up intervals and event listeners
+ * Called when page is unloaded
*/
- let moveEndTimeout;
- map.on('moveend', () => {
- clearTimeout(moveEndTimeout);
- moveEndTimeout = setTimeout(() => {
- loadRadarData();
- }, 300);
- });
+ function cleanup() {
+ if (clockInterval) {
+ clearInterval(clockInterval);
+ clockInterval = null;
+ }
+ if (dataUpdateInterval) {
+ clearInterval(dataUpdateInterval);
+ dataUpdateInterval = null;
+ }
+ console.log('Cleanup abgeschlossen');
+ }
// ===== Application Startup =====
- // Initialize clock display
- updateClock();
+ // Initialize the application
+ initializeApp();
- // Get user location and load initial data
- getUserLocation();
+ // Cleanup on page unload
+ window.addEventListener('beforeunload', cleanup);
- // Update clock every second
- setInterval(updateClock, 1000);
-
- // Refresh vehicle data every 15 seconds
- setInterval(() => {
- if (!isLoading) {
- loadRadarData();
+ // Handle visibility change to pause/resume updates
+ document.addEventListener('visibilitychange', () => {
+ if (document.hidden) {
+ // Page is hidden - pause updates
+ if (dataUpdateInterval) {
+ clearInterval(dataUpdateInterval);
+ dataUpdateInterval = null;
+ }
+ console.log('Updates pausiert (Tab versteckt)');
+ } else {
+ // Page is visible - resume updates
+ if (!dataUpdateInterval) {
+ dataUpdateInterval = setInterval(() => {
+ if (!isLoading) {
+ loadRadarData();
+ }
+ }, 15000);
+ }
+ // Load data immediately when tab becomes visible
+ if (!isLoading && map) {
+ loadRadarData();
+ }
+ console.log('Updates fortgesetzt (Tab sichtbar)');
}
- }, 15000);
-
- // Log application start
- console.log('Berlin Live Transit gestartet');
+ });