您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Zeigt NINA Warnmeldungen im Waze Map Editor Scripts-Tab an
// ==UserScript== // @name WME NINA Warnungen // @namespace https://greasyfork.org/de/users/863740-horst-wittlich // @version 2025.08.21 // @description Zeigt NINA Warnmeldungen im Waze Map Editor Scripts-Tab an // @author Hiwi234 // @match https://www.waze.com/editor* // @match https://www.waze.com/*/editor* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @license MIT // ==/UserScript== function addPolygonsToMap(warnings) { if (!warnings || warnings.length === 0) return; // Prüfe ob Polygone aktiviert sind const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox'); const showPolygons = showPolygonsCheckbox ? showPolygonsCheckbox.checked : true; if (!showPolygons || !W.map) return; try { let ninaPolygonLayer = W.map.getOLMap().getLayersByName('ninaPolygonLayer')[0]; if (!ninaPolygonLayer) { ninaPolygonLayer = new OpenLayers.Layer.Vector('ninaPolygonLayer', { displayInLayerSwitcher: false, visibility: true }); W.map.getOLMap().addLayer(ninaPolygonLayer); console.log('NINA: Polygon-Layer erstellt'); } console.log(`NINA: Versuche Polygone für ${warnings.length} Warnungen zu laden`); warnings.forEach((warning, index) => { try { // Laden der detaillierten Geometrie-Daten für jede Warnung if (warning.id) { console.log(`NINA: Lade Polygon-Details für ${warning.id}`); GM_xmlhttpRequest({ method: 'GET', url: `https://warnung.bund.de/api31/warnings/${warning.id}.json`, onload: function(response) { try { const detailData = JSON.parse(response.responseText); console.log(`NINA: Detail-Daten für ${warning.id}:`, detailData); if (detailData.info && detailData.info[0] && detailData.info[0].area) { console.log(`NINA: Area-Daten gefunden:`, detailData.info[0].area); createPolygonFromArea(detailData.info[0].area, warning, ninaPolygonLayer); } else { console.log(`NINA: Keine Area-Daten in ${warning.id}`); // Fallback: Erstelle Kreis um Demo-Position createFallbackPolygon(warning, ninaPolygonLayer, index); } } catch (e) { console.warn('NINA: Fehler beim Parsen der Polygon-Details:', e); createFallbackPolygon(warning, ninaPolygonLayer, index); } }, onerror: function(error) { console.error(`NINA: Fehler beim Laden der Details für ${warning.id}:`, error); createFallbackPolygon(warning, ninaPolygonLayer, index); } }); } else { console.log('NINA: Keine ID für Warnung, erstelle Fallback-Polygon'); createFallbackPolygon(warning, ninaPolygonLayer, index); } } catch (e) { console.error('NINA: Fehler beim Erstellen von Polygon:', e); } }); } catch (e) { console.error('NINA: Fehler beim Hinzufügen der Polygone:', e); } } function createFallbackPolygon(warning, layer, index) { try { const locations = [ [52.5200, 13.4050], [48.1351, 11.5820], [53.5511, 9.9937], [50.9375, 6.9603], [50.1109, 8.6821], [48.7758, 9.1829], [51.2277, 6.7735], [51.0504, 13.7373] ]; const [lat, lon] = locations[index % locations.length]; const radius = 5000; // 5km Radius // Erstelle Kreis um Position const centerPoint = new OpenLayers.LonLat(lon, lat).transform( new OpenLayers.Projection("EPSG:4326"), W.map.getOLMap().getProjectionObject() ); const circle = OpenLayers.Geometry.Polygon.createRegularPolygon( new OpenLayers.Geometry.Point(centerPoint.lon, centerPoint.lat), radius, 20 ); const color = getSeverityColor(warning.severity); const fillColor = color + '40'; // 25% Transparenz const style = new OpenLayers.Style({ fillColor: fillColor, strokeColor: color, strokeWidth: 2, fillOpacity: 0.25, strokeOpacity: 0.8 }); const feature = new OpenLayers.Feature.Vector(circle, { warning: warning }, style); layer.addFeatures([feature]); console.log('NINA: Fallback-Polygon erstellt für:', warning.i18nTitle?.de || warning.id); } catch (e) { console.error('NINA: Fehler beim Erstellen des Fallback-Polygons:', e); } } function createPolygonFromArea(area, warning, layer) { if (!area || !area.polygon) return; try { // Polygon-Koordinaten parsen (Format: "lat1,lon1 lat2,lon2 ...") const coordString = area.polygon; const coordPairs = coordString.split(' '); const points = []; coordPairs.forEach(pair => { const [lat, lon] = pair.split(',').map(Number); if (!isNaN(lat) && !isNaN(lon)) { const point = new OpenLayers.LonLat(lon, lat).transform( new OpenLayers.Projection("EPSG:4326"), W.map.getOLMap().getProjectionObject() ); points.push(new OpenLayers.Geometry.Point(point.lon, point.lat)); } }); if (points.length > 2) { // Polygon erstellen const ring = new OpenLayers.Geometry.LinearRing(points); const polygon = new OpenLayers.Geometry.Polygon([ring]); // Farbe basierend auf Schweregrad const color = getSeverityColor(warning.severity); const fillColor = color + '40'; // 25% Transparenz const style = new OpenLayers.Style({ fillColor: fillColor, strokeColor: color, strokeWidth: 2, fillOpacity: 0.25, strokeOpacity: 0.8 }); const feature = new OpenLayers.Feature.Vector(polygon, { warning: warning }, style); // Click-Event für Polygon feature.attributes.clickHandler = function() { showWarningDetails(warning); }; layer.addFeatures([feature]); console.log('NINA: Polygon erstellt für Warnung:', warning.i18nTitle?.de || warning.id); } } catch (e) { console.error('NINA: Fehler beim Erstellen des Polygons:', e); } } (function() { 'use strict'; let initialized = false; let ninaTab = null; let tabPane = null; // Globale Variablen const NINA_DATA = { warnings: [], markers: [], polygons: [], showMarkersOnMap: true, showPolygonsOnMap: true, activeFilters: { sources: { mowas: true, dwd: true, katwarn: true, biwapp: true, lhp: true }, severities: { extreme: true, severe: true, moderate: true, minor: true, unknown: true }, types: { alert: true, update: true, cancel: true } } }; // CSS hinzufügen GM_addStyle(` .nina-tab-content { padding: 10px; font-family: Arial, sans-serif; height: 100%; overflow-y: auto; } .nina-header { background: #ff6b35; color: white; padding: 10px; margin: -10px -10px 10px -10px; font-weight: bold; display: flex; justify-content: space-between; align-items: center; } .nina-stats { background: #f8f9fa; padding: 8px; border-radius: 4px; margin-bottom: 10px; font-size: 0.9em; color: #495057; } .nina-controls { background: #f8f9fa; padding: 8px; border-radius: 4px; margin-bottom: 10px; } .nina-control-section { margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #dee2e6; } .nina-control-section:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .nina-control-title { font-weight: bold; margin-bottom: 5px; font-size: 0.9em; color: #495057; } .nina-checkbox-group { display: flex; flex-wrap: wrap; gap: 8px; } .nina-checkbox { display: flex; align-items: center; gap: 5px; font-size: 0.85em; white-space: nowrap; } .nina-checkbox input[type="checkbox"] { margin: 0; } .nina-source-filter { padding: 2px 6px; border-radius: 3px; color: white; font-weight: bold; } .nina-source-mowas { background: #ff6b35; } .nina-source-dwd { background: #2196F3; } .nina-source-katwarn { background: #f44336; } .nina-source-biwapp { background: #9c27b0; } .nina-source-lhp { background: #00bcd4; } .nina-warning { border-left: 4px solid #ff6b35; padding: 8px; margin-bottom: 10px; background: #fff5f2; cursor: pointer; border-radius: 4px; transition: all 0.2s ease; } .nina-warning:hover { background: #ffe8e0; transform: translateX(2px); box-shadow: 2px 2px 8px rgba(0,0,0,0.1); } .nina-warning-title { font-weight: bold; color: #d63031; margin-bottom: 4px; font-size: 0.95em; line-height: 1.3; } .nina-warning-meta { color: #636e72; font-size: 0.9em; margin-bottom: 6px; line-height: 1.4; } .nina-warning-type { background: #ff6b35; color: white; padding: 2px 6px; border-radius: 12px; font-size: 0.8em; display: inline-block; margin-right: 4px; } .nina-refresh { cursor: pointer; margin-right: 10px; padding: 4px 8px; background: rgba(255,255,255,0.2); border-radius: 4px; transition: background 0.2s; } .nina-refresh:hover { background: rgba(255,255,255,0.3); } .nina-loading { text-align: center; padding: 20px; color: #636e72; } .nina-empty { text-align: center; padding: 30px; color: #636e72; background: #f8f9fa; border-radius: 8px; margin: 20px 0; } .nina-source-badge { background: #6c757d; color: white; padding: 1px 4px; border-radius: 2px; font-size: 0.7em; margin-left: 4px; } .nina-goto-btn { float: right; background: #007bff; color: white; border: none; padding: 2px 6px; border-radius: 3px; font-size: 0.8em; cursor: pointer; margin-left: 8px; } .nina-goto-btn:hover { background: #0056b3; } `); function waitForWME(callback) { if (typeof W !== 'undefined' && W.userscripts && W.userscripts.registerSidebarTab && W.map && W.map.getOLMap) { callback(); } else { setTimeout(() => waitForWME(callback), 250); } } function initNINAScript() { if (initialized) return; initialized = true; try { const result = W.userscripts.registerSidebarTab("nina-warnings"); if (!result) { console.error('NINA: Konnte Tab nicht registrieren'); return; } const { tabLabel, tabPane: pane } = result; tabPane = pane; tabLabel.innerHTML = 'NINA'; tabLabel.title = 'NINA Warnmeldungen'; tabLabel.style.fontSize = '16px'; W.userscripts.waitForElementConnected(tabPane).then(() => { setupTabContent(); loadNINAWarnings(); setInterval(loadNINAWarnings, 300000); }); } catch (error) { console.error('NINA: Fehler beim Registrieren des Tabs:', error); } } function setupTabContent() { if (!tabPane) return; tabPane.innerHTML = ` <div class="nina-tab-content"> <div class="nina-header"> <span>NINA Warnungen</span> <span class="nina-refresh" id="nina-refresh-btn">Aktualisieren</span> </div> <div class="nina-stats" id="nina-stats">Lade Warnungen...</div> <div class="nina-controls"> <div class="nina-control-section"> <div class="nina-control-title">Kartenanzeige</div> <div class="nina-checkbox"> <input type="checkbox" id="show-markers-checkbox" checked> <label for="show-markers-checkbox">Icons auf Karte anzeigen</label> </div> </div> <div class="nina-control-section"> <div class="nina-control-title">Warnquellen</div> <div class="nina-checkbox-group"> <div class="nina-checkbox"> <input type="checkbox" id="filter-mowas" checked> <label for="filter-mowas"><span class="nina-source-filter nina-source-mowas">MoWaS</span></label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-dwd" checked> <label for="filter-dwd"><span class="nina-source-filter nina-source-dwd">DWD</span></label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-katwarn" checked> <label for="filter-katwarn"><span class="nina-source-filter nina-source-katwarn">KatWarn</span></label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-biwapp" checked> <label for="filter-biwapp"><span class="nina-source-filter nina-source-biwapp">BiWapp</span></label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-lhp" checked> <label for="filter-lhp"><span class="nina-source-filter nina-source-lhp">LHP</span></label> </div> </div> </div> <div class="nina-control-section"> <div class="nina-control-title">Anzeige</div> <div class="nina-checkbox-group"> <div class="nina-checkbox"> <input type="checkbox" id="show-polygons-checkbox" checked> <label for="show-polygons-checkbox">Warngebiete als Flaechen</label> </div> </div> </div> <div class="nina-control-section"> <div class="nina-control-title">Schweregrad</div> <div class="nina-checkbox-group"> <div class="nina-checkbox"> <input type="checkbox" id="filter-extreme" checked> <label for="filter-extreme" style="color: #8B0000; font-weight: bold;">Extrem</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-severe" checked> <label for="filter-severe" style="color: #FF0000; font-weight: bold;">Schwer</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-moderate" checked> <label for="filter-moderate" style="color: #FF8C00; font-weight: bold;">Mittel</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-minor" checked> <label for="filter-minor" style="color: #FFD700; font-weight: bold;">Gering</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-unknown" checked> <label for="filter-unknown" style="color: #999;">Unbekannt</label> </div> </div> </div> <div class="nina-control-section"> <div class="nina-control-title">Status</div> <div class="nina-checkbox-group"> <div class="nina-checkbox"> <input type="checkbox" id="filter-alert" checked> <label for="filter-alert">Aktive Warnungen</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-update" checked> <label for="filter-update">Updates</label> </div> <div class="nina-checkbox"> <input type="checkbox" id="filter-cancel"> <label for="filter-cancel">Entwarnungen</label> </div> </div> </div> </div> <div id="nina-warnings-content" class="nina-loading"> <div>Verbinde mit NINA API...</div> </div> </div> `; setupEventListeners(); } function setupEventListeners() { const refreshBtn = document.getElementById('nina-refresh-btn'); if (refreshBtn) { refreshBtn.addEventListener('click', loadNINAWarnings); } const showMarkersCheckbox = document.getElementById('show-markers-checkbox'); if (showMarkersCheckbox) { showMarkersCheckbox.addEventListener('change', toggleMapMarkers); } const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox'); if (showPolygonsCheckbox) { showPolygonsCheckbox.addEventListener('change', toggleMapPolygons); } // Alle Filter-Event-Listener ['mowas', 'dwd', 'katwarn', 'biwapp', 'lhp'].forEach(source => { const checkbox = document.getElementById(`filter-${source}`); if (checkbox) { checkbox.addEventListener('change', () => { NINA_DATA.activeFilters.sources[source] = checkbox.checked; applyFilters(); }); } }); ['extreme', 'severe', 'moderate', 'minor', 'unknown'].forEach(severity => { const checkbox = document.getElementById(`filter-${severity}`); if (checkbox) { checkbox.addEventListener('change', () => { NINA_DATA.activeFilters.severities[severity] = checkbox.checked; applyFilters(); }); } }); ['alert', 'update', 'cancel'].forEach(type => { const checkbox = document.getElementById(`filter-${type}`); if (checkbox) { checkbox.addEventListener('change', () => { NINA_DATA.activeFilters.types[type] = checkbox.checked; applyFilters(); }); } }); } function loadNINAWarnings() { console.log('NINA: Lade Warnungen...'); updateStats('Lade Warnungen...'); const sources = ['mowas', 'biwapp', 'katwarn', 'dwd', 'lhp']; let allWarnings = []; let loadedCount = 0; sources.forEach(source => { GM_xmlhttpRequest({ method: 'GET', url: `https://warnung.bund.de/api31/${source}/mapData.json`, onload: function(response) { try { const data = JSON.parse(response.responseText); if (data && Array.isArray(data) && data.length > 0) { console.log(`NINA: Gefunden ${data.length} Warnungen von ${source}`); data.forEach(warning => warning.source = source); allWarnings = allWarnings.concat(data); } } catch (e) { console.warn(`NINA: Fehler beim Laden von ${source}:`, e); } loadedCount++; if (loadedCount === sources.length) { console.log(`NINA: Insgesamt ${allWarnings.length} Warnungen geladen`); processWarnings(allWarnings); } }, onerror: function(error) { console.error(`NINA: Fehler beim Laden von ${source}:`, error); loadedCount++; if (loadedCount === sources.length) { processWarnings(allWarnings); } } }); }); } function processWarnings(warnings) { console.log('NINA: Verarbeite', warnings.length, 'Warnungen'); warnings.sort((a, b) => { const dateA = a.startDate ? new Date(a.startDate) : new Date(0); const dateB = b.startDate ? new Date(b.startDate) : new Date(0); return dateB - dateA; }); NINA_DATA.warnings = warnings; updateDisplay(warnings); } function applyFilters() { const filteredWarnings = NINA_DATA.warnings.filter(warning => { const source = warning.source || 'unknown'; const severity = (warning.severity || 'unknown').toLowerCase(); const type = (warning.type || 'Alert').toLowerCase(); return NINA_DATA.activeFilters.sources[source] && NINA_DATA.activeFilters.severities[severity] && NINA_DATA.activeFilters.types[type]; }); updateDisplay(filteredWarnings); } function updateDisplay(warnings) { clearMarkers(); clearPolygons(); const showMarkersCheckbox = document.getElementById('show-markers-checkbox'); const showPolygonsCheckbox = document.getElementById('show-polygons-checkbox'); if (showMarkersCheckbox && showMarkersCheckbox.checked) { addMarkersToMap(warnings); } if (showPolygonsCheckbox && showPolygonsCheckbox.checked) { addPolygonsToMap(warnings); } updateTabContent(warnings); } function clearMarkers() { try { const ninaLayer = W.map.getOLMap().getLayersByName('ninaLayer')[0]; if (ninaLayer) { ninaLayer.clearMarkers(); } } catch (e) { console.warn('NINA: Fehler beim Entfernen der Marker:', e); } } function clearPolygons() { try { const ninaPolygonLayer = W.map.getOLMap().getLayersByName('ninaPolygonLayer')[0]; if (ninaPolygonLayer) { ninaPolygonLayer.removeAllFeatures(); } } catch (e) { console.warn('NINA: Fehler beim Entfernen der Polygone:', e); } } function addMarkersToMap(warnings) { // Nur hinzufügen wenn Checkbox aktiviert ist const showMarkersCheckbox = document.getElementById('show-markers-checkbox'); const showMarkers = showMarkersCheckbox ? showMarkersCheckbox.checked : true; if (!showMarkers || !W.map) return; try { let ninaLayer = W.map.getOLMap().getLayersByName('ninaLayer')[0]; if (!ninaLayer) { ninaLayer = new OpenLayers.Layer.Markers('ninaLayer'); W.map.getOLMap().addLayer(ninaLayer); } const locations = [ [52.5200, 13.4050], [48.1351, 11.5820], [53.5511, 9.9937], [50.9375, 6.9603], [50.1109, 8.6821], [48.7758, 9.1829], [51.2277, 6.7735], [51.0504, 13.7373] ]; warnings.forEach((warning, index) => { const [lat, lon] = locations[index % locations.length]; warning.demoCoords = { lat, lon }; try { const lonLat = new OpenLayers.LonLat(lon, lat).transform( new OpenLayers.Projection("EPSG:4326"), W.map.getOLMap().getProjectionObject() ); const iconUrl = getWarningIcon(warning); const size = new OpenLayers.Size(24, 24); const offset = new OpenLayers.Pixel(-12, -12); const icon = new OpenLayers.Icon(iconUrl, size, offset); const marker = new OpenLayers.Marker(lonLat, icon); marker.events.register('click', marker, function() { showWarningDetails(warning); }); ninaLayer.addMarker(marker); } catch (e) { console.error('NINA: Fehler beim Erstellen von Marker:', e); } }); } catch (e) { console.error('NINA: Fehler beim Hinzufügen der Marker:', e); } } function getWarningIcon(warning) { let color = '#ff6b35'; if (warning.severity) { switch(warning.severity.toLowerCase()) { case 'extreme': color = '#8B0000'; break; case 'severe': color = '#FF0000'; break; case 'moderate': color = '#FF8C00'; break; case 'minor': color = '#FFD700'; break; } } let symbol = '!'; if (warning.source) { switch(warning.source) { case 'dwd': symbol = 'W'; break; case 'mowas': symbol = '!'; break; case 'katwarn': symbol = 'K'; break; case 'biwapp': symbol = 'B'; break; case 'lhp': symbol = 'H'; break; } } const svgContent = `<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="11" fill="${color}" stroke="#ffffff" stroke-width="2"/> <text x="12" y="16" text-anchor="middle" fill="white" font-size="12" font-weight="bold" font-family="Arial">${symbol}</text> </svg>`; try { return `data:image/svg+xml;base64,${btoa(svgContent)}`; } catch (e) { return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`; } } function updateTabContent(warnings) { updateStats(); const content = document.getElementById('nina-warnings-content'); if (!content) return; if (!warnings || warnings.length === 0) { content.innerHTML = ` <div class="nina-empty"> <div style="font-size: 2em; margin-bottom: 10px;">✓</div> <div style="font-weight: bold; margin-bottom: 5px;">Keine aktuellen Warnungen</div> <div style="font-size: 0.9em;">Alle Systeme normal</div> </div> `; return; } const warningsHtml = warnings.map((warning, index) => { const title = warning.i18nTitle?.de || warning.headline || warning.title || 'Warnung'; const source = warning.source || 'Unbekannt'; const severity = warning.severity || 'Unbekannt'; const urgency = warning.urgency || ''; const type = warning.type || 'Alert'; const isCancel = type === 'Cancel'; // Zeitinformationen formatieren const startDate = warning.startDate ? new Date(warning.startDate).toLocaleString('de-DE') : ''; const expiresDate = warning.expiresDate ? new Date(warning.expiresDate).toLocaleString('de-DE') : ''; const ageHours = warning.startDate ? Math.floor((Date.now() - new Date(warning.startDate)) / (1000 * 60 * 60)) : 0; const ageText = ageHours < 1 ? 'Neu' : ageHours < 24 ? `${ageHours}h alt` : `${Math.floor(ageHours / 24)}d alt`; return ` <div class="nina-warning" data-warning-index="${index}" style="${isCancel ? 'opacity: 0.6; border-left-color: #95a5a6;' : ''}"> <div class="nina-warning-title"> ${isCancel ? 'Entwarnung: ' : ''}${title} <button class="nina-goto-btn" data-goto-index="${index}">Zur Karte</button> </div> <div class="nina-warning-meta"> Quelle: ${source.toUpperCase()}<span class="nina-source-badge">${getSourceSymbol(source)}</span> <br>Alter: ${ageText} ${startDate ? `<br>Gueltig seit: ${startDate}` : ''} ${expiresDate ? `<br>Gueltig bis: ${expiresDate}` : ''} </div> <div> <span class="nina-warning-type" style="background: ${getSeverityColor(severity)}">${severity}</span> ${urgency ? `<span class="nina-warning-type" style="background: #e74c3c; margin-left: 5px;">${urgency}</span>` : ''} ${isCancel ? '<span class="nina-warning-type" style="background: #27ae60; margin-left: 5px;">Entwarnung</span>' : ''} </div> </div> `; }).join(''); content.innerHTML = warningsHtml; content.querySelectorAll('.nina-warning').forEach(warningEl => { const index = parseInt(warningEl.dataset.warningIndex); warningEl.addEventListener('click', () => showWarningDetails(NINA_DATA.warnings[index])); }); content.querySelectorAll('.nina-goto-btn').forEach(btn => { const index = parseInt(btn.dataset.gotoIndex); btn.addEventListener('click', (event) => { event.stopPropagation(); gotoWarning(index); }); }); } function getSourceSymbol(source) { switch(source) { case 'dwd': return 'W'; case 'mowas': return '!'; case 'katwarn': return 'K'; case 'biwapp': return 'B'; case 'lhp': return 'H'; default: return '?'; } } function getSeverityColor(severity) { switch(severity?.toLowerCase()) { case 'extreme': return '#8B0000'; case 'severe': return '#FF0000'; case 'moderate': return '#FF8C00'; case 'minor': return '#FFD700'; default: return '#ff6b35'; } } function translateSeverity(severity) { switch(severity?.toLowerCase()) { case 'extreme': return 'Extrem'; case 'severe': return 'Schwer'; case 'moderate': return 'Mittel'; case 'minor': return 'Gering'; case 'unknown': return 'Unbekannt'; default: return severity || 'Unbekannt'; } } function translateUrgency(urgency) { switch(urgency?.toLowerCase()) { case 'immediate': return 'Sofort'; case 'expected': return 'Erwartet'; case 'future': return 'Zukunft'; case 'past': return 'Vergangen'; case 'unknown': return 'Unbekannt'; default: return urgency || ''; } } function translateType(type) { switch(type?.toLowerCase()) { case 'alert': return 'Warnung'; case 'update': return 'Update'; case 'cancel': return 'Entwarnung'; case 'test': return 'Test'; default: return type || 'Warnung'; } } function updateStats(message) { const statsEl = document.getElementById('nina-stats'); if (!statsEl) return; if (typeof message === 'string') { statsEl.innerHTML = message; } else { const total = NINA_DATA.warnings.length; // Gefilterte Anzahl berechnen const filteredCount = NINA_DATA.warnings.filter(warning => { const source = warning.source || 'unknown'; const severity = (warning.severity || 'unknown').toLowerCase(); const type = (warning.type || 'Alert').toLowerCase(); return NINA_DATA.activeFilters.sources[source] && NINA_DATA.activeFilters.severities[severity] && NINA_DATA.activeFilters.types[type]; }).length; const sources = {}; NINA_DATA.warnings.forEach(w => { sources[w.source] = (sources[w.source] || 0) + 1; }); const sourceStats = Object.entries(sources) .map(([source, count]) => `${source.toUpperCase()}: ${count}`) .join(' | '); const filterInfo = filteredCount < total ? ` | Gefiltert: ${filteredCount}` : ''; statsEl.innerHTML = `Gesamt: <strong>${total}</strong> Warnungen${filterInfo} | ${sourceStats} | ${new Date().toLocaleTimeString('de-DE')}`; } } function showWarningDetails(warning) { if (!warning) return; const title = warning.i18nTitle?.de || warning.headline || warning.title || 'Warnung'; const description = warning.description || warning.info?.[0]?.description || 'Keine Details verfügbar'; const source = warning.source ? warning.source.toUpperCase() : 'Unbekannte Quelle'; const severity = translateSeverity(warning.severity); const urgency = translateUrgency(warning.urgency); const type = warning.type || 'Alert'; const startDate = warning.startDate ? new Date(warning.startDate).toLocaleString('de-DE') : 'Unbekannt'; const expiresDate = warning.expiresDate ? new Date(warning.expiresDate).toLocaleString('de-DE') : 'Unbekannt'; const isCancel = type === 'Cancel'; const statusText = isCancel ? 'ENTWARNUNG' : 'AKTIVE WARNUNG'; const detailText = `${statusText} ${title} Quelle: ${source} Schweregrad: ${severity} Dringlichkeit: ${urgency} Gueltig seit: ${startDate} Gueltig bis: ${expiresDate} Details: ${description}`; alert(detailText); } function gotoWarning(index) { const warning = NINA_DATA.warnings[index]; if (!warning || !warning.demoCoords || !W.map) return; const { lat, lon } = warning.demoCoords; try { const lonLat = new OpenLayers.LonLat(lon, lat).transform( new OpenLayers.Projection("EPSG:4326"), W.map.getOLMap().getProjectionObject() ); W.map.getOLMap().setCenter(lonLat); if (W.map.getOLMap().getZoom() < 5) { W.map.getOLMap().zoomTo(5); } console.log(`NINA: Springe zur Warnung: ${warning.i18nTitle?.de || warning.id}`); } catch (e) { console.error('NINA: Fehler beim Navigieren:', e); } } function toggleMapPolygons() { const checkbox = document.getElementById('show-polygons-checkbox'); const showPolygons = checkbox ? checkbox.checked : true; if (showPolygons) { console.log('NINA: Aktiviere Warngebiets-Polygone'); // Lade aktuelle Warnungen neu loadNINAWarnings(); } else { console.log('NINA: Deaktiviere Warngebiets-Polygone'); clearPolygons(); } } function toggleMapMarkers() { const checkbox = document.getElementById('show-markers-checkbox'); const showMarkers = checkbox ? checkbox.checked : true; if (showMarkers) { console.log('NINA: Aktiviere Karten-Marker'); // Lade aktuelle Warnungen neu loadNINAWarnings(); } else { console.log('NINA: Deaktiviere Karten-Marker'); clearMarkers(); } } // Script starten console.log('NINA: Script gestartet'); waitForWME(initNINAScript); })();