diff --git a/app.js b/app.js index 4ca2f6b..df3121b 100644 --- a/app.js +++ b/app.js @@ -1202,7 +1202,112 @@ document.addEventListener('DOMContentLoaded', async () => { console.warn("Restriktionsabstände-Layer konnte nicht geladen werden."); } - statusEl.innerText = "Layer geladen (ALKIS DB & Artennachweise integriert)."; + // Leitungsverläufe aus DB laden + console.log("Lade Leitungsverläufe aus Datenbank..."); + const ltgResp = await fetch('/api/layers/leitungsverlaeufe').catch(err => { + console.error("Netzwerkfehler beim Laden der Leitungsverläufe:", err); + return null; + }); + + if (ltgResp?.ok) { + const data = await ltgResp.json(); + console.log(`Leitungsverläufe API: ${data.features ? data.features.length : 0} Features erhalten.`); + + // Alte lokale Layer aufräumen + const localLtgKeys = Object.keys(overlays).filter(k => + (k.toLowerCase().includes('freileitung') || k.toLowerCase().includes('wasserstoff') || k.toLowerCase().includes('leitung')) && !k.includes('(db)') + ); + localLtgKeys.forEach(key => { + console.log(`Entferne lokalen Leitungs-Layer "${key}" (wird durch DB ersetzt).`); + if (state.map.hasLayer(overlays[key])) { + state.map.removeLayer(overlays[key]); + } + layerControl.removeLayer(overlays[key]); + delete overlays[key]; + if (state.bakedData[key]) delete state.bakedData[key]; + }); + + // In zwei Gruppen splitten + const freileitungen = { type: 'FeatureCollection', features: [] }; + const wasserstoff = { type: 'FeatureCollection', features: [] }; + + if (data.features) { + data.features.forEach(f => { + const art = (f.properties.art || '').toLowerCase(); + if (art.includes('freileitung')) { + freileitungen.features.push(f); + } else if (art.includes('wasserstoff')) { + wasserstoff.features.push(f); + } + }); + } + + const createDbLayer = (geojsonData, name, styleFunc, isFreileitung) => { + if (geojsonData.features.length === 0) return; + + const layer = L.geoJSON(geojsonData, { + style: styleFunc, + onEachFeature: (feature, l) => { + if (feature.properties) { + let popup = `${name}

`; + for (let key in feature.properties) { + const val = feature.properties[key]; + if (val !== null && val !== undefined) popup += `${key}: ${val}
`; + } + l.bindPopup(popup); + } + } + }); + overlays[name] = layer; + state.map.addLayer(layer); + layerControl.addOverlay(layer, name); + + // In bakedData eintragen für die Abstandslinien (updateProximityLines) + state.bakedData[name] = { data: geojsonData, style: styleFunc() }; + + // Dynamischer Turf Buffer für Freileitungen + if (isFreileitung) { + try { + const bufferedFeatures = []; + geojsonData.features.forEach(f => { + let dist = 0.05; // 50m default + const spannung = (f.properties.spannung || '').toString().toLowerCase(); + if (spannung.includes('110')) dist = 0.035; + else if (spannung.includes('380')) dist = 0.05; + + const b = turf.buffer(f, dist, {units: 'kilometers'}); + if (b) bufferedFeatures.push(b); + }); + + if (bufferedFeatures.length > 0) { + const bufferLayer = L.geoJSON({ type: 'FeatureCollection', features: bufferedFeatures }, { + style: { + color: '#ffff00', + weight: 0, + fillColor: '#ffff00', + fillOpacity: 0.3 + } + }); + const bufferName = name + " (Puffer)"; + overlays[bufferName] = bufferLayer; + state.map.addLayer(bufferLayer); + layerControl.addOverlay(bufferLayer, bufferName); + bufferLayer.bringToBack(); + } + } catch(err) { + console.error("Fehler beim Erstellen des Puffers für " + name, err); + } + } + }; + + createDbLayer(freileitungen, "Freileitungen (DB)", () => ({ color: '#ccaa00', weight: 3, fillOpacity: 0 }), true); + createDbLayer(wasserstoff, "Wasserstoffleitungen (DB)", () => ({ color: '#9400d3', weight: 2.5, fillOpacity: 0 }), false); + + } else { + console.warn("Leitungsverläufe-Layer konnte nicht geladen werden."); + } + + statusEl.innerText = "Layer geladen (ALKIS DB, Artennachweise & Leitungen integriert)."; } catch (e) { if (!isLocalFile) console.error("Layer-Init fehlgeschlagen:", e); } diff --git a/server.js b/server.js index 399078b..4f20989 100644 --- a/server.js +++ b/server.js @@ -300,6 +300,42 @@ app.get('/api/layers/artennachweise_restriktionen', async (req, res) => { } }); +// NEU: API zum Laden der Leitungsverläufe (Freileitung, Wasserstoff etc.) +app.get('/api/layers/leitungsverlaeufe', async (req, res) => { + log("Lade Leitungsverläufe aus Datenbank..."); + try { + const result = await pool.query( + `SELECT jsonb_build_object( + 'type', 'FeatureCollection', + 'features', COALESCE(jsonb_agg(features.feature), '[]'::jsonb) + ) + FROM ( + SELECT jsonb_build_object( + 'type', 'Feature', + 'geometry', ST_AsGeoJSON(ST_Transform(geom, 4326))::jsonb, + 'properties', jsonb_build_object( + 'art', art, + 'spannung', spannung, + 'ltg_name', ltg_name, + 'bezeichnun', bezeichnun, + 'bemerkung', bemerkung, + 'status', status, + 'quelle', quelle, + 'info', info, + 'vorschlag', vorschlag + ) + ) AS feature + FROM geodaten.leitungsverlaeufe + WHERE art ILIKE '%wasserstoff%' OR art ILIKE '%freileitung%' + ) features` + ); + res.json(result.rows[0].jsonb_build_object); + } catch (err) { + log(`FEHLER beim Laden der Leitungsverläufe: ${err.message}`); + res.status(500).json({ error: err.message }); + } +}); + // API für Projekt-Statistiken (Fortschrittsanzeige) app.get('/api/stats/:projekt_id', async (req, res) => { const { projekt_id } = req.params;