您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Erweiterte Version mit TopPlus, Dark Map, Basemap DE und allen DACH Geoportal Overlays
// ==UserScript== // @name WME Multi Map Overlay // @namespace https://gf.qytechs.cn/de/users/863740-horst-wittlich // @version 2025.06.09 // @description Erweiterte Version mit TopPlus, Dark Map, Basemap DE und allen DACH Geoportal Overlays // @author Hiwi234 // @match https://www.waze.com/editor* // @match https://www.waze.com/*/editor* // @match https://beta.waze.com/editor* // @match https://beta.waze.com/*/editor* // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_info // @connect sgx.geodatenzentrum.de // @connect owsproxy.lgl-bw.de // @connect www.wmts.nrw.de // @connect geoservices.bayern.de // @connect mapsneu.wien.gv.at // @connect www.basemap.at // @connect wmts.geo.admin.ch // @connect cdnjs.cloudflare.com // @connect a.tile.openstreetmap.org // @connect b.tile.openstreetmap.org // @connect c.tile.openstreetmap.org // @connect a.basemaps.cartocdn.com // @connect b.basemaps.cartocdn.com // @connect c.basemaps.cartocdn.com // @license MIT // ==/UserScript== (function() { 'use strict'; const SCRIPT_NAME = 'WME Multi Overlay'; const SCRIPT_ID = 'wme-multi-overlay'; const DEFAULT_OPACITY = 0.64; const DEFAULT_ZINDEX = 2000; const STORAGE_KEY = 'wme-overlay-settings'; // Layer storage const layers = {}; // Settings Management function saveSettings() { const settings = { version: GM_info.script.version, layers: {} }; Object.keys(layers).forEach(layerId => { const layer = layers[layerId]; if (layer) { settings.layers[layerId] = { visible: layer.getVisibility(), opacity: layer.opacity || DEFAULT_OPACITY, zIndex: layer.getZIndex() || DEFAULT_ZINDEX }; } }); localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); console.log('Settings gespeichert:', settings); } function saveGlobalFilters() { localStorage.setItem('wme-overlay-global-filters', JSON.stringify(globalFilters)); } function loadGlobalFilters() { try { const saved = localStorage.getItem('wme-overlay-global-filters'); if (saved) { const filters = JSON.parse(saved); globalFilters = { ...globalFilters, ...filters }; } } catch (error) { console.error('Fehler beim Laden der globalen Filter:', error); } } function loadSettings() { try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { const settings = JSON.parse(saved); console.log('Settings geladen:', settings); return settings; } } catch (error) { console.error('Fehler beim Laden der Settings:', error); } return { layers: {} }; } function applySettingsToLayer(layerId, layer) { const settings = loadSettings(); const layerSettings = settings.layers[layerId]; if (layerSettings) { // Sichtbarkeit anwenden layer.setVisibility(layerSettings.visible || false); // Transparenz anwenden layer.setOpacity(layerSettings.opacity || DEFAULT_OPACITY); // Z-Index anwenden layer.setZIndex(layerSettings.zIndex || DEFAULT_ZINDEX); console.log(`Settings für ${layerId} angewendet:`, layerSettings); } } // Filter-Updates für alle Layer function updateAllLayerFilters() { const brightness = globalFilters.brightness; const contrast = globalFilters.contrast; const saturation = globalFilters.saturation; const sharpness = globalFilters.sharpness; // CSS Filter mit funktionierender Schärfe erstellen // Schärfe wird über blur() (umgekehrt) implementiert: 100% = kein blur, über 100% = unsharp mask via contrast let filterString = `brightness(${brightness}%) contrast(${contrast}%) saturate(${saturation}%)`; // Schärfe-Implementierung if (sharpness < 100) { // Unter 100%: Blur hinzufügen (weicher) const blurAmount = (100 - sharpness) / 100 * 2; // Max 2px blur bei 0% filterString += ` blur(${blurAmount}px)`; } else if (sharpness > 100) { // Über 100%: Zusätzlichen Kontrast für Schärfe-Effekt const extraContrast = 100 + (sharpness - 100) * 0.5; // Moderate Verstärkung filterString += ` contrast(${extraContrast}%)`; } console.log('Applying global filters:', filterString); // Filter auf alle OpenLayers Divs anwenden setTimeout(() => { const layerElements = document.querySelectorAll('.olLayerDiv'); layerElements.forEach(element => { if (element && element.style) { element.style.filter = filterString; element.style.webkitFilter = filterString; } }); // Zusätzlich auf alle Layer-Container anwenden Object.keys(layers).forEach(layerId => { const layer = layers[layerId]; if (layer && layer.div && layer.getVisibility()) { layer.div.style.filter = filterString; layer.div.style.webkitFilter = filterString; } }); // Für Canvas-Elemente (falls vorhanden) const canvasElements = document.querySelectorAll('#map canvas'); canvasElements.forEach(canvas => { if (canvas && canvas.style) { canvas.style.filter = filterString; canvas.style.webkitFilter = filterString; } }); }, 100); } // Neu organisierte Layer-Konfiguration const layerGroups = { basic: { name: "🔧 Basis Layer", layers: [ { id: 'topplus', name: 'TopPlus WMS', type: 'wms', url: 'https://sgx.geodatenzentrum.de/wms_topplus_web_open', params: { layers: 'web', format: 'image/png', transparent: true }, attribution: '© BKG' }, { id: 'topplus-grau', name: 'TopPlus Grau', type: 'wms', url: 'https://sgx.geodatenzentrum.de/wms_topplus_web_open', params: { layers: 'web_grau', format: 'image/png', transparent: true }, attribution: '© BKG' } ] }, germany: { name: "🇩🇪 GeoOverlays DE", layers: [ { id: 'basemap-de', name: 'Basemap DE', type: 'wms', url: 'https://sgx.geodatenzentrum.de/wms_basemapde', params: { layers: 'de_basemapde_web_raster_farbe', format: 'image/png', transparent: true }, attribution: '© <a href="https://www.basemap.de">basemap.de</a>' }, { id: 'basemap-de-grau', name: 'Basemap.de Grau', type: 'wms', url: 'https://sgx.geodatenzentrum.de/wms_basemapde', params: { layers: 'de_basemapde_web_raster_grau', format: 'image/png', transparent: true }, attribution: '© <a href="https://www.basemap.de">basemap.de</a>' }, { id: "geoportal-nrw", name: "GeoPortal NRW", type: "wmts", source: "https://www.wmts.nrw.de/geobasis/wmts_nw_dtk/1.0.0/WMTSCapabilities.xml", layerName: "nw_dtk_col", matrixSet: "EPSG_3857_16", }, { id: "geoportal-nrw-overlay", name: "GeoPortal NRW Overlay", type: "wmts", source: "https://www.wmts.nrw.de/geobasis/wmts_nw_dop_overlay/1.0.0/WMTSCapabilities.xml", layerName: "nw_dop_overlay", matrixSet: "EPSG_3857_16", }, { id: "geoportal-by", name: "GeoPortal BY", type: "wmts", source: "https://geoservices.bayern.de/od/wmts/geobasis/v1/1.0.0/WMTSCapabilities.xml", layerName: "by_webkarte", matrixSet: "smerc", } ] }, austria: { name: "🇦🇹 GeoOverlays AT", layers: [ { id: "basemap-at", name: "Basemap AT", type: "wmts", source: "https://mapsneu.wien.gv.at/basemapneu/1.0.0/WMTSCapabilities.xml", layerName: "geolandbasemap", matrixSet: "google3857", }, { id: "overlay-at", name: "Overlay AT", type: "wmts", source: "https://www.basemap.at/wmts/1.0.0/WMTSCapabilities.xml", layerName: "bmapoverlay", matrixSet: "google3857", } ] }, switzerland: { name: "🇨🇭 GeoOverlays CH", layers: [ { id: "swiss-strassen", name: "Strassenkarte", type: "wmts", source: "https://wmts.geo.admin.ch/EPSG/3857/1.0.0/WMTSCapabilities.xml", layerName: "ch.swisstopo.swisstne-base", matrixSet: "3857_18", }, { id: "swiss-basis", name: "Basisnetz", type: "wmts", source: "https://wmts.geo.admin.ch/EPSG/3857/1.0.0/WMTSCapabilities.xml", layerName: "ch.swisstopo.swisstlm3d-strassen", matrixSet: "3857_18", }, { id: "swiss-luft", name: "Luftbild", type: "wmts", source: "https://wmts.geo.admin.ch/EPSG/3857/1.0.0/WMTSCapabilities.xml", layerName: "ch.swisstopo.swissimage-product", matrixSet: "3857_20", } ] }, unofficial: { name: "🌍 Nicht Amtliche Karten", layers: [ { id: 'osm-standard', name: 'OpenStreetMap Standard', type: 'xyz', urls: [ 'https://a.tile.openstreetmap.org/${z}/${x}/${y}.png', 'https://b.tile.openstreetmap.org/${z}/${x}/${y}.png', 'https://c.tile.openstreetmap.org/${z}/${x}/${y}.png' ], attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }, { id: 'darkmap', name: 'OSM Dark Matter', type: 'xyz', urls: [ 'https://a.basemaps.cartocdn.com/dark_all/${z}/${x}/${y}@2x.png', 'https://b.basemaps.cartocdn.com/dark_all/${z}/${x}/${y}@2x.png', 'https://c.basemaps.cartocdn.com/dark_all/${z}/${x}/${y}@2x.png' ], attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>' } ] } }; // Hilfsfunktionen für OpenLayers Patches function loadOLScript(filename) { const version = OpenLayers.VERSION_NUMBER.replace(/Release /, ""); console.info("Loading openlayers/" + version + "/" + filename + ".js"); const script = document.createElement("script"); script.src = `https://cdnjs.cloudflare.com/ajax/libs/openlayers/${version}/${filename}.js`; script.type = "text/javascript"; script.async = false; document.head.appendChild(script); } function patchOpenLayers() { console.log("Patching OpenLayers for WMTS support..."); if (!OpenLayers.VERSION_NUMBER.match(/^Release [0-9.]*$/)) { console.error("OpenLayers version mismatch - cannot apply patch"); return; } // Lade notwendige OpenLayers Komponenten loadOLScript("lib/OpenLayers/Format/XML"); loadOLScript("lib/OpenLayers/Format/XML/VersionedOGC"); loadOLScript("lib/OpenLayers/Layer/WMTS"); loadOLScript("lib/OpenLayers/Format/OWSCommon"); loadOLScript("lib/OpenLayers/Format/OWSCommon/v1"); loadOLScript("lib/OpenLayers/Format/OWSCommon/v1_1_0"); loadOLScript("lib/OpenLayers/Format/WMSCapabilities"); loadOLScript("lib/OpenLayers/Format/WMSCapabilities/v1"); loadOLScript("lib/OpenLayers/Format/WMSCapabilities/v1_3"); loadOLScript("lib/OpenLayers/Format/WMSCapabilities/v1_3_0"); loadOLScript("lib/OpenLayers/Format/WMTSCapabilities"); loadOLScript("lib/OpenLayers/Format/WMTSCapabilities/v1_0_0"); } // Basis Layer erstellen function createBasicLayer(config) { const olMap = W.map.getOLMap(); let layer; switch (config.type) { case 'wms': layer = new OpenLayers.Layer.WMS( config.name, config.url, config.params, { transitionEffect: 'resize', attribution: config.attribution, isBaseLayer: false, visibility: false, opacity: DEFAULT_OPACITY, projection: new OpenLayers.Projection("EPSG:3857"), displayInLayerSwitcher: false, alwaysInRange: true, zIndex: DEFAULT_ZINDEX } ); break; case 'xyz': layer = new OpenLayers.Layer.XYZ( config.name, config.urls, { attribution: config.attribution, transitionEffect: 'resize', isBaseLayer: false, visibility: false, opacity: DEFAULT_OPACITY, displayInLayerSwitcher: false, alwaysInRange: true, zIndex: DEFAULT_ZINDEX } ); break; } if (layer) { layer.setOpacity(DEFAULT_OPACITY); olMap.addLayer(layer); layers[config.id] = layer; // Gespeicherte Einstellungen anwenden applySettingsToLayer(config.id, layer); } } // WMTS Layer erstellen function createWMTSLayer(layerConfig) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: layerConfig.source, onload: (response) => { try { let responseXML = response.responseXML; if (!responseXML) { responseXML = new DOMParser().parseFromString(response.responseText, "text/xml"); } if (!responseXML || !(responseXML instanceof XMLDocument)) { throw new Error("Invalid XML response"); } const format = new OpenLayers.Format.WMTSCapabilities(); const capabilities = format.read(responseXML); const layer = format.createLayer(capabilities, { layer: layerConfig.layerName, matrixSet: layerConfig.matrixSet, opacity: DEFAULT_OPACITY, isBaseLayer: false, requestEncoding: layerConfig.requestEncoding || "REST", visibility: false, zIndex: DEFAULT_ZINDEX }); if (layer && layer.url && layer.url.length) { const olMap = W.map.getOLMap(); olMap.addLayer(layer); olMap.setLayerIndex(layer, 9); layers[layerConfig.id] = layer; // Gespeicherte Einstellungen anwenden applySettingsToLayer(layerConfig.id, layer); console.log(`✓ ${layerConfig.name} loaded successfully`); resolve(layer); } else { throw new Error("No valid URLs found"); } } catch (error) { console.error(`✗ Failed to load ${layerConfig.name}:`, error); reject(error); } }, onerror: () => reject(new Error("Network error")), ontimeout: () => reject(new Error("Request timeout")) }); }); } // Update Notification System function showUpdateNotification() { // Prüfe ob bereits angezeigt wurde const lastShown = localStorage.getItem('wme-overlay-update-shown'); const currentVersion = GM_info.script.version; if (lastShown === currentVersion) { return; // Bereits für diese Version angezeigt } // Erstelle Overlay const overlay = document.createElement('div'); overlay.className = 'update-notification-overlay'; overlay.innerHTML = ` <div class="update-notification"> <div class="update-header"> <h2>WME Multi Map 🗺️ Overlay</h2> <div class="header-right"> <span class="version-badge">v${currentVersion}</span> <button class="close-btn" id="header-close-btn">×</button> </div> </div> <div class="update-content"> <h3>🎨 Neue Overlay-Einstellungen!</h3> <div class="new-features"> <div class="feature-group"> <h4>🎛️ Neue Filter-Optionen:</h4> <ul> <li>✅ Helligkeit (0-300%)</li> <li>✅ Kontrast (0-300%)</li> <li>✅ Sättigung (0-300%)</li> <li>✅ Schärfe (0-300%)</li> </ul> </div> <div class="feature-group"> <h4>🔧 Basis Layer:</h4> <ul> <li>✅ TopPlus WMS</li> <li>✅ TopPlus Grau</li> </ul> </div> <div class="feature-group"> <h4>🇩🇪 GeoOverlays DE:</h4> <ul> <li>✅ Basemap DE</li> <li>✅ Basemap.de Grau</li> <li>✅ GeoPortal NRW</li> <li>✅ GeoPortal NRW Overlay</li> <li>✅ GeoPortal BY</li> </ul> </div> <div class="feature-group"> <h4>🇦🇹 GeoOverlays AT:</h4> <ul> <li>✅ Basemap AT</li> <li>✅ Overlay AT</li> </ul> </div> <div class="feature-group"> <h4>🇨🇭 GeoOverlays CH:</h4> <ul> <li>✅ Strassenkarte</li> <li>✅ Basisnetz</li> <li>✅ Luftbild</li> </ul> </div> <div class="feature-group"> <h4>🌍 Nicht Amtliche Karten:</h4> <ul> <li>✅ OpenStreetMap Standard</li> <li>✅ OSM Dark Matter</li> </ul> </div> </div> <div class="feature-info"> <p><strong>🎨 Individuelle Anpassung!</strong></p> <p>Jede Karte kann jetzt individuell in Helligkeit, Kontrast, Sättigung und Schärfe angepasst werden!</p> </div> </div> <div class="update-actions"> <button class="btn-primary" id="explore-maps-btn"> 🚀 Karten erkunden! </button> <button class="btn-secondary" id="close-popup-btn"> Später </button> </div> </div> `; // Styles für das Update-Popup const updateStyle = document.createElement('style'); updateStyle.textContent = ` .update-notification-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 999999; display: flex; align-items: center; justify-content: center; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .update-notification { background: white; border-radius: 12px; max-width: 600px; width: 90%; max-height: 80vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { opacity: 0; transform: scale(0.9) translateY(-20px); } to { opacity: 1; transform: scale(1) translateY(0); } } .update-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px 12px 0 0; display: flex; align-items: center; justify-content: space-between; } .header-right { display: flex; align-items: center; gap: 12px; } .close-btn { background: rgba(255, 255, 255, 0.2); border: none; color: white; width: 32px; height: 32px; border-radius: 50%; font-size: 18px; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.2s; } .close-btn:hover { background: rgba(255, 255, 255, 0.3); } .update-header h2 { margin: 0; font-size: 24px; font-weight: 600; } .version-badge { background: rgba(255, 255, 255, 0.2); padding: 4px 12px; border-radius: 20px; font-size: 14px; font-weight: 500; } .update-content { padding: 24px; } .update-content h3 { margin: 0 0 20px 0; color: #333; font-size: 20px; } .new-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 24px; } .feature-group { background: #f8f9fa; padding: 16px; border-radius: 8px; border-left: 4px solid #667eea; } .feature-group h4 { margin: 0 0 12px 0; color: #333; font-size: 16px; font-weight: 600; } .feature-group ul { margin: 0; padding-left: 0; list-style: none; } .feature-group li { margin: 6px 0; color: #555; font-size: 14px; } .feature-info { background: #e3f2fd; padding: 16px; border-radius: 8px; border-left: 4px solid #2196f3; } .feature-info p { margin: 0; color: #1565c0; font-size: 14px; } .feature-info strong { font-weight: 600; } .update-actions { padding: 20px 24px; border-top: 1px solid #eee; display: flex; gap: 12px; justify-content: flex-end; } .btn-primary, .btn-secondary { padding: 12px 24px; border: none; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .btn-primary { background: #667eea; color: white; } .btn-primary:hover { background: #5a6fd8; transform: translateY(-1px); } .btn-secondary { background: #e0e0e0; color: #333; } .btn-secondary:hover { background: #d0d0d0; } `; document.head.appendChild(updateStyle); document.body.appendChild(overlay); // Event Listener für Buttons hinzufügen overlay.querySelector('#explore-maps-btn').addEventListener('click', function() { overlay.remove(); localStorage.setItem('wme-overlay-update-shown', currentVersion); }); overlay.querySelector('#close-popup-btn').addEventListener('click', function() { overlay.remove(); localStorage.setItem('wme-overlay-update-shown', currentVersion); }); overlay.querySelector('#header-close-btn').addEventListener('click', function() { overlay.remove(); localStorage.setItem('wme-overlay-update-shown', currentVersion); }); // Overlay bei Klick außerhalb schließen overlay.addEventListener('click', function(e) { if (e.target === overlay) { overlay.remove(); localStorage.setItem('wme-overlay-update-shown', currentVersion); } }); // ESC-Taste zum Schließen document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && document.contains(overlay)) { overlay.remove(); localStorage.setItem('wme-overlay-update-shown', currentVersion); } }); } function createLayerControl(layerId, name, isGroup = false) { const container = document.createElement('div'); container.className = isGroup ? 'layer-group' : 'layer-control'; if (isGroup) { const header = document.createElement('div'); header.className = 'group-header'; header.innerHTML = `<span class="group-title">${name}</span>`; container.appendChild(header); return container; } const layer = layers[layerId]; if (!layer) return container; // Sichtbarkeits-Checkbox const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = layer.getVisibility(); checkbox.addEventListener('change', () => { layer.setVisibility(checkbox.checked); saveSettings(); // Speichern nach Änderung }); const label = document.createElement('label'); label.appendChild(checkbox); label.appendChild(document.createTextNode(name)); // Transparenz-Slider const opacityContainer = document.createElement('div'); opacityContainer.className = 'slider-container'; const opacityLabel = document.createElement('span'); opacityLabel.textContent = 'Transparenz: '; const opacityValue = document.createElement('span'); opacityValue.className = 'slider-value'; opacityValue.textContent = Math.round((layer.opacity || DEFAULT_OPACITY) * 100) + '%'; const opacitySlider = document.createElement('input'); opacitySlider.type = 'range'; opacitySlider.min = '0'; opacitySlider.max = '1'; opacitySlider.step = '0.1'; opacitySlider.value = layer.opacity || DEFAULT_OPACITY; opacitySlider.addEventListener('input', () => { const value = parseFloat(opacitySlider.value); layer.setOpacity(value); opacityValue.textContent = Math.round(value * 100) + '%'; saveSettings(); // Speichern nach Änderung }); opacityContainer.appendChild(opacityLabel); opacityContainer.appendChild(opacitySlider); opacityContainer.appendChild(opacityValue); // Z-Index-Slider const zIndexContainer = document.createElement('div'); zIndexContainer.className = 'slider-container'; const zIndexLabel = document.createElement('span'); zIndexLabel.textContent = 'Ebene: '; const zIndexValue = document.createElement('span'); zIndexValue.className = 'slider-value'; zIndexValue.textContent = layer.getZIndex() || DEFAULT_ZINDEX; const zIndexSlider = document.createElement('input'); zIndexSlider.type = 'range'; zIndexSlider.min = '5'; zIndexSlider.max = '2500'; zIndexSlider.step = '5'; zIndexSlider.value = layer.getZIndex() || DEFAULT_ZINDEX; zIndexSlider.addEventListener('input', () => { const zIndex = parseInt(zIndexSlider.value); layer.setZIndex(zIndex); zIndexValue.textContent = zIndex; saveSettings(); // Speichern nach Änderung }); zIndexContainer.appendChild(zIndexLabel); zIndexContainer.appendChild(zIndexSlider); zIndexContainer.appendChild(zIndexValue); container.appendChild(label); container.appendChild(opacityContainer); container.appendChild(zIndexContainer); return container; } // Globale Filter-Einstellungen let globalFilters = { brightness: 100, contrast: 100, saturation: 100, sharpness: 100 }; function createGlobalFilterControls() { const container = document.createElement('div'); container.className = 'layer-group'; const header = document.createElement('div'); header.className = 'group-header'; header.innerHTML = `<span class="group-title">🎨 Karten Einstellungen</span>`; container.appendChild(header); // Helligkeit-Slider const brightnessContainer = document.createElement('div'); brightnessContainer.className = 'slider-container global-filter'; const brightnessLabel = document.createElement('span'); brightnessLabel.textContent = 'Helligkeit: '; const brightnessValue = document.createElement('span'); brightnessValue.className = 'slider-value'; brightnessValue.textContent = globalFilters.brightness + '%'; const brightnessSlider = document.createElement('input'); brightnessSlider.type = 'range'; brightnessSlider.min = '0'; brightnessSlider.max = '300'; brightnessSlider.step = '1'; brightnessSlider.value = globalFilters.brightness; brightnessSlider.addEventListener('input', () => { const value = parseInt(brightnessSlider.value); globalFilters.brightness = value; brightnessValue.textContent = value + '%'; updateAllLayerFilters(); saveGlobalFilters(); }); brightnessContainer.appendChild(brightnessLabel); brightnessContainer.appendChild(brightnessSlider); brightnessContainer.appendChild(brightnessValue); // Kontrast-Slider const contrastContainer = document.createElement('div'); contrastContainer.className = 'slider-container global-filter'; const contrastLabel = document.createElement('span'); contrastLabel.textContent = 'Kontrast: '; const contrastValue = document.createElement('span'); contrastValue.className = 'slider-value'; contrastValue.textContent = globalFilters.contrast + '%'; const contrastSlider = document.createElement('input'); contrastSlider.type = 'range'; contrastSlider.min = '0'; contrastSlider.max = '300'; contrastSlider.step = '1'; contrastSlider.value = globalFilters.contrast; contrastSlider.addEventListener('input', () => { const value = parseInt(contrastSlider.value); globalFilters.contrast = value; contrastValue.textContent = value + '%'; updateAllLayerFilters(); saveGlobalFilters(); }); contrastContainer.appendChild(contrastLabel); contrastContainer.appendChild(contrastSlider); contrastContainer.appendChild(contrastValue); // Sättigung-Slider const saturationContainer = document.createElement('div'); saturationContainer.className = 'slider-container global-filter'; const saturationLabel = document.createElement('span'); saturationLabel.textContent = 'Sättigung: '; const saturationValue = document.createElement('span'); saturationValue.className = 'slider-value'; saturationValue.textContent = globalFilters.saturation + '%'; const saturationSlider = document.createElement('input'); saturationSlider.type = 'range'; saturationSlider.min = '0'; saturationSlider.max = '300'; saturationSlider.step = '1'; saturationSlider.value = globalFilters.saturation; saturationSlider.addEventListener('input', () => { const value = parseInt(saturationSlider.value); globalFilters.saturation = value; saturationValue.textContent = value + '%'; updateAllLayerFilters(); saveGlobalFilters(); }); saturationContainer.appendChild(saturationLabel); saturationContainer.appendChild(saturationSlider); saturationContainer.appendChild(saturationValue); // Schärfe-Slider (mit funktionierender Implementierung) const sharpnessContainer = document.createElement('div'); sharpnessContainer.className = 'slider-container global-filter'; const sharpnessLabel = document.createElement('span'); sharpnessLabel.textContent = 'Schärfe: '; const sharpnessValue = document.createElement('span'); sharpnessValue.className = 'slider-value'; sharpnessValue.textContent = globalFilters.sharpness + '%'; const sharpnessSlider = document.createElement('input'); sharpnessSlider.type = 'range'; sharpnessSlider.min = '0'; sharpnessSlider.max = '300'; sharpnessSlider.step = '1'; sharpnessSlider.value = globalFilters.sharpness; sharpnessSlider.addEventListener('input', () => { const value = parseInt(sharpnessSlider.value); globalFilters.sharpness = value; sharpnessValue.textContent = value + '%'; updateAllLayerFilters(); saveGlobalFilters(); }); sharpnessContainer.appendChild(sharpnessLabel); sharpnessContainer.appendChild(sharpnessSlider); sharpnessContainer.appendChild(sharpnessValue); container.appendChild(brightnessContainer); container.appendChild(contrastContainer); container.appendChild(saturationContainer); container.appendChild(sharpnessContainer); return container; } async function initializeScript() { try { // Registriere Script-Info W.userscripts[SCRIPT_ID] = { name: SCRIPT_NAME, author: 'Hiwi234', version: GM_info.script.version }; // Patche OpenLayers für WMTS Support patchOpenLayers(); // Warte kurz für OpenLayers Patches await new Promise(resolve => setTimeout(resolve, 1000)); // Erstelle alle Layer console.log("Creating layers..."); const wmtsPromises = []; Object.keys(layerGroups).forEach(groupKey => { const group = layerGroups[groupKey]; group.layers.forEach(layerConfig => { if (layerConfig.type === 'wmts') { wmtsPromises.push(createWMTSLayer(layerConfig)); } else { createBasicLayer(layerConfig); } }); }); // Warte auf alle WMTS Layer await Promise.allSettled(wmtsPromises); // Erstelle Sidebar Tab const { tabLabel, tabPane } = W.userscripts.registerSidebarTab(SCRIPT_ID); tabLabel.textContent = 'Multi Map 🗺️'; tabLabel.title = 'Erweiterte Karten-Overlays'; await W.userscripts.waitForElementConnected(tabPane); // Erstelle Content Container const content = document.createElement('div'); content.className = 'overlay-tab'; // Lade globale Filter-Einstellungen loadGlobalFilters(); // Füge alle Gruppen in der gewünschten Reihenfolge hinzu const groupOrder = ['basic', 'germany', 'austria', 'switzerland', 'unofficial']; groupOrder.forEach(groupKey => { if (layerGroups[groupKey]) { const group = layerGroups[groupKey]; const groupContainer = createLayerControl(null, group.name, true); group.layers.forEach(layerConfig => { if (layers[layerConfig.id]) { groupContainer.appendChild(createLayerControl(layerConfig.id, layerConfig.name)); } }); content.appendChild(groupContainer); } }); // Füge globale Filter-Kontrollen am Ende hinzu content.appendChild(createGlobalFilterControls()); tabPane.appendChild(content); // Füge Reset-Button hinzu const resetContainer = document.createElement('div'); resetContainer.className = 'reset-container'; const resetButton = document.createElement('button'); resetButton.textContent = '🔄 Einstellungen zurücksetzen'; resetButton.className = 'reset-button'; resetButton.addEventListener('click', () => { if (confirm('Alle Einstellungen zurücksetzen?')) { localStorage.removeItem(STORAGE_KEY); localStorage.removeItem('wme-overlay-global-filters'); location.reload(); } }); resetContainer.appendChild(resetButton); tabPane.appendChild(resetContainer); // Füge erweiterte Styles hinzu const style = document.createElement('style'); style.textContent = ` .overlay-tab { padding: 8px; max-height: 70vh; overflow-y: auto; } .layer-group { margin-bottom: 15px; border: 1px solid #ddd; border-radius: 6px; overflow: hidden; } .group-header { background: #f5f5f5; padding: 8px 12px; font-weight: bold; border-bottom: 1px solid #ddd; } .group-title { font-size: 14px; } .layer-control { margin: 0; padding: 12px; border-bottom: 1px solid #eee; } .layer-control:last-child { border-bottom: none; } .layer-control label { display: block; margin-bottom: 8px; font-weight: 500; cursor: pointer; } .layer-control input[type="checkbox"] { margin-right: 8px; } .slider-container { margin: 6px 0; display: flex; align-items: center; } .global-filter { padding: 8px 12px; border-bottom: 1px solid #eee; } .global-filter:last-child { border-bottom: none; } .slider-container span { display: inline-block; width: 90px; font-size: 12px; color: #666; } .slider-container input[type="range"] { flex: 1; margin: 0 8px; } .slider-value { width: 40px !important; text-align: right; font-weight: 500; color: #333 !important; } .reset-container { margin-top: 15px; padding: 15px; border-top: 1px solid #ddd; text-align: center; } .reset-button { background: #f44336; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: background 0.2s; } .reset-button:hover { background: #d32f2f; } `; document.head.appendChild(style); console.log(SCRIPT_NAME + ': Erfolgreich initialisiert mit', Object.keys(layers).length, 'Layern'); // Zeige Update-Benachrichtigung showUpdateNotification(); // Initiale Anwendung der globalen Filter setTimeout(() => { updateAllLayerFilters(); }, 2000); } catch (error) { console.error(SCRIPT_NAME + ': Fehler bei der Initialisierung:', error); } } // Starte Initialisierung wenn WME bereit ist if (W?.userscripts?.state.isReady) { initializeScript(); } else { document.addEventListener('wme-ready', initializeScript, { once: true }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址