diff --git a/app.js b/app.js
index 0f1bede..55221f0 100644
--- a/app.js
+++ b/app.js
@@ -36,31 +36,6 @@ const symbols = {
regional: '🚆', express: '🚄', longDistance: '🚅', ferry: '🛥️'
};
-// =============================
-// Aktive Filter
-// =============================
-let activeProducts = Array.from(document.querySelectorAll('#controls input[type="checkbox"]'))
- .filter(c => c.checked)
- .map(c => c.value);
-
-// Checkbox Event
-document.querySelectorAll('#controls input[type="checkbox"]').forEach(cb => {
- cb.addEventListener('change', () => {
- activeProducts = Array.from(document.querySelectorAll('#controls input[type="checkbox"]'))
- .filter(c => c.checked)
- .map(c => c.value);
-
- Object.values(vehicleMarkers).forEach(marker => {
- const prod = marker.options.vehicleProduct || '';
- if (activeProducts.includes(prod)) {
- if (!map.hasLayer(marker)) map.addLayer(marker);
- } else {
- if (map.hasLayer(marker)) map.removeLayer(marker);
- }
- });
- });
-});
-
// =============================
// Hilfsfunktionen
// =============================
@@ -78,7 +53,7 @@ function getLineColor(lineName, product) {
}
function createDivIcon(vehicle) {
- const product = vehicle.line?.product || '';
+ const product = vehicle.line?.product;
const lineName = vehicle.line?.name || '?';
const symbol = symbols[product] || '❓';
@@ -104,9 +79,7 @@ function createDivIcon(vehicle) {
`;
- const icon = L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
- icon.product = product;
- return icon;
+ return L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
}
const lineColor = getLineColor(lineName, product);
@@ -119,9 +92,7 @@ function createDivIcon(vehicle) {
`;
- const icon = L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
- icon.product = product;
- return icon;
+ return L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
}
// =============================
@@ -149,18 +120,16 @@ async function loadVehicles() {
if (vehicleMarkers[id]) {
vehicleMarkers[id].setLatLng([loc.latitude, loc.longitude]);
} else {
- const marker = L.marker([loc.latitude, loc.longitude], { icon });
- marker.options.vehicleProduct = vehicle.line?.product || '';
- if (activeProducts.includes(marker.options.vehicleProduct)) {
- marker.addTo(map);
- }
+ const marker = L.marker([loc.latitude, loc.longitude], { icon })
+ .bindPopup(`Linie: ${vehicle.line?.name || 'unbekannt'}
Typ: ${vehicle.line?.product || 'unbekannt'}
Richtung: ${vehicle.direction || 'unbekannt'}`)
+ .addTo(vehiclesLayer);
vehicleMarkers[id] = marker;
}
});
Object.keys(vehicleMarkers).forEach(id => {
if (!newIds.has(id)) {
- if (map.hasLayer(vehicleMarkers[id])) map.removeLayer(vehicleMarkers[id]);
+ vehiclesLayer.removeLayer(vehicleMarkers[id]);
delete vehicleMarkers[id];
}
});
@@ -188,3 +157,69 @@ function locateAndLoad() {
locateAndLoad();
setInterval(loadVehicles, 30000);
map.on('moveend', loadVehicles);
+
+// =============================
+// Bahnhöfe mit Live-Abfahrten
+// =============================
+const stations = [
+ { name: "Berlin Zoologischer Garten", id: "900023201", coords: [52.5069, 13.3326] },
+ { name: "Berlin Alexanderplatz", id: "900100003", coords: [52.5215, 13.4115] },
+ { name: "Berlin Gesundbrunnen", id: "900007102", coords: [52.5483, 13.3889] },
+ { name: "Berlin Spandau", id: "900029101", coords: [52.5341, 13.1977] },
+ { name: "Berlin Südkreuz", id: "900058101", coords: [52.4752, 13.3653] },
+ { name: "Berlin Ostbahnhof", id: "900100004", coords: [52.5100, 13.4340] }
+];
+
+async function loadStationDepartures(stationId, marker, stationName) {
+ const symbols = {
+ bus: '🚌', tram: '🚎', subway: '🚉', suburban: '🚋',
+ regional: '🚆', express: '🚄', longDistance: '🚅', ferry: '🛥️'
+ };
+
+ try {
+ const res = await fetch(`https://v6.vbb.transport.rest/stops/${stationId}/departures?duration=30&results=10`);
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ const data = await res.json();
+ const departures = data.departures || [];
+
+ let html = `${stationName}
`;
+ html += `
`;
+ html += `| Linie | Richtung | Zeit |
`;
+
+ departures.forEach((dep, index) => {
+ const line = dep.line?.name || "?";
+ const product = dep.line?.product;
+ const icon = symbols[product] || '❓';
+ const direction = dep.direction || "?";
+ const when = dep.when ? new Date(dep.when) : null;
+ const planned = dep.plannedWhen ? new Date(dep.plannedWhen) : null;
+ const delay = when && planned ? Math.round((when - planned) / 60000) : 0;
+ const timeStr = when ? when.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }) : "n/a";
+ const delayStr = delay > 0 ? `+${delay} min` : "";
+
+ const color = getLineColor(line, product);
+ const bg = index % 2 === 0 ? '#f9f9f9' : '#fff';
+
+ html += `
+ | ${icon} ${line} |
+ ${direction} |
+ ${timeStr} ${delayStr} |
+
`;
+ });
+
+ html += `
`;
+ marker.setPopupContent(html).openPopup();
+ } catch (err) {
+ marker.setPopupContent(`${stationName}
Fehler beim Laden`);
+ console.error(err);
+ }
+}
+
+
+stations.forEach(station => {
+ const marker = L.marker(station.coords)
+ .addTo(map)
+ .bindPopup(`${station.name}
Lade Abfahrten...`);
+
+ marker.on('click', () => loadStationDepartures(station.id, marker, station.name));
+});
diff --git a/index.html b/index.html
index 4fc4d5c..8dcc62a 100644
--- a/index.html
+++ b/index.html
@@ -8,8 +8,6 @@
-
-
@@ -17,7 +15,9 @@
+
+
diff --git a/old/README.md b/old/README.md
deleted file mode 100644
index 9030bd8..0000000
--- a/old/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# VBB-Live-Maps
-VBB Live Maps ist eine interaktive Live-Karte, die Fahrzeuge des Berliner Nahverkehrs (z. B. Busse, U-Bahnen, S-Bahnen etc.) in Echtzeit anzeigt.
-
-https://vbb-live-maps.netlify.app/
diff --git a/old/VBB-Live-Maps-BG/app.js b/old/VBB-Live-Maps-BG/app.js
deleted file mode 100644
index 31fc441..0000000
--- a/old/VBB-Live-Maps-BG/app.js
+++ /dev/null
@@ -1,224 +0,0 @@
-// =============================
-// Karte initialisieren
-// =============================
-const map = L.map('map', { zoomControl: false }).setView([52.52, 13.405], 13);
-
-L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 19,
- attribution: '© OpenStreetMap contributors'
-}).addTo(map);
-
-
-const vehiclesLayer = L.layerGroup().addTo(map);
-const vehicleMarkers = {};
-
-const lineColors = {
- 'S45': '#CD9C53', 'S46': '#CD9C53', 'S47': '#CD9C53', 'S6': '#CD9C53', 'S65': '#CD9C53', 'S66': '#CD9C53',
- 'S42': '#CB6418',
- 'S4': '#AD5937', 'S41': '#AD5937',
- 'U5': '#7E5330', 'U55': '#7E5330',
- 'S9': '#992746', 'S95': '#992746', 'S96': '#992746',
- 'U12': ['#7DAD4C', '#DA421E'],
- 'U2': '#DA421E',
- 'S3': '#EB7405', 'S5': '#EB7405', 'S55': '#EB7405', 'S56': '#EB7405',
- 'U9': '#F3791D',
- 'S3-wannsee': '#F0D722', 'U4': '#F0D722',
- 'U1': '#7DAD4C', 'U15': '#7DAD4C',
- 'S8': '#66AA22', 'S85': '#66AA22', 'S86': '#66AA22',
- 'S2': '#007734', 'S21': '#007734', 'S25': '#007734', 'S26': '#007734',
- 'U3': '#16683D', 'U35': '#16683D',
- 'S3-charlottenburg': '#009BD5', 'U7': '#009BD5',
- 'S10': '#0082C4', 'S19': '#0082C4',
- 'S3-berlin-schoenefeld': '#0066AD', 'S35': '#0066AD', 'S36': '#0066AD',
- 'U8': '#224F86',
- 'S7': '#816DA6', 'S75': '#816DA6', 'S76': '#816DA6',
- 'U6': '#8C6DAB',
- 'S1': '#DA6BA2', 'S15': '#DA6BA2', 'S16': '#DA6BA2', 'U0': '#DA6BA2',
- 'U10': '#808080', 'U11': '#808080',
- 'F10': '#528DBA',
- 'F11': '#528DBA',
- 'F12': '#528DBA',
- 'F21': '#528DBA',
- 'F23': '#528DBA',
- 'F24': '#528DBA'
-};
-
-const symbols = {
- bus: '🚌',
- tram: '🚎',
- subway: '🚉',
- suburban: '🚋',
- regional: '🚆',
- express: '🚄',
- longDistance: '🚅',
- ferry: '🛥️'
-};
-
-function getLineColor(lineName, product) {
- if(lineName === 'U12') return null;
-
- if(lineName.startsWith('S3 ')) {
- if(lineName.toLowerCase().includes('wannsee')) return lineColors['S3-wannsee'];
- if(lineName.toLowerCase().includes('charlottenburg') || lineName.toLowerCase().includes('schönefeld')) return lineColors['S3-berlin-schoenefeld'];
- return lineColors['S3'];
- }
-
- if(lineColors[lineName]) return lineColors[lineName];
- if(product === 'suburban') return '#CD9C53';
- if(product === 'subway') return '#7DAD4C';
- return '#666';
-}
-
-function createDivIcon(vehicle) {
- const product = vehicle.line?.product;
- const lineName = vehicle.line?.name || '?';
- const symbol = symbols[product] || '❓';
-
- if(lineName === 'U12') {
- const iconHtml = `
-
-
-
- ${symbol}
-
-
- U12
-
-
- `;
- return L.divIcon({
- html: iconHtml,
- className: '',
- iconSize: [30, 40],
- iconAnchor: [15, 20]
- });
- }
-
- const lineColor = getLineColor(lineName, product);
- const labelStyle = `background: ${lineColor}; color: white; padding: 2px 6px; border-radius: 3px; display: inline-block; font-weight: bold; font-size: 12px; user-select: none; font-family: Arial, sans-serif;`;
-
- const iconHtml = `
-
-
${symbol}
-
${lineName}
-
- `;
-
- return L.divIcon({
- html: iconHtml,
- className: '',
- iconSize: [30, 40],
- iconAnchor: [15, 20]
- });
-}
-
-async function loadVehicles() {
- const bounds = map.getBounds();
- const bbox = `north=${bounds.getNorth()}&west=${bounds.getWest()}&south=${bounds.getSouth()}&east=${bounds.getEast()}`;
-
- try {
- const res = await fetch(`https://v6.vbb.transport.rest/radar?${bbox}&results=200&duration=30`);
- const result = await res.json();
- const data = result.movements || [];
-
- const newIds = new Set();
-
- data.forEach(vehicle => {
- const id = vehicle.tripId;
- const loc = vehicle.location;
- if (!loc || !loc.latitude || !loc.longitude) return;
-
- newIds.add(id);
- const icon = createDivIcon(vehicle);
-
- if (vehicleMarkers[id]) {
- vehicleMarkers[id].setLatLng([loc.latitude, loc.longitude]);
- } else {
- const marker = L.marker([loc.latitude, loc.longitude], { icon })
- .bindPopup(`
- Linie: ${vehicle.line?.name || 'unbekannt'}
- Typ: ${vehicle.line?.product || 'unbekannt'}
- Richtung: ${vehicle.direction || 'unbekannt'}
- `)
- .addTo(vehiclesLayer);
- vehicleMarkers[id] = marker;
- }
- });
-
- Object.keys(vehicleMarkers).forEach(id => {
- if (!newIds.has(id)) {
- vehiclesLayer.removeLayer(vehicleMarkers[id]);
- delete vehicleMarkers[id];
- }
- });
- } catch (e) {
- console.error('Fehler beim Laden der Fahrzeuge:', e);
- }
-}
-
-function locateAndLoad() {
- if (!navigator.geolocation) {
- alert('Geolocation nicht unterstützt');
- loadVehicles();
- return;
- }
- navigator.geolocation.getCurrentPosition(pos => {
- const { latitude, longitude } = pos.coords;
- map.setView([latitude, longitude], 14);
-
- const locationIcon = L.divIcon({
- className: 'user-location-icon',
- iconSize: [12, 12],
- iconAnchor: [6, 6]
- });
-
- L.marker([latitude, longitude], { icon: locationIcon }).addTo(map);
- loadVehicles();
- }, () => {
- map.setView([52.52, 13.405], 13);
- loadVehicles();
- });
-}
-
-locateAndLoad();
-setInterval(loadVehicles, 610);
-map.on('moveend', loadVehicles);
-
-// ====================
-// Uhr unten rechts
-// ====================
-const ssTimeEl = document.getElementById('ss-time');
-const ssDateEl = document.getElementById('ss-date');
-
-function updateClock() {
- const now = new Date();
- ssTimeEl.textContent = now.toLocaleTimeString('de-DE', { hour12: false });
- ssDateEl.textContent = now.toLocaleDateString('de-DE', {
- weekday: 'long',
- year: 'numeric',
- month: 'long',
- day: '2-digit'
- });
-}
-
-updateClock();
-setInterval(updateClock, 1000);
-
-
-
-
-
-
-
-
-
diff --git a/old/VBB-Live-Maps-BG/index.html b/old/VBB-Live-Maps-BG/index.html
deleted file mode 100644
index 5e7fd13..0000000
--- a/old/VBB-Live-Maps-BG/index.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
- VBB Live Tracker
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/old/VBB-Live-Maps-BG/style.css b/old/VBB-Live-Maps-BG/style.css
deleted file mode 100644
index e85d1cd..0000000
--- a/old/VBB-Live-Maps-BG/style.css
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ==================== */
-/* Grundlayout */
-/* ==================== */
-html, body, #map {
- height: 100%;
- margin: 0;
- padding: 0;
-}
-
-.leaflet-marker-icon {
- transition: transform 1s linear;
-}
-
-.line-label {
- padding: 2px 6px;
- border-radius: 3px;
- font-weight: bold;
- font-size: 10px;
- display: inline-block;
- color: white;
- margin-top: 2px;
- user-select: none;
- font-family: Arial, sans-serif;
-}
-
-.user-location-icon {
- background-color: #007bff;
- border: 2px solid white;
- border-radius: 50%;
- width: 12px;
- height: 12px;
- box-shadow: 0 0 6px rgba(0, 123, 255, 0.6);
-}
-
-/* ==================== */
-/* Uhr unten rechts */
-/* ==================== */
-#clock {
- position: fixed;
- right: 40px;
- bottom: 40px;
- z-index: 9999;
- text-align: right;
- font-family: "Comic Sans MS", Comic Sans, cursive; /* Comic Sans einfügen */
- color: #ffffff;
- text-shadow: 0 0 8px rgba(0,0,0,0.7);
- user-select: none;
-
- /* Hintergrund-Box */
- background: rgba(0, 0, 0, 0.6);
- padding: 16px 24px;
- border-radius: 12px;
- backdrop-filter: blur(4px);
-
-}
-
-
-#clock .time {
- font-size: clamp(42px, 6vw, 72px);
- line-height: 1.1;
- font-weight: 700;
-}
-
-#clock .date {
- font-size: clamp(18px, 3vw, 28px);
- line-height: 1.2;
- opacity: 0.9;
-}
-
diff --git a/old/app.js b/old/app.js
deleted file mode 100644
index 55221f0..0000000
--- a/old/app.js
+++ /dev/null
@@ -1,225 +0,0 @@
-// =============================
-// Karte initialisieren
-// =============================
-const map = L.map('map').setView([52.52, 13.405], 13);
-
-L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 19,
- attribution: '© OpenStreetMap contributors'
-}).addTo(map);
-
-// Layer für Fahrzeuge
-const vehiclesLayer = L.layerGroup().addTo(map);
-const vehicleMarkers = {};
-
-// =============================
-// Farben & Symbole
-// =============================
-const lineColors = {
- 'S45': '#CD9C53', 'S46': '#CD9C53', 'S47': '#CD9C53', 'S6': '#CD9C53', 'S65': '#CD9C53', 'S66': '#CD9C53',
- 'S42': '#CB6418', 'S4': '#AD5937', 'S41': '#AD5937', 'U5': '#7E5330', 'U55': '#7E5330',
- 'S9': '#992746', 'S95': '#992746', 'S96': '#992746', 'U12': ['#7DAD4C', '#DA421E'], 'U2': '#DA421E',
- 'S3': '#EB7405', 'S5': '#EB7405', 'S55': '#EB7405', 'S56': '#EB7405', 'U9': '#F3791D',
- 'S3-wannsee': '#F0D722', 'U4': '#F0D722', 'U1': '#7DAD4C', 'U15': '#7DAD4C',
- 'S8': '#66AA22', 'S85': '#66AA22', 'S86': '#66AA22', 'S2': '#007734', 'S21': '#007734',
- 'S25': '#007734', 'S26': '#007734', 'U3': '#16683D', 'U35': '#16683D',
- 'S3-charlottenburg': '#009BD5', 'U7': '#009BD5', 'S10': '#0082C4', 'S19': '#0082C4',
- 'S3-berlin-schoenefeld': '#0066AD', 'S35': '#0066AD', 'S36': '#0066AD', 'U8': '#224F86',
- 'S7': '#816DA6', 'S75': '#816DA6', 'S76': '#816DA6', 'U6': '#8C6DAB',
- 'S1': '#DA6BA2', 'S15': '#DA6BA2', 'S16': '#DA6BA2', 'U0': '#DA6BA2',
- 'U10': '#808080', 'U11': '#808080', 'F10': '#528DBA', 'F11': '#528DBA',
- 'F12': '#528DBA', 'F21': '#528DBA', 'F23': '#528DBA', 'F24': '#528DBA'
-};
-
-const symbols = {
- bus: '🚌', tram: '🚎', subway: '🚉', suburban: '🚋',
- regional: '🚆', express: '🚄', longDistance: '🚅', ferry: '🛥️'
-};
-
-// =============================
-// Hilfsfunktionen
-// =============================
-function getLineColor(lineName, product) {
- if(lineName === 'U12') return null;
- if(lineName.startsWith('S3 ')) {
- if(lineName.toLowerCase().includes('wannsee')) return lineColors['S3-wannsee'];
- if(lineName.toLowerCase().includes('charlottenburg') || lineName.toLowerCase().includes('schönefeld')) return lineColors['S3-berlin-schoenefeld'];
- return lineColors['S3'];
- }
- if(lineColors[lineName]) return lineColors[lineName];
- if(product === 'suburban') return '#CD9C53';
- if(product === 'subway') return '#7DAD4C';
- return '#666';
-}
-
-function createDivIcon(vehicle) {
- const product = vehicle.line?.product;
- const lineName = vehicle.line?.name || '?';
- const symbol = symbols[product] || '❓';
-
- if(lineName === 'U12') {
- const iconHtml = `
-
-
-
- ${symbol}
-
-
- U12
-
-
- `;
- return L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
- }
-
- const lineColor = getLineColor(lineName, product);
- const labelStyle = `background: ${lineColor}; color: white; padding: 2px 6px; border-radius: 3px; display: inline-block; font-weight: bold; font-size: 12px; user-select: none; font-family: Arial, sans-serif;`;
-
- const iconHtml = `
-
-
${symbol}
-
${lineName}
-
- `;
-
- return L.divIcon({ html: iconHtml, className: '', iconSize: [30, 40], iconAnchor: [15, 20] });
-}
-
-// =============================
-// Fahrzeuge laden
-// =============================
-async function loadVehicles() {
- const bounds = map.getBounds();
- const bbox = `north=${bounds.getNorth()}&west=${bounds.getWest()}&south=${bounds.getSouth()}&east=${bounds.getEast()}`;
-
- try {
- const res = await fetch(`https://v6.vbb.transport.rest/radar?${bbox}&results=100&duration=30`);
- const result = await res.json();
- const data = result.movements || [];
-
- const newIds = new Set();
-
- data.forEach(vehicle => {
- const id = vehicle.tripId;
- const loc = vehicle.location;
- if (!loc || !loc.latitude || !loc.longitude) return;
-
- newIds.add(id);
- const icon = createDivIcon(vehicle);
-
- if (vehicleMarkers[id]) {
- vehicleMarkers[id].setLatLng([loc.latitude, loc.longitude]);
- } else {
- const marker = L.marker([loc.latitude, loc.longitude], { icon })
- .bindPopup(`Linie: ${vehicle.line?.name || 'unbekannt'}
Typ: ${vehicle.line?.product || 'unbekannt'}
Richtung: ${vehicle.direction || 'unbekannt'}`)
- .addTo(vehiclesLayer);
- vehicleMarkers[id] = marker;
- }
- });
-
- Object.keys(vehicleMarkers).forEach(id => {
- if (!newIds.has(id)) {
- vehiclesLayer.removeLayer(vehicleMarkers[id]);
- delete vehicleMarkers[id];
- }
- });
- } catch (e) {
- console.error('Fehler beim Laden der Fahrzeuge:', e);
- }
-}
-
-// =============================
-// Geolocation & Auto-Update
-// =============================
-function locateAndLoad() {
- if (!navigator.geolocation) {
- loadVehicles();
- return;
- }
- navigator.geolocation.getCurrentPosition(pos => {
- map.setView([pos.coords.latitude, pos.coords.longitude], 14);
- loadVehicles();
- }, () => {
- loadVehicles();
- });
-}
-
-locateAndLoad();
-setInterval(loadVehicles, 30000);
-map.on('moveend', loadVehicles);
-
-// =============================
-// Bahnhöfe mit Live-Abfahrten
-// =============================
-const stations = [
- { name: "Berlin Zoologischer Garten", id: "900023201", coords: [52.5069, 13.3326] },
- { name: "Berlin Alexanderplatz", id: "900100003", coords: [52.5215, 13.4115] },
- { name: "Berlin Gesundbrunnen", id: "900007102", coords: [52.5483, 13.3889] },
- { name: "Berlin Spandau", id: "900029101", coords: [52.5341, 13.1977] },
- { name: "Berlin Südkreuz", id: "900058101", coords: [52.4752, 13.3653] },
- { name: "Berlin Ostbahnhof", id: "900100004", coords: [52.5100, 13.4340] }
-];
-
-async function loadStationDepartures(stationId, marker, stationName) {
- const symbols = {
- bus: '🚌', tram: '🚎', subway: '🚉', suburban: '🚋',
- regional: '🚆', express: '🚄', longDistance: '🚅', ferry: '🛥️'
- };
-
- try {
- const res = await fetch(`https://v6.vbb.transport.rest/stops/${stationId}/departures?duration=30&results=10`);
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
- const data = await res.json();
- const departures = data.departures || [];
-
- let html = `${stationName}
`;
- html += ``;
- html += `| Linie | Richtung | Zeit |
`;
-
- departures.forEach((dep, index) => {
- const line = dep.line?.name || "?";
- const product = dep.line?.product;
- const icon = symbols[product] || '❓';
- const direction = dep.direction || "?";
- const when = dep.when ? new Date(dep.when) : null;
- const planned = dep.plannedWhen ? new Date(dep.plannedWhen) : null;
- const delay = when && planned ? Math.round((when - planned) / 60000) : 0;
- const timeStr = when ? when.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }) : "n/a";
- const delayStr = delay > 0 ? `+${delay} min` : "";
-
- const color = getLineColor(line, product);
- const bg = index % 2 === 0 ? '#f9f9f9' : '#fff';
-
- html += `
- | ${icon} ${line} |
- ${direction} |
- ${timeStr} ${delayStr} |
-
`;
- });
-
- html += `
`;
- marker.setPopupContent(html).openPopup();
- } catch (err) {
- marker.setPopupContent(`${stationName}
Fehler beim Laden`);
- console.error(err);
- }
-}
-
-
-stations.forEach(station => {
- const marker = L.marker(station.coords)
- .addTo(map)
- .bindPopup(`${station.name}
Lade Abfahrten...`);
-
- marker.on('click', () => loadStationDepartures(station.id, marker, station.name));
-});
diff --git a/old/app.js.backup b/old/app.js.backup
deleted file mode 100644
index b095f3c..0000000
--- a/old/app.js.backup
+++ /dev/null
@@ -1,192 +0,0 @@
-const map = L.map('map').setView([52.52, 13.405], 13);
-
-L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 19,
- attribution: '© OpenStreetMap contributors'
-}).addTo(map);
-
-const vehiclesLayer = L.layerGroup().addTo(map);
-const vehicleMarkers = {};
-
-const lineColors = {
- 'S45': '#CD9C53', 'S46': '#CD9C53', 'S47': '#CD9C53', 'S6': '#CD9C53', 'S65': '#CD9C53', 'S66': '#CD9C53',
- 'S42': '#CB6418',
- 'S4': '#AD5937', 'S41': '#AD5937',
- 'U5': '#7E5330', 'U55': '#7E5330',
- 'S9': '#992746', 'S95': '#992746', 'S96': '#992746',
- 'U12': ['#7DAD4C', '#DA421E'],
- 'U2': '#DA421E',
- 'S3': '#EB7405', 'S5': '#EB7405', 'S55': '#EB7405', 'S56': '#EB7405',
- 'U9': '#F3791D',
- 'S3-wannsee': '#F0D722', 'U4': '#F0D722',
- 'U1': '#7DAD4C', 'U15': '#7DAD4C',
- 'S8': '#66AA22', 'S85': '#66AA22', 'S86': '#66AA22',
- 'S2': '#007734', 'S21': '#007734', 'S25': '#007734', 'S26': '#007734',
- 'U3': '#16683D', 'U35': '#16683D',
- 'S3-charlottenburg': '#009BD5', 'U7': '#009BD5',
- 'S10': '#0082C4', 'S19': '#0082C4',
- 'S3-berlin-schoenefeld': '#0066AD', 'S35': '#0066AD', 'S36': '#0066AD',
- 'U8': '#224F86',
- 'S7': '#816DA6', 'S75': '#816DA6', 'S76': '#816DA6',
- 'U6': '#8C6DAB',
- 'S1': '#DA6BA2', 'S15': '#DA6BA2', 'S16': '#DA6BA2', 'U0': '#DA6BA2',
- 'U10': '#808080', 'U11': '#808080',
- 'F10': '#528DBA',
- 'F11': '#528DBA',
- 'F12': '#528DBA',
- 'F21': '#528DBA',
- 'F23': '#528DBA',
- 'F24': '#528DBA'
-};
-
-const symbols = {
- bus: '🚌',
- tram: '🚎',
- subway: '🚉',
- suburban: '🚋',
- regional: '🚆',
- express: '🚄',
- longDistance: '🚅',
- ferry: '🛥️'
-};
-
-function getLineColor(lineName, product) {
- if(lineName === 'U12') return null;
-
- if(lineName.startsWith('S3 ')) {
- if(lineName.toLowerCase().includes('wannsee')) return lineColors['S3-wannsee'];
- if(lineName.toLowerCase().includes('charlottenburg') || lineName.toLowerCase().includes('schönefeld')) return lineColors['S3-berlin-schoenefeld'];
- return lineColors['S3'];
- }
-
- if(lineColors[lineName]) return lineColors[lineName];
- if(product === 'suburban') return '#CD9C53';
- if(product === 'subway') return '#7DAD4C';
- return '#666';
-}
-
-function createDivIcon(vehicle) {
- const product = vehicle.line?.product;
- const lineName = vehicle.line?.name || '?';
- const symbol = symbols[product] || '❓';
-
- if(lineName === 'U12') {
- const iconHtml = `
-
-
-
- ${symbol}
-
-
- U12
-
-
- `;
- return L.divIcon({
- html: iconHtml,
- className: '',
- iconSize: [30, 40],
- iconAnchor: [15, 20]
- });
- }
-
- const lineColor = getLineColor(lineName, product);
- const labelStyle = `background: ${lineColor}; color: white; padding: 2px 6px; border-radius: 3px; display: inline-block; font-weight: bold; font-size: 12px; user-select: none; font-family: Arial, sans-serif;`;
-
- const iconHtml = `
-
-
${symbol}
-
${lineName}
-
- `;
-
- return L.divIcon({
- html: iconHtml,
- className: '',
- iconSize: [30, 40],
- iconAnchor: [15, 20]
- });
-}
-
-async function loadVehicles() {
- const bounds = map.getBounds();
- const bbox = `north=${bounds.getNorth()}&west=${bounds.getWest()}&south=${bounds.getSouth()}&east=${bounds.getEast()}`;
-
- try {
- const res = await fetch(`https://v6.vbb.transport.rest/radar?${bbox}&results=100&duration=30`);
- const result = await res.json();
- const data = result.movements || [];
-
- const newIds = new Set();
-
- data.forEach(vehicle => {
- const id = vehicle.tripId;
- const loc = vehicle.location;
- if (!loc || !loc.latitude || !loc.longitude) return;
-
- newIds.add(id);
- const icon = createDivIcon(vehicle);
-
- if (vehicleMarkers[id]) {
- vehicleMarkers[id].setLatLng([loc.latitude, loc.longitude]);
- } else {
- const marker = L.marker([loc.latitude, loc.longitude], { icon })
- .bindPopup(`
- Linie: ${vehicle.line?.name || 'unbekannt'}
- Typ: ${vehicle.line?.product || 'unbekannt'}
- Richtung: ${vehicle.direction || 'unbekannt'}
- `)
- .addTo(vehiclesLayer);
- vehicleMarkers[id] = marker;
- }
- });
-
- Object.keys(vehicleMarkers).forEach(id => {
- if (!newIds.has(id)) {
- vehiclesLayer.removeLayer(vehicleMarkers[id]);
- delete vehicleMarkers[id];
- }
- });
- } catch (e) {
- console.error('Fehler beim Laden der Fahrzeuge:', e);
- }
-}
-
-function locateAndLoad() {
- if (!navigator.geolocation) {
- alert('Geolocation nicht unterstützt');
- loadVehicles();
- return;
- }
- navigator.geolocation.getCurrentPosition(pos => {
- const { latitude, longitude } = pos.coords;
- map.setView([latitude, longitude], 14);
-
- const locationIcon = L.divIcon({
- className: 'user-location-icon',
- iconSize: [12, 12],
- iconAnchor: [6, 6]
- });
-
- L.marker([latitude, longitude], { icon: locationIcon }).addTo(map);
- loadVehicles();
- }, () => {
- map.setView([52.52, 13.405], 13);
- loadVehicles();
- });
-}
-
-locateAndLoad();
-setInterval(loadVehicles, 610);
-map.on('moveend', loadVehicles);
-
diff --git a/old/index.html b/old/index.html
deleted file mode 100644
index 8dcc62a..0000000
--- a/old/index.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
- VBB Live Tracker
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/old/style.css b/old/style.css
deleted file mode 100644
index 030147b..0000000
--- a/old/style.css
+++ /dev/null
@@ -1,43 +0,0 @@
-html, body, #map {
- height: 100%;
- margin: 0;
- padding: 0;
-}
-
-#controls {
- position: absolute;
- top: 10px;
- right: 10px;
- background: rgba(255,255,255,0.9);
- padding: 8px 12px;
- border-radius: 5px;
- z-index: 1000;
- font-family: Arial, sans-serif;
- display: flex;
- flex-wrap: wrap; /* wenn zu viele, umbrechen */
- gap: 8px;
-}
-
-#controls label {
- display: flex;
- align-items: center;
- gap: 4px;
- font-size: 12px;
- cursor: pointer;
-}
-
-.leaflet-marker-icon {
- transition: transform 1s linear;
-}
-
-.line-label {
- padding: 2px 6px;
- border-radius: 3px;
- font-weight: bold;
- font-size: 10px;
- display: inline-block;
- color: white;
- margin-top: 2px;
- user-select: none;
- font-family: Arial, sans-serif;
-}
diff --git a/style.css b/style.css
index 31a3213..030147b 100644
--- a/style.css
+++ b/style.css
@@ -8,13 +8,13 @@ html, body, #map {
position: absolute;
top: 10px;
right: 10px;
- background: rgba(255, 255, 255, 0.9);
+ background: rgba(255,255,255,0.9);
padding: 8px 12px;
border-radius: 5px;
z-index: 1000;
font-family: Arial, sans-serif;
display: flex;
- flex-wrap: wrap;
+ flex-wrap: wrap; /* wenn zu viele, umbrechen */
gap: 8px;
}