Nutzerhilfe nach SIDOUN-Muster, Hilfe-Bilder, Build für wwwpy erweitert

js/hilfe.js + css/hilfe.css: selbstgebautes Hilfe-Modal mit 8 Bereichen und
35 Themen (Suche, Querverweise über data-hilfe, letztes Thema im
localStorage, Stylesheet aus dem Skriptpfad, Bilder aus img/ bzw.
data-eab-base). index.html verliert das statische Hilfe-Modal, bekommt
?-Zeichen an den Abschnittsköpfen und ?v=20260908g; app.js bindet
?-Knopf, F1 und data-hilfe an EABHilfe.oeffnen(), Bilanzstände-Tabelle
scrollt horizontal.

tools/hilfe_screenshots.py erzeugt die Bilder mit Playwright (Beispiel-
Vorhaben im Zwischenspeicher, API-Attrappe für Öffnen/Bilanzstände,
Quantisierung auf 256 Farben). tools/build_meinvln_vorlage.py kopiert
hilfe.js, hilfe.css und die PNG mit und bindet hilfe.js in die Vorlage ein.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
erik
2026-09-08 16:44:38 +02:00
co-authored by Claude Fable 5.1
parent 9f6bf7ab26
commit 22e84081d4
16 changed files with 1167 additions and 51 deletions
+6
View File
@@ -32,6 +32,9 @@ python3 -m http.server 8131 --directory /Users/erik/GIT/eingriffsbilanz
* **Auf-/Abschläge** (Spalte 12 der Biotopwertliste) je Fläche, nur zulässige Nummern.
* **F13/F14 Gesamtbilanz**, Formblätter druckbar, Speichern/Laden als JSON, GeoJSON-Export
(EPSG:25833) mit Bilanzattributen, Autosave im Browser (localStorage).
* **Nutzerhilfe** (`js/hilfe.js`, Muster SIDOUN): ?-Knopf, F1 und ?-Zeichen an den Abschnitten
öffnen ein Modal mit 8 Bereichen / 35 Themen, Suche, Querverweisen und Bildschirmfotos
(`img/hilfe-*.png`, erzeugt von `tools/hilfe_screenshots.py` mit Playwright).
## Weiterentwicklung
@@ -49,10 +52,13 @@ Ohne `data-eab-api` (diese Einzelseite) bleiben Öffnen/Speichern auf dem Server
| `js/bilanz.js` | Rechenkern (reine Funktionen, Formblätter F1–F14) |
| `js/karte.js` | OpenLayers-Karte, WMS-Dienste, Zeichenwerkzeuge |
| `js/app.js` | Zustand, Formulare, Formblatt-Rendering, Persistenz |
| `js/hilfe.js`, `css/hilfe.css` | Nutzerhilfe (Modal, Bereiche/Themen, Suche, `data-hilfe`-Verweise) |
| `img/hilfe-*.png` | Bilder der Nutzerhilfe (256 Farben, aus `tools/hilfe_screenshots.py`) |
| `data/biotopwertliste.json` | Anlage 2 – 527 Einträge (382 bewertbare Biotoptypen) mit BW, PW, KAG, Schutz, LRT, RL, AAS, Definitionen der *-Typen |
| `data/faktoren.json` | Anlagen 1, 3, 4, 6.x: Faktoren, Bonusfaktoren, PIK-Steckbriefe, GRM-Maßnahmen, AAS-Katalog, Einfachfälle |
| `tools/parse_biotopwertliste.py` | pdfplumber-Extraktion der Biotopwertliste aus der Quell-PDF (`he.pdf` = Handlungsempfehlung_kombiniert.pdf) |
| `tools/build_meinvln_vorlage.py` | erzeugt die meinVLN-Vorlage und kopiert die App-Dateien nach wwwpy |
| `tools/hilfe_screenshots.py` | fotografiert die Hilfe-Bilder gegen http://localhost:8131/ (Playwright/Chromium, Beispiel-Vorhaben, API-Attrappe) |
## Datenqualität
+53
View File
@@ -0,0 +1,53 @@
/* ============================================================================
hilfe.css — Aussehen des Hilfe-Modals (js/hilfe.js). Wird von hilfe.js selbst nachgeladen.
Farben über Bootstrap-Variablen (Dark-Mode der Portalhülle), mit Ersatzwerten.
========================================================================== */
.eab-hilfe .modal-header { gap: .75rem; align-items: center; background: var(--bs-tertiary-bg, #f3f5f7); border-bottom: 1px solid var(--bs-border-color, #d6dbe0); }
.eab-hilfe .modal-title { display: flex; align-items: center; gap: .5rem; font-weight: 600; white-space: nowrap; font-size: 1rem; }
.eab-hilfe .modal-title .bi { color: #1a7f3e; }
.eab-hlp-suche { position: relative; flex: 1 1 auto; max-width: 22rem; margin-left: auto; }
.eab-hlp-suche .bi { position: absolute; left: .6rem; top: 50%; transform: translateY(-50%); color: var(--bs-secondary-color, #5a6a7a); font-size: .85rem; pointer-events: none; }
.eab-hlp-suche input { padding-left: 1.9rem; }
.eab-hilfe .modal-body { padding: 0; }
.eab-hlp-raster { display: grid; grid-template-columns: 16.5rem 1fr; min-height: 26rem; }
.eab-hlp-nav { border-right: 1px solid var(--bs-border-color, #d6dbe0); background: var(--bs-tertiary-bg, #fafbfc); padding: .6rem 0 1rem; overflow-y: auto; max-height: 70vh; }
.eab-hlp-inhalt { padding: 1.15rem 1.5rem 1.75rem; overflow-y: auto; max-height: 70vh; outline: none; line-height: 1.6; font-size: .92rem; }
.eab-hlp-gruppe { margin-bottom: .5rem; }
.eab-hlp-gruppe-titel { display: flex; align-items: center; gap: .45rem; padding: .45rem .9rem .3rem; font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--bs-secondary-color, #5a6a7a); }
.eab-hlp-gruppe-titel .bi { color: #1a7f3e; font-size: .9rem; }
a.eab-hlp-thema { display: block; padding: .3rem .9rem .3rem 2rem; font-size: .88rem; color: var(--bs-body-color, #233140); text-decoration: none; border-left: 3px solid transparent; }
a.eab-hlp-thema:hover { background: rgba(26, 127, 62, .12); color: #14622f; }
a.eab-hlp-thema.aktiv { background: rgba(26, 127, 62, .14); border-left-color: #1a7f3e; color: #14622f; font-weight: 600; }
[data-bs-theme=dark] a.eab-hlp-thema:hover, [data-bs-theme=dark] a.eab-hlp-thema.aktiv { color: #4ade80; }
.eab-hlp-leer { padding: 1.2rem 1rem; color: var(--bs-secondary-color, #5a6a7a); font-size: .88rem; }
.eab-hlp-kopf { margin-bottom: .9rem; }
.eab-hlp-marke { display: inline-flex; align-items: center; gap: .35rem; font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #14622f; background: rgba(26, 127, 62, .14); border-radius: 999px; padding: .15rem .6rem; }
[data-bs-theme=dark] .eab-hlp-marke { color: #4ade80; }
.eab-hlp-inhalt h2 { font-size: 1.25rem; font-weight: 700; margin: .5rem 0 0; }
.eab-hlp-inhalt p { margin: 0 0 .8rem; }
.eab-hlp-inhalt ul, .eab-hlp-inhalt ol { margin: 0 0 .9rem; padding-left: 1.3rem; }
.eab-hlp-inhalt li { margin-bottom: .35rem; }
.eab-hlp-inhalt code { background: var(--bs-tertiary-bg, #eef3ef); border-radius: 4px; padding: .05rem .3rem; font-size: .88em; color: inherit; }
.eab-hlp-inhalt a[data-hilfe] { color: #14622f; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.eab-hlp-inhalt a[data-hilfe]:hover { color: #1a7f3e; }
[data-bs-theme=dark] .eab-hlp-inhalt a[data-hilfe] { color: #4ade80; }
table.eab-hlp-tab { width: 100%; border-collapse: collapse; font-size: .86rem; margin: 0 0 1rem; }
table.eab-hlp-tab th { background: var(--bs-tertiary-bg, #eef1f4); text-align: left; font-size: .72rem; letter-spacing: .03em; text-transform: uppercase; padding: .4rem .6rem; border-bottom: 1px solid var(--bs-border-color, #d6dbe0); }
table.eab-hlp-tab td { padding: .38rem .6rem; border-bottom: 1px solid var(--bs-border-color-translucent, #eef2ef); vertical-align: top; }
table.eab-hlp-tab tr:last-child td { border-bottom: 0; }
.eab-hlp-merk, .eab-hlp-warn { border-radius: .6rem; padding: .7rem .9rem; margin: 0 0 1rem; font-size: .9rem; line-height: 1.55; }
.eab-hlp-merk { background: rgba(26, 127, 62, .10); border: 1px solid rgba(26, 127, 62, .3); border-left: 4px solid #1a7f3e; }
.eab-hlp-warn { background: rgba(180, 35, 24, .08); border: 1px solid rgba(180, 35, 24, .3); border-left: 4px solid #b42318; }
.eab-hlp-fuss { margin-right: auto; font-size: .78rem; color: var(--bs-secondary-color, #5a6a7a); }
figure.eab-hlp-fig { margin: 0 0 1.1rem; }
figure.eab-hlp-fig img { display: block; width: 100%; height: auto; border: 1px solid var(--bs-border-color, #d6dbe0); border-radius: .5rem; background: var(--bs-tertiary-bg, #fafbfc); }
figure.eab-hlp-fig figcaption { margin-top: .4rem; font-size: .8rem; line-height: 1.45; color: var(--bs-secondary-color, #5a6a7a); }
.eab-hilfe-link { color: var(--bs-secondary-color, #6c757d); text-decoration: none; margin-left: .35rem; font-size: .85rem; vertical-align: middle; }
.eab-hilfe-link:hover { color: #1a7f3e; }
@media (max-width: 767.98px) {
.eab-hlp-raster { grid-template-columns: 1fr; }
.eab-hlp-nav { border-right: 0; border-bottom: 1px solid var(--bs-border-color, #d6dbe0); max-height: 30vh; }
.eab-hlp-inhalt { max-height: none; padding: 1rem 1.1rem 1.4rem; }
.eab-hilfe .modal-header { flex-wrap: wrap; }
.eab-hlp-suche { max-width: none; width: 100%; margin-left: 0; order: 3; }
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

+15 -43
View File
@@ -8,7 +8,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta3/css/bootstrap-select.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.6.1/ol.css">
<link rel="stylesheet" href="css/app.css?v=20260908f">
<link rel="stylesheet" href="css/app.css?v=20260908g">
</head>
<body class="eab-standalone">
<div class="eab-app">
@@ -26,7 +26,7 @@
<button class="btn btn-outline-light" id="btn-import" title="Vorhaben aus JSON-Datei laden"><i class="bi bi-upload"></i><span class="d-none d-lg-inline"> Laden</span></button>
<button class="btn btn-outline-light" id="btn-geojson" title="Flächen als GeoJSON (EPSG:25833) exportieren"><i class="bi bi-geo"></i><span class="d-none d-lg-inline"> GeoJSON</span></button>
<button class="btn btn-outline-light" id="btn-print" title="Formblätter drucken"><i class="bi bi-printer"></i><span class="d-none d-lg-inline"> Drucken</span></button>
<button class="btn btn-outline-light" id="btn-hilfe" title="Methodik und Bedienung"><i class="bi bi-question-circle"></i></button>
<button class="btn btn-outline-light" id="btn-hilfe" title="Hilfe (F1)"><i class="bi bi-question-circle"></i></button>
</div>
<input type="file" id="file-import" accept=".json,application/json" class="d-none">
</div>
@@ -56,6 +56,7 @@
<button class="btn btn-outline-secondary" data-tool="delete" title="Geometrie der gewählten Fläche löschen"><i class="bi bi-trash"></i></button>
<button class="btn btn-outline-danger" id="btn-draw-cancel" title="Zeichnen abbrechen (Esc)" hidden><i class="bi bi-x-lg"></i> Abbrechen</button>
</div>
<a href="#" class="eab-hilfe-link ms-1" data-hilfe="karte-zeichnen" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a>
</div>
<div class="map-wrap"><div id="map"></div>
<div class="map-legend small">
@@ -84,7 +85,7 @@
<!-- Vorhaben -->
<div class="tab-pane fade show active p-3" id="tab-vorhaben">
<h6 class="text-uppercase text-muted small mb-2">Vorhaben</h6>
<h6 class="text-uppercase text-muted small mb-2">Vorhaben<a href="#" class="eab-hilfe-link" data-hilfe="vorhaben-anlegen" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
<div class="row g-2">
<div class="col-12"><label class="form-label small mb-0">Bezeichnung des Vorhabens</label><input class="form-control form-control-sm" data-meta="name" placeholder="z. B. Neubau Wirtschaftsweg W 12"></div>
<div class="col-6"><label class="form-label small mb-0">Verfahren (VKZ)</label><input class="form-control form-control-sm" data-meta="vkz" placeholder="Verfahrenskennzahl"><div class="form-text small" id="hint-vkz"></div></div>
@@ -98,7 +99,7 @@
<div class="col-12"><label class="form-label small mb-0">Beschreibung / Wirkfaktoren</label><textarea class="form-control form-control-sm" rows="3" data-meta="beschreibung" placeholder="Vorhabenbeschreibung, bau-/anlage-/betriebsbedingte Wirkfaktoren, Einwirkungsbereich …"></textarea></div>
</div>
<h6 class="text-uppercase text-muted small mt-4 mb-2">Anwendungsvoraussetzungen</h6>
<h6 class="text-uppercase text-muted small mt-4 mb-2">Anwendungsvoraussetzungen<a href="#" class="eab-hilfe-link" data-hilfe="vorhaben-einfachfall" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="chk-einfachfall" data-meta="einfachfall">
<label class="form-check-label" for="chk-einfachfall">Einfachfall nach Anlage 1 – kein gutachterlicher Darlegungsbedarf (vereinfachte verbale Gegenüberstellung genügt)</label>
@@ -119,7 +120,7 @@
<!-- Eingriff -->
<div class="tab-pane fade p-3" id="tab-eingriff">
<div class="d-flex align-items-center mb-2">
<h6 class="text-uppercase text-muted small mb-0">1 · Biotoptypen – allgemeine Lebensraumfunktion</h6>
<h6 class="text-uppercase text-muted small mb-0">1 · Biotoptypen – allgemeine Lebensraumfunktion<a href="#" class="eab-hilfe-link" data-hilfe="eingriff-flaeche" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
<div class="btn-group btn-group-sm ms-auto">
<button class="btn btn-primary" id="btn-ef-draw"><i class="bi bi-vector-pen"></i> Fläche zeichnen</button>
<button class="btn btn-outline-primary" id="btn-ef-add" title="Zeile ohne Geometrie (Fläche manuell eingeben)"><i class="bi bi-plus-lg"></i></button>
@@ -129,7 +130,7 @@
<div class="text-muted small mt-1">Bestand = Biotopwert (BW), Zustand nach Eingriff = Planungswert (PW) des Zielbiotoptyps; Versiegelung → z. B. 11.06.110 „Einzelgebäude ohne Begrünung“ (0 WP) oder 11.04.xxx Verkehrsflächen.</div>
<div class="d-flex align-items-center mt-4 mb-2">
<h6 class="text-uppercase text-muted small mb-0">2 · Werte und Funktionen besonderer Bedeutung (Anlage 3 / 4)</h6>
<h6 class="text-uppercase text-muted small mb-0">2 · Werte und Funktionen besonderer Bedeutung (Anlage 3 / 4)<a href="#" class="eab-hilfe-link" data-hilfe="eingriff-funktionen" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
<div class="btn-group btn-group-sm ms-auto">
<button class="btn btn-primary" id="btn-fk-draw" title="Funktionsraum als Fläche zeichnen"><i class="bi bi-vector-pen"></i> Funktionsraum</button>
<button class="btn btn-outline-primary" id="btn-fk-add" title="Zeile ohne Geometrie"><i class="bi bi-plus-lg"></i></button>
@@ -139,7 +140,7 @@
<div class="text-muted small mt-1">Beeinträchtigung: FMF × Grundfläche des Funktionsraums (Tab. 4-1). Aufwertungen im Planungszustand (z. B. Gestaltungsmaßnahmen am Eingriffsort) als „Funktionsherstellung/-erhöhung“ (FH/FE) eintragen → P2.</div>
<div class="d-flex align-items-center mt-4 mb-2">
<h6 class="text-uppercase text-muted small mb-0">3 · Landschaftsbild – landschaftsästhetische Funktion (Anlage 6.2)</h6>
<h6 class="text-uppercase text-muted small mb-0">3 · Landschaftsbild – landschaftsästhetische Funktion (Anlage 6.2)<a href="#" class="eab-hilfe-link" data-hilfe="eingriff-landschaft" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
</div>
<div id="box-land" class="card card-body p-2 small"></div>
@@ -150,7 +151,7 @@
<!-- Kompensation -->
<div class="tab-pane fade p-3" id="tab-komp">
<h6 class="text-uppercase text-muted small mb-1">Kompensationsmaßnahmen</h6>
<h6 class="text-uppercase text-muted small mb-1">Kompensationsmaßnahmen<a href="#" class="eab-hilfe-link" data-hilfe="komp-anlegen" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6>
<div class="d-flex align-items-center mb-1 gap-2">
<select class="form-select form-select-sm flex-grow-1" id="sel-mtyp" style="min-width:0" title="Maßnahmentyp / Formblatt"></select>
<div class="btn-group btn-group-sm flex-shrink-0">
@@ -167,14 +168,14 @@
<div class="tab-pane fade p-3" id="tab-bilanz">
<div id="box-bilanz"></div>
<div id="box-staende" class="eab-server mt-4">
<div class="d-flex align-items-center mb-2"><h6 class="text-uppercase text-muted small mb-0">Festgehaltene Bilanzstände (Server)</h6><button class="btn btn-sm btn-outline-primary ms-auto" id="btn-stand" disabled><i class="bi bi-pin-angle"></i> Bilanzstand festhalten</button></div>
<div class="d-flex align-items-center mb-2"><h6 class="text-uppercase text-muted small mb-0">Festgehaltene Bilanzstände (Server)<a href="#" class="eab-hilfe-link" data-hilfe="bilanz-stand" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></h6><button class="btn btn-sm btn-outline-primary ms-auto" id="btn-stand" disabled><i class="bi bi-pin-angle"></i> Bilanzstand festhalten</button></div>
<div class="staende-liste"></div>
</div>
</div>
<!-- Formblätter -->
<div class="tab-pane fade p-3" id="tab-form">
<div class="d-flex mb-2"><span class="text-muted small">Formblätter nach Anlage 7 (F1 – F14). Druck über <i class="bi bi-printer"></i>.</span><button class="btn btn-sm btn-outline-secondary ms-auto" id="btn-form-refresh"><i class="bi bi-arrow-clockwise"></i> Aktualisieren</button></div>
<div class="d-flex mb-2"><span class="text-muted small">Formblätter nach Anlage 7 (F1 – F14). Druck über <i class="bi bi-printer"></i>.<a href="#" class="eab-hilfe-link" data-hilfe="bilanz-formblaetter" title="Hilfe zu diesem Abschnitt"><i class="bi bi-question-circle"></i></a></span><button class="btn btn-sm btn-outline-secondary ms-auto" id="btn-form-refresh"><i class="bi bi-arrow-clockwise"></i> Aktualisieren</button></div>
<div id="box-form" class="formblaetter"></div>
</div>
</div>
@@ -218,36 +219,6 @@
</div>
</div>
<!-- Modal: Hilfe -->
<div class="modal fade" id="modal-hilfe" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header py-2"><h6 class="modal-title">Methodik und Bedienung</h6><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
<div class="modal-body small">
<h6>Grundprinzip (Biotopwertverfahren)</h6>
<p>Jeder Fläche wird über ihren Biotoptyp ein <b>Biotopwert</b> (BW, 0–30 Wertpunkte je m²) zugeordnet. <b>Wertpunkte (WP) = Fläche [m²] × Wert [WP/m²]</b>. Der Kompensationsbedarf ergibt sich aus dem Vergleich des Zustands vor dem Eingriff (BW) mit dem Zustand nach dem Eingriff (Planungswert PW des neuen Biotoptyps). Kompensationsmaßnahmen werden umgekehrt mit der Differenz Planungswert (Zielbiotoptyp) minus Biotopwert (Ausgangszustand) bewertet.</p>
<h6>Formblätter (Anlage 7)</h6>
<ul>
<li><b>F1</b> Kompensationsbedarf: B1 = (A1 + A2) − (P1 + P2) für den Naturhaushalt, B2 = A3 − P3 für das Landschaftsbild.</li>
<li><b>F2–F11</b> Kompensationsleistung je Maßnahmentyp (L1 Naturhaushalt, L2 Landschaftsbild) mit den jeweiligen Bonusfaktoren (Entsiegelung BFE, PIK BFP, Wiedervernetzung BFV, Gewässerrevitalisierung BFR, Wald/Naturschutz BFN).</li>
<li><b>F12</b> Ersatzzahlung für mastenartige Eingriffe ab 50 m (Prozentsätze der Baukosten).</li>
<li><b>F13/F14</b> Gesamtbilanz: B1 − L1 ≤ 0 und B2 − L2 ≤ 0 → Eingriff vollständig kompensiert.</li>
</ul>
<h6>Werte und Funktionen besonderer Bedeutung (Anlage 3/4)</h6>
<p>Bei Betroffenheit der Stufen mittel/hoch/sehr hoch wird zusätzlich ein Funktionsminderungsfaktor (FMF, Tab. 4-1) mit der Grundfläche des Funktionsraums multipliziert; Kompensationsmaßnahmen erhalten analog einen Funktionsaufwertungsfaktor (FAF).</p>
<h6>Bedienung</h6>
<ul>
<li>Flächen direkt in der Karte zeichnen (Doppelklick beendet die Fläche). Die Fläche wird geodätisch in EPSG:25833 berechnet und kann manuell überschrieben werden.</li>
<li>Biotoptypen über die Auswahlliste mit Suchfeld wählen (Code, Bezeichnung, Wertpunkte). <i class="bi bi-info-circle"></i> zeigt Definition, Schutzstatus, KAG.</li>
<li>Auf-/Abschläge (Spalte 12 der Biotopwertliste) je Fläche über den Button „AAS“; nur die für den Biotoptyp zugelassenen Nummern werden angeboten.</li>
<li>Alle Eingaben werden im Browser zwischengespeichert (localStorage) und können als JSON gesichert/geladen werden.</li>
</ul>
<p class="text-muted">Datenbasis: Biotopwertliste Sachsen (Anlage 2) und Anlagen 1, 3–7 der „Grundlagen für die Anlagen zur Sächsischen Kompensationsverordnung“ (TU Dresden / Froelich &amp; Sporbeck, Stand 01/2017), auf Grundlage der Handlungsempfehlung zur Bewertung und Bilanzierung von Eingriffen im Freistaat Sachsen (SMUL 2009). Automatisch extrahierte Werte – im Zweifel Quelle prüfen.</p>
</div>
</div>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3" id="toasts"></div>
</div><!-- /eab-app -->
@@ -257,8 +228,9 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta3/js/i18n/defaults-de_DE.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.15.0/proj4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.6.1/dist/ol.js"></script>
<script src="js/bilanz.js?v=20260908f"></script>
<script src="js/karte.js?v=20260908f"></script>
<script src="js/app.js?v=20260908f"></script>
<script src="js/bilanz.js?v=20260908g"></script>
<script src="js/karte.js?v=20260908g"></script>
<script src="js/hilfe.js?v=20260908g"></script>
<script src="js/app.js?v=20260908g"></script>
</body>
</html>
+8 -4
View File
@@ -98,8 +98,8 @@
apiGet('staende', { id: P.server.id }).done(r => {
const st = r.staende || [];
if (!st.length) { $b.find('.staende-liste').html('<div class="text-muted small">Noch kein Bilanzstand festgehalten.</div>'); return; }
$b.find('.staende-liste').html('<table class="table table-sm small mb-0"><thead><tr><th>Zeitpunkt</th><th>von</th><th class="text-end">B1</th><th class="text-end">L1</th><th class="text-end">B1 − L1</th><th class="text-end">B2 − L2</th><th class="text-end">E1</th><th>Bemerkung</th></tr></thead><tbody>' +
st.map(x => '<tr><td class="text-nowrap">' + esc(x.berechnet_am) + '</td><td>' + esc(x.berechnet_von || '') + '</td><td class="text-end">' + fmtWP(x.b1) + '</td><td class="text-end">' + fmtWP(x.l1) + '</td><td class="text-end ' + (x.b1 - x.l1 <= 0 ? 'ok' : 'warn') + '">' + fmtWP(x.b1 - x.l1) + '</td><td class="text-end ' + (x.b2 - x.l2 <= 0 ? 'ok' : 'warn') + '">' + fmtWP(x.b2 - x.l2) + '</td><td class="text-end">' + (x.e1 === null || x.e1 === undefined ? '–' : fmtEur(x.e1)) + '</td><td>' + esc(x.bemerkung || '') + '</td></tr>').join('') + '</tbody></table>');
$b.find('.staende-liste').html('<div class="table-responsive"><table class="table table-sm small mb-0"><thead><tr><th>Zeitpunkt</th><th>von</th><th class="text-end">B1</th><th class="text-end">L1</th><th class="text-end">B1 − L1</th><th class="text-end">B2 − L2</th><th class="text-end">E1</th><th>Bemerkung</th></tr></thead><tbody>' +
st.map(x => '<tr><td class="text-nowrap">' + esc(x.berechnet_am) + '</td><td>' + esc(x.berechnet_von || '') + '</td><td class="text-end">' + fmtWP(x.b1) + '</td><td class="text-end">' + fmtWP(x.l1) + '</td><td class="text-end ' + (x.b1 - x.l1 <= 0 ? 'ok' : 'warn') + '">' + fmtWP(x.b1 - x.l1) + '</td><td class="text-end ' + (x.b2 - x.l2 <= 0 ? 'ok' : 'warn') + '">' + fmtWP(x.b2 - x.l2) + '</td><td class="text-end">' + (x.e1 === null || x.e1 === undefined ? '–' : fmtEur(x.e1)) + '</td><td>' + esc(x.bemerkung || '') + '</td></tr>').join('') + '</tbody></table></div>');
}).fail(xhr => $b.find('.staende-liste').html('<div class="warn small">' + esc(fehlerText(xhr)) + '</div>'));
}
function standFesthalten() {
@@ -795,7 +795,7 @@
function renderBilanz(G) {
const ok1 = G.bil1 <= 0.005, ok2 = G.bil2 <= 0.005;
const kachel = (t, v, cls, sub) => '<div class="col-6 col-xl-4"><div class="card h-100"><div class="card-body p-2"><div class="text-muted small">' + t + '</div><div class="wp-big ' + (cls || '') + '">' + v + '</div>' + (sub ? '<div class="small text-muted">' + sub + '</div>' : '') + '</div></div></div>';
let h = '<h6 class="text-uppercase text-muted small mb-2">Gesamtbilanz (' + (G.mast ? 'F14' : 'F13') + ')</h6><div class="row g-2">' +
let h = '<h6 class="text-uppercase text-muted small mb-2">Gesamtbilanz (' + (G.mast ? 'F14' : 'F13') + ')<a href="#" class="eab-hilfe-link" data-hilfe="bilanz-lesen" title="Hilfe zur Bilanz"><i class="bi bi-question-circle"></i></a></h6><div class="row g-2">' +
kachel('Kompensationsbedarf Naturhaushalt B1', fmtWP(G.B1) + ' WP', '', 'aus F1: (A1 + A2) − (P1 + P2)') +
kachel('Kompensationsleistung Naturhaushalt L1', fmtWP(G.L1) + ' WP', 'text-success', 'aus F2 – F11') +
kachel('Bilanzwert Naturhaushalt B1 − L1', fmtWP(G.bil1) + ' WP', ok1 ? 'ok' : 'warn', ok1 ? 'Eingriff in den Naturhaushalt vollständig kompensiert' : 'Defizit – weitere Kompensation erforderlich');
@@ -930,7 +930,11 @@
download(dateiname('_flaechen_epsg25833.geojson'), JSON.stringify(gj), 'application/geo+json');
});
$('#btn-print').on('click', () => { renderForm(); showTab('tab-form'); setTimeout(() => window.print(), 300); });
$('#btn-hilfe').on('click', () => bootstrap.Modal.getOrCreateInstance('#modal-hilfe').show());
/* Nutzerhilfe (js/hilfe.js): ?-Knopf, F1, data-hilfe-Verweise in Abschnittsköpfen */
function hilfe(thema) { if (window.EABHilfe) EABHilfe.oeffnen(thema); }
$('#btn-hilfe').on('click', () => hilfe());
$(document).on('click', '.eab-app [data-hilfe]', function (e) { e.preventDefault(); hilfe($(this).data('hilfe')); });
$(document).on('keydown', e => { if (e.key === 'F1' && !e.ctrlKey && !e.metaKey && !e.altKey) { e.preventDefault(); hilfe(); } });
$('#btn-form-refresh').on('click', () => renderForm());
$('button[data-bs-target="#tab-form"]').on('shown.bs.tab', () => renderForm());
+873
View File
@@ -0,0 +1,873 @@
/*!
* hilfe.js — Die Nutzerhilfe der EA-Bilanz als Modal (Muster: sidoun/web_assets/hilfe.js).
*
* Baut sich selbst im DOM auf, lädt ihr eigenes Stylesheet nach und braucht außer dem
* Bootstrap-5-Bundle nichts. Läuft in der Einzelseite (index.html) und in der meinVLN-Vorlage.
*
* Öffentliche API:
* window.EABHilfe.oeffnen() — Hilfe öffnen (zuletzt gelesenes Thema / Überblick)
* window.EABHilfe.oeffnen('eingriff-aas') — direkt bei einem Thema oder Bereich
* window.EABHilfe.themen / .bereiche — Gliederung (für Tests/Diagnose)
*
* Anbindung: app.js öffnet die Hilfe über den ?-Knopf der Werkzeugleiste und über jedes
* Element mit data-hilfe="<thema>" (kleine ?-Zeichen an den Abschnittsüberschriften).
*
* Bilder: bild('name', 'Unterschrift') → hilfe-<name>.png aus dem Statik-Ordner
* (document.body.dataset.eabBase, sonst img/). Erzeugt von tools/hilfe_screenshots.py.
*/
(function () {
'use strict';
var MODAL_ID = 'eab-hilfe-modal';
var LS_LETZTES = 'eab_hilfe_letztes';
/* Bereiche — die Gliederung. `tab` ist der Reiter der Seite, an dem das Thema hängt
(tests/test_eabilanz.py prüft: jeder Reiter hat mindestens ein Thema). */
var BEREICHE = [
{ id: 'start', tab: null, titel: 'Erste Schritte', icon: 'bi-compass' },
{ id: 'karte', tab: null, titel: 'Karte', icon: 'bi-map' },
{ id: 'vorhaben', tab: 'tab-vorhaben', titel: 'Vorhaben', icon: 'bi-folder2-open' },
{ id: 'eingriff', tab: 'tab-eingriff', titel: 'Eingriff (F1)', icon: 'bi-bounding-box' },
{ id: 'kompensation', tab: 'tab-komp', titel: 'Kompensation (F2–F11)', icon: 'bi-tree' },
{ id: 'bilanz', tab: 'tab-bilanz', titel: 'Bilanz und Formblätter', icon: 'bi-calculator' },
{ id: 'fachlich', tab: 'tab-form', titel: 'Fachliche Grundlagen', icon: 'bi-book' },
{ id: 'technik', tab: null, titel: 'Speichern, Zugang, Technik', icon: 'bi-gear' }
];
function assetAdresse(datei) {
var base = (document.body && document.body.dataset && document.body.dataset.eabBase) || '';
if (base) return base + datei;
return 'img/' + datei;
}
function bild(name, unterschrift) {
return '<figure class="eab-hlp-fig"><img loading="lazy" src="' + assetAdresse('hilfe-' + name + '.png') +
'" alt="' + escapeHtml(unterschrift) + '"><figcaption>' + escapeHtml(unterschrift) + '</figcaption></figure>';
}
function merk(html) { return '<div class="eab-hlp-merk">' + html + '</div>'; }
function warn(html) { return '<div class="eab-hlp-warn">' + html + '</div>'; }
function tab(kopf, zeilen) {
return '<table class="eab-hlp-tab"><thead><tr>' + kopf.map(function (k) { return '<th>' + k + '</th>'; }).join('') +
'</tr></thead><tbody>' + zeilen.map(function (z) {
return '<tr>' + z.map(function (c) { return '<td>' + c + '</td>'; }).join('') + '</tr>';
}).join('') + '</tbody></table>';
}
var THEMEN = [
/* ------------------------------------------------------------ Erste Schritte */
{
id: 'start-ueberblick', bereich: 'start', titel: 'Was die EA-Bilanz macht',
schlagworte: 'überblick einstieg ablauf eingriff ausgleich ersatz kompensation biotopwert wertpunkte',
html:
'<p>Die EA-Bilanz stellt einem <b>Eingriff</b> in Natur und Landschaft (Wegebau, Gewässerausbau, ' +
'Gebäude, Masten …) die <b>Kompensation</b> gegenüber — nach dem <a data-hilfe="fach-biotopwert">' +
'Biotopwertverfahren</a> der sächsischen Handlungsempfehlung in der Fassung der Anlagen zur ' +
'Kompensationsverordnung (Stand 01/2017). Alles wird in <b>Wertpunkten</b> gerechnet: ' +
'Fläche in m² × Wert des Biotoptyps in Wertpunkten je m².</p>' +
'<ol>' +
'<li><b>Vorhaben</b> anlegen: Name, Verfahren, Bearbeiter (<a data-hilfe="vorhaben-anlegen">Vorhaben</a>).</li>' +
'<li><b>Eingriff</b> erfassen: Flächen in der Karte zeichnen, Biotoptyp vorher und nachher wählen ' +
'(<a data-hilfe="eingriff-flaeche">Eingriffsfläche</a>). Bei Bedarf Funktionen besonderer Bedeutung ' +
'und Landschaftsbild.</li>' +
'<li><b>Kompensation</b> planen: Maßnahmen zeichnen, Typ und Zielbiotoptyp wählen ' +
'(<a data-hilfe="komp-anlegen">Maßnahme anlegen</a>).</li>' +
'<li><b>Bilanz</b> prüfen: Bedarf minus Leistung ≤ 0 → vollständig kompensiert ' +
'(<a data-hilfe="bilanz-lesen">Bilanz lesen</a>). Formblätter drucken, Stand festhalten.</li>' +
'</ol>' +
bild('ueberblick', 'Links die Karte mit den gezeichneten Flächen, rechts die Reiter Vorhaben · Eingriff · Kompensation · Bilanz · Formblätter.') +
merk('<b>Alles rechnet sofort.</b> Jede Eingabe aktualisiert die Wertpunkte der Zeile, die Summen des ' +
'Reiters und die Gesamtbilanz. Es gibt keinen „Berechnen"-Knopf.')
},
{
id: 'start-oberflaeche', bereich: 'start', titel: 'Die Oberfläche',
schlagworte: 'aufbau karte reiter tabs werkzeugleiste knöpfe leiste',
html:
'<p>Die Seite ist zweigeteilt: <b>links die Karte</b>, <b>rechts die Erfassung</b> in fünf Reitern.</p>' +
tab(['Bereich', 'Was dort steht'], [
['Werkzeugleiste oben', 'Neu · Öffnen · Speichern (Server) · Datei · Laden · GeoJSON · Drucken · Hilfe. Rechts der Speicherstand (Server-Version, lokaler Zwischenstand).'],
['Karte', 'Hintergrund wählen, Flurstücke einblenden, Ort suchen, Werkzeuge Auswählen / Bearbeiten / Löschen. Die Flächen selbst werden aus den Reitern heraus gezeichnet (<a data-hilfe="karte-zeichnen">Fläche zeichnen</a>).'],
['Vorhaben', 'Stammdaten, Verfahren, Status, Einfachfall, Vermeidung, Kompensationskonzept.'],
['Eingriff', 'Eingriffsflächen (Biotoptypen), Werte und Funktionen besonderer Bedeutung, Landschaftsbild — Formblatt F1.'],
['Kompensation', 'Maßnahmen nach Typ F2–F11 mit Bonusfaktoren und Funktionsaufwertungen.'],
['Bilanz', 'Gesamtbilanz F13/F14, Beiträge der Maßnahmen, festgehaltene Bilanzstände.'],
['Formblätter', 'F1–F14 als druckbare Tabellen nach Anlage 7.']
]) +
'<p>Die Reiter zeigen in ihrer Beschriftung den Kompensationsbedarf (Eingriff) und die Anzahl der ' +
'Maßnahmen. Die kleinen <i class="bi bi-question-circle"></i> neben den Abschnittsüberschriften öffnen ' +
'diese Hilfe beim passenden Thema.</p>' +
'<p>Unter etwa 900 px Breite liegt die Karte über der Erfassung.</p>'
},
{
id: 'start-speichern', bereich: 'start', titel: 'Wo die Eingaben bleiben',
schlagworte: 'speichern zwischenspeicher localstorage server datei json export import autosave',
html:
'<p>Drei Ebenen, von flüchtig bis dauerhaft:</p>' +
'<ol>' +
'<li><b>Zwischenspeicher im Browser</b> — automatisch nach jeder Eingabe („lokal 10:15" in der Leiste). ' +
'Gilt nur für dieses Gerät und diesen Browser; beim nächsten Aufruf steht der letzte Stand wieder da.</li>' +
'<li><b>Server</b> — <i class="bi bi-cloud-arrow-up"></i> <b>Speichern</b> (auch Strg+S) legt das Vorhaben ' +
'in der Datenbank ab; <i class="bi bi-folder2-open"></i> <b>Öffnen</b> zeigt alle Vorhaben im Zugriff. ' +
'Details: <a data-hilfe="tech-server">Speichern auf dem Server</a>.</li>' +
'<li><b>Datei</b> — <i class="bi bi-download"></i> <b>Datei</b> exportiert das Vorhaben als JSON ' +
'(mit Geometrien), <i class="bi bi-upload"></i> <b>Laden</b> liest eine solche Datei ein. Für Archiv, ' +
'Weitergabe oder den Umzug zwischen Geräten.</li>' +
'</ol>' +
warn('<b>Neu</b> verwirft alle Eingaben und den Zwischenspeicher. Wer das Vorhaben behalten will, ' +
'speichert vorher auf dem Server oder als Datei.')
},
/* --------------------------------------------------------------------- Karte */
{
id: 'karte-hintergrund', bereich: 'karte', titel: 'Hintergrund, Flurstücke, Ortssuche',
schlagworte: 'hintergrund luftbild dop webatlas osm flurstücke alkis suche adresse ort nominatim',
html:
'<p>Links oben in der Karte:</p>' +
'<ul>' +
'<li><b>Hintergrund</b>: OpenStreetMap (Vorgabe), <b>Luftbild</b> (GeoSN DOP, 20 cm), <b>WebAtlasSN</b> ' +
'oder kein Hintergrund.</li>' +
'<li><b>Flurstücke (ALKIS)</b>: amtliche Flurstücksgrenzen, sichtbar ab Ortsmaßstab (etwa 1:14 000).</li>' +
'<li><b>Ort / Adresse</b>: Suche über OpenStreetMap; der erste Treffer wird angeflogen.</li>' +
'</ul>' +
bild('karte-werkzeuge', 'Werkzeugleiste der Karte: Hintergrund, Flurstücke, Ortssuche und rechts die Werkzeuge Auswählen · Bearbeiten · Löschen.') +
'<p>Die Karte arbeitet im amtlichen Koordinatensystem <b>ETRS89 / UTM 33 (EPSG:25833)</b>; die ' +
'Statuszeile unten zeigt die Koordinaten unter dem Mauszeiger, der Maßstabsbalken die Entfernung.</p>'
},
{
id: 'karte-zeichnen', bereich: 'karte', titel: 'Fläche zeichnen',
schlagworte: 'zeichnen polygon fläche stützpunkt doppelklick abbrechen esc neu zeichnen',
html:
'<p>Flächen werden immer aus dem passenden Reiter heraus gezeichnet — so weiß die Seite, wozu die ' +
'Fläche gehört:</p>' +
tab(['Knopf', 'Ergebnis'], [
['Eingriff → <b>Fläche zeichnen</b>', 'neue <a data-hilfe="eingriff-flaeche">Eingriffsfläche</a> (rot)'],
['Eingriff → <b>Funktionsraum</b>', 'neuer <a data-hilfe="eingriff-funktionen">Funktionsraum</a> (orange, gestrichelt)'],
['Eingriff → Landschaftsbild → <b>Standort setzen</b>', 'Punkt des Bauwerks/Mastes; die Wirkzonen-Kreise entstehen automatisch (violett)'],
['Kompensation → <b>Fläche zeichnen</b>', 'neue <a data-hilfe="komp-anlegen">Maßnahme</a> des gewählten Typs (grün)']
]) +
'<p>Zeichnen: je Klick ein Stützpunkt, <b>Doppelklick</b> schließt die Fläche, <b>Esc</b> oder ' +
'„Abbrechen" verwirft. Die Fläche in m² wird geodätisch berechnet und in die Zeile übernommen.</p>' +
'<p>Der Knopf <i class="bi bi-vector-pen"></i> an einer bestehenden Zeile zeichnet deren Fläche ' +
'<b>neu</b> (die alte Geometrie wird ersetzt). Zeilen ohne Geometrie (<i class="bi bi-plus-lg"></i>) ' +
'bekommen ihre Fläche von Hand — siehe <a data-hilfe="karte-flaeche">Fläche und Verknüpfung</a>.</p>'
},
{
id: 'karte-bearbeiten', bereich: 'karte', titel: 'Auswählen, Bearbeiten, Löschen',
schlagworte: 'bearbeiten stützpunkte verschieben löschen geometrie auswählen klick markieren',
html:
'<p>Die drei Werkzeuge rechts in der Kartenleiste:</p>' +
'<ul>' +
'<li><i class="bi bi-cursor"></i> <b>Auswählen</b> (Vorgabe): Klick auf eine Fläche markiert sie blau ' +
'und springt rechts zur zugehörigen Zeile; Ziehen verschiebt die Karte.</li>' +
'<li><i class="bi bi-pencil"></i> <b>Bearbeiten</b>: Fläche anklicken, dann Stützpunkte ziehen; ein Klick ' +
'auf eine Kante fügt einen Punkt ein. Die Fläche in m² wird sofort nachgerechnet (außer sie ist ' +
'manuell überschrieben).</li>' +
'<li><i class="bi bi-trash"></i> <b>Löschen</b>: Klick auf eine Fläche entfernt nur die <b>Geometrie</b>; ' +
'die Zeile bleibt mit ihrer Fläche als Handeingabe erhalten. Eine ganze Zeile löscht der rote ' +
'Papierkorb in der Zeile.</li>' +
'</ul>' +
'<p>Die Karte fängt beim Zeichnen an vorhandenen Stützpunkten (Snapping) — Nachbarflächen lassen ' +
'sich so lückenlos anschließen.</p>'
},
{
id: 'karte-flaeche', bereich: 'karte', titel: 'Fläche und Verknüpfung',
schlagworte: 'fläche m² manuell überschreiben aus karte übernehmen ohne geometrie verknüpfung zeile',
html:
'<p>Jede Zeile trägt ihre Fläche in m². Sie kommt <b>aus der Karte</b> (Anzeige „aus Karte") oder ' +
'wird <b>von Hand</b> eingegeben („manuell"). Sobald man in das Feld tippt, gilt die Handeingabe — auch ' +
'wenn die Geometrie später geändert wird. <i class="bi bi-arrow-repeat"></i> holt die Fläche wieder aus ' +
'der Karte.</p>' +
'<p>Zeilen ohne Geometrie (angelegt über <i class="bi bi-plus-lg"></i>) sind erlaubt — etwa für ' +
'Flächen aus einem Aufmaß oder einem Bauwerksplan. Sie tauchen in der Karte nicht auf, rechnen aber ' +
'voll mit.</p>' +
merk('Die Fläche eines <b>Funktionsraums</b> darf von der Biotoptypenfläche abweichen; Funktionsräume ' +
'haben eigene Geometrien (orange).')
},
/* ------------------------------------------------------------------ Vorhaben */
{
id: 'vorhaben-anlegen', bereich: 'vorhaben', titel: 'Vorhaben anlegen und beschreiben',
schlagworte: 'vorhaben name verfahren vkz gemeinde träger bearbeiter datum naturschutzbehörde beschreibung wirkfaktoren status',
html:
'<p>Im Reiter <b>Vorhaben</b> stehen die Kopfdaten, die später auf jedem Formblatt erscheinen:</p>' +
'<ul>' +
'<li><b>Bezeichnung</b> — Pflicht für das Speichern auf dem Server.</li>' +
'<li><b>Verfahren (VKZ)</b> — Auswahlliste der Teilnehmergemeinschaften im eigenen Zugriff (mit Suchfeld). ' +
'TG-Vorsitzende <b>müssen</b> ein eigenes Verfahren wählen, sonst lässt sich nicht speichern; der Verband ' +
'darf Vorhaben ohne Verfahren führen.</li>' +
'<li><b>Status</b> — Entwurf · mit UNB abgestimmt · genehmigt · Archiv. Rein beschreibend, sperrt nichts.</li>' +
'<li><b>Maßnahmekennzahl</b> — optionaler Bezug zur Baumaßnahme im Verfahren.</li>' +
'<li><b>Beschreibung / Wirkfaktoren</b> — Vorhaben, bau-/anlage-/betriebsbedingte Wirkungen, Einwirkungsbereich.</li>' +
'</ul>' +
'<p>Darunter die <b>Anwendungsvoraussetzungen</b>: <a data-hilfe="vorhaben-einfachfall">Einfachfall</a> und ' +
'das Kreuz „Werte und Funktionen besonderer Bedeutung betroffen" (Fall B — dann ist der Abschnitt ' +
'<a data-hilfe="eingriff-funktionen">Funktionen</a> zu füllen). <b>Vermeidung</b> (Anlage 5) und ' +
'<b>Kompensationskonzept</b> (räumlicher, funktionaler, zeitlicher Bezug) sind Freitexte, die der ' +
'Nachweis erwartet.</p>'
},
{
id: 'vorhaben-einfachfall', bereich: 'vorhaben', titel: 'Einfachfälle (Anlage 1)',
schlagworte: 'einfachfall anlage 1 kein gutachten stellplatz garage leitung einfriedung baustelle',
html:
'<p>Für kleine Vorhaben verlangt die Kompensationsverordnung keinen gutachterlichen Nachweis, nur ' +
'eine vereinfachte verbale Gegenüberstellung. Die Liste (Anlage 1) klappt unter dem Kreuz auf — z. B. ' +
'Stellplätze bis 100 m², landwirtschaftliche Gebäude bis 100 m² und 5 m Traufhöhe, Leitungen bis 500 m ' +
'ohne Baustraße, Einfriedungen, Baustelleneinrichtungen.</p>' +
'<p>Das Kreuz <b>Einfachfall</b> rechnet nichts anders; es kennzeichnet das Vorhaben und erscheint als ' +
'Hinweis in der Bilanz. Die Zahlen bleiben als Orientierung nutzbar.</p>'
},
/* ------------------------------------------------------------------ Eingriff */
{
id: 'eingriff-flaeche', bereich: 'eingriff', titel: 'Eingriffsfläche erfassen',
schlagworte: 'eingriffsfläche bestand planung vorher nachher biotoptyp wertpunkte wertminderung zustand nach eingriff',
html:
'<p>Jede Eingriffsfläche vergleicht <b>Bestand</b> (vor dem Eingriff, Biotopwert BW) mit dem ' +
'<b>Zustand nach Eingriff</b> (Planungswert PW des neuen Biotoptyps):</p>' +
'<p><code>Wertminderung = Fläche × BW − Fläche × PW</code></p>' +
bild('eingriffsflaeche', 'Eine Eingriffsfläche: links Bestand mit Biotopwert, rechts der Zustand nach dem Eingriff, darunter Fläche und Wertpunkte.') +
'<ol>' +
'<li><b>Fläche zeichnen</b> (oder <i class="bi bi-plus-lg"></i> für eine Zeile ohne Karte).</li>' +
'<li><b>Bezeichnung</b> vergeben — sie erscheint als Beschriftung in der Karte und im Formblatt.</li>' +
'<li><b>Bestand</b> wählen (<a data-hilfe="eingriff-biotoptyp">Biotoptyp finden</a>), ggf. ' +
'<a data-hilfe="eingriff-aas">Auf-/Abschläge</a>.</li>' +
'<li><b>Zustand nach Eingriff</b> wählen — bei Versiegelung siehe <a data-hilfe="eingriff-versiegelung">Versiegelung abbilden</a>.</li>' +
'</ol>' +
'<p>Die Zeile zeigt BW und PW als Wert je m² sowie Wertpunkte Bestand, nach Eingriff und die ' +
'Wertminderung. Die Summe aller Zeilen ist <b>A1</b> bzw. <b>P1</b> im Formblatt F1.</p>' +
merk('Große, gleichartige Flächen dürfen zusammengefasst werden; bei unterschiedlichen Biotoptypen ' +
'oder Zielzuständen je Teilfläche eine eigene Zeile anlegen.')
},
{
id: 'eingriff-biotoptyp', bereich: 'eingriff', titel: 'Biotoptyp finden',
schlagworte: 'biotoptyp suchen auswahlliste code bezeichnung suchfeld info definition kag schutz lrt rote liste',
html:
'<p>Die Auswahllisten enthalten alle 382 bewertbaren Biotoptypen der Biotopwertliste Sachsen, ' +
'gegliedert nach Hauptgruppen (01 Wälder … 11 Siedlung). Das <b>Suchfeld</b> findet nach Code ' +
'(„06.02.110" oder „0602"), Wort („Frischwiese") oder Wertangabe („BW 30").</p>' +
'<p>Unter jedem Eintrag stehen Biotopwert, Planungswert, Kategorie der Ausgleichbarkeit und Schutz. ' +
'Der Knopf <i class="bi bi-info-circle"></i> öffnet die Einzelheiten: Definition (bei ergänzten Typen), ' +
'gesetzlicher Schutz (§ / (§) / ((§))), FFH-Lebensraumtyp, Rote Liste, zulässige Auf-/Abschläge und ' +
'Alternativwerte der Quelle.</p>' +
'<p>Für den <b>Zielzustand</b> (Planung, Maßnahmenziel) bietet die Liste nur Typen mit Planungswert — ' +
'Typen der Kategorie D (nicht wiederherstellbar, z. B. Hochmoor, natürlicher Fels) fehlen dort.</p>' +
'<p>Mehr zu den Werten: <a data-hilfe="fach-biotopwert">Biotopwert und Planungswert</a>.</p>'
},
{
id: 'eingriff-aas', bereich: 'eingriff', titel: 'Auf- und Abschläge (AAS)',
schlagworte: 'aufschlag abschlag aas ausprägung alter bhd neophyten verbuschung straßenabstand standort deich',
html:
'<p>Die Biotopwertliste erlaubt je Biotoptyp bestimmte Auf- oder Abschläge auf den Wert (Spalte 12, ' +
'Nummern 1–15). Der Knopf <b>AAS</b> unter der Biotoptyp-Auswahl öffnet den Dialog — angeboten werden ' +
'<b>nur die für diesen Typ zugelassenen Nummern</b>.</p>' +
bild('aas', 'Der Dialog für Auf- und Abschläge: je zugelassener Nummer eine Auswahl, unten die Summe und der Wert, der sich ergibt.') +
tab(['Nr.', 'Thema', 'Beispiel'], [
['1', 'Ausprägung Gehölzbestand', 'BHD ≤ 20 cm −2, BHD > 60 cm +1, > 100 cm +2'],
['2', 'Deckungsgrad Baumbestand', 'waldartig ≥ 30 % +1, ≥ 50 % +2'],
['3', 'gesetzlich geschützte Ausprägung', '+2 (nur bei (§)-Typen)'],
['4 / 6 / 9', 'Kennarten fehlen / Verbuschung > 25 % / Kulturarten > 40 %', 'je −2'],
['5', 'invasive Neophyten', '−2 bis −5 nach Flächenanteil'],
['10', 'naturschutzrelevanter Standort (nass, trocken, mager)', '+2'],
['11', 'Abstand zu Straßen', '−4 bis 25 m an stark befahrenen Straßen, −2 abgestuft'],
['12 / 13', 'Sohlgestaltung / Oberflächenbefestigung', '+1 / +2 bei wasserdurchlässiger Bauweise'],
['14', 'gebietsfremdes Saatgut/Gehölze', '−4'],
['15', 'Hochwasserschutzdeich: Oberboden, Begrünung, Pflege', 'je Gruppe eine Wahl, bis +9']
]) +
'<p>Zusätzlich gibt es die <b>Abweichung in Absprache mit der Naturschutzbehörde</b> (−5 bis +5) mit ' +
'Begründung. Der Wert bleibt in jedem Fall zwischen 0 und 30 WP/m². Der Knopf zeigt danach die Summe, ' +
'z. B. „AAS −3 (5b)". Beim Wechsel des Biotoptyps fallen Positionen weg, die für den neuen Typ nicht ' +
'zulässig sind.</p>'
},
{
id: 'eingriff-versiegelung', bereich: 'eingriff', titel: 'Versiegelung und Bebauung abbilden',
schlagworte: 'versiegelung straße weg gebäude parkplatz bankett dachbegrünung zustand nach eingriff 0 wertpunkte',
html:
'<p>Versiegelte und bebaute Flächen haben in der Biotopwertliste eigene Typen mit 0 bis 11 WP/m². ' +
'Als <b>Zustand nach Eingriff</b> eignen sich:</p>' +
tab(['Code', 'Biotoptyp', 'PW'], [
['11.04.110 / 120', 'Autobahn, Bundesstraße / Staats-, Kreis-, Gemeindestraße', '0'],
['11.04.130', 'Befestigter Wirtschaftsweg', '0 (+1/+2 bei wassergebundener oder ungebundener Bauweise, AAS 13)'],
['11.04.160', 'Bankett', '1'],
['11.04.200 / 400', 'Parkplatz / sonstiger versiegelter Platz', '0'],
['11.06.110', 'Einzelgebäude ohne Begrünung', '0'],
['11.06.120 / 130 / 140', 'Einzelgebäude mit intensiver / extensiver Dach- / Fassadenbegrünung', '11 / 9 / 6'],
['11.03.910', 'Scherrasen / krautiger Bewuchs auf Straßennebenflächen (Böschungen)', '7'],
['09.07.120', 'Unbefestigter Feldweg', '12']
]) +
'<p>Bei einem Weg also mindestens zwei Zeilen: die Fahrbahn (0) und die Nebenflächen (Bankett, ' +
'Böschung). Bleibt ein Teil der Fläche unverändert, gehört er nicht in die Bilanz.</p>'
},
{
id: 'eingriff-funktionen', bereich: 'eingriff', titel: 'Werte und Funktionen besonderer Bedeutung',
schlagworte: 'funktionen besondere bedeutung anlage 3 4 funktionsraum lebensraum biotopverbund boden retention grundwasser klima faktor fmf faf stufe',
html:
'<p>Werden über den Biotoptyp hinaus <b>Funktionen besonderer Bedeutung</b> (Stufen mittel, hoch, sehr ' +
'hoch nach Anlage 3) beeinträchtigt, kommt je Funktion ein Zuschlag hinzu:</p>' +
'<p><code>Wertpunkte = Fläche des Funktionsraums × Faktor (Tab. 4-1)</code></p>' +
'<ol>' +
'<li><b>Funktionsraum</b> zeichnen oder Zeile anlegen; die Fläche darf von den Biotoptypenflächen abweichen.</li>' +
'<li><b>Funktion</b> wählen — der Hinweistext nennt die Kriterien der Stufen (z. B. Retention: ' +
'Überschwemmungsgebiet HQ100 = sehr hoch, überschwemmungsgefährdet = hoch).</li>' +
'<li><b>Einwirkungsbereich</b> UE (unmittelbar, überbaut) oder EE (erweitert, z. B. Entwässerung, Lärm).</li>' +
'<li><b>Bewertungsstufe</b> und <b>Betroffenheit</b>: FV Verlust · FS Senkung (Wertminderung A2) — ' +
'FH Herstellung · FE Erhöhung (Aufwertung am Eingriffsort, P2).</li>' +
'</ol>' +
tab(['Stufe', 'FV', 'FS', 'FH', 'FE'], [
['mittel', '1,0', '0,5', '0,9', '0,5'],
['hoch', '1,5', '1,0', '1,4', '0,9'],
['sehr hoch', '2,0', '1,5', '1,8', '1,4']
]) +
'<p>Ein abweichender Faktor lässt sich eintragen (Feld „abw."), braucht aber eine Begründung im ' +
'Bemerkungsfeld. Jede Funktion darf auf derselben Fläche nur <b>einmal</b> angesetzt werden.</p>' +
merk('Die Stufen gering/sehr gering lösen keinen Bedarf aus — solche Funktionsräume werden nicht ' +
'erfasst. Das Kreuz „Fall B" im Reiter Vorhaben dokumentiert, dass geprüft wurde.')
},
{
id: 'eingriff-landschaft', bereich: 'eingriff', titel: 'Landschaftsbild (Anlage 6.2)',
schlagworte: 'landschaftsbild landschaftsästhetisch wirkzone radius mast höhe standort anteile stufen sichtbarkeit',
html:
'<p>Beeinträchtigungen des Landschaftsbildes werden über <b>Wirkzonen</b> um das Bauwerk bewertet:</p>' +
tab(['Art des Eingriffs', 'Zone 1', 'Zone 2', 'WP je m²'], [
['sonstiger Eingriff (Gebäude, Weg, Damm …)', '200 m (mind. 50 m, Eingabe)', '—', '0,1'],
['mastenartig 10 bis unter 50 m', '200 m', 'bis 25 × Höhe', '0,2 / 0,1'],
['mastenartig ab 50 m', 'Ersatzzahlung statt Wertpunkte', '', '<a data-hilfe="eingriff-ersatzzahlung">F12</a>']
]) +
'<ol>' +
'<li><b>Art des Eingriffs</b> wählen, bei Masten die <b>Gesamthöhe</b> eintragen.</li>' +
'<li><b>Standort setzen</b>: Punkt in der Karte; die Zonenkreise erscheinen und die Zonenflächen ' +
'werden berechnet (Schloss-Symbol: Fläche manuell überschreiben).</li>' +
'<li>Je Zone die <b>Anteile</b> der Landschaftsbild-Bewertungsstufen <b>sehr hoch / hoch / mittel</b> in ' +
'Prozent eingeben (Rest = gering/sehr gering, ohne Bedarf).</li>' +
'</ol>' +
bild('landschaft', 'Landschaftsbild: Eingriffstyp, Standort und die Anteile der Bewertungsstufen je Wirkzone; rechts die Wertpunkte.') +
'<p><code>WP = WP je m² × Zonenfläche × Anteil × Faktor</code> mit Faktor 1,5 (sehr hoch), 1,0 (hoch), ' +
'0,5 (mittel). Summe = <b>A3</b>. Gestaltungsmaßnahmen am Eingriffsort (Eingrünung, Sichtschutz) ' +
'kommen als Aufwertung <b>P3</b> darunter — Stufe, Herstellung/Erhöhung, Fläche.</p>'
},
{
id: 'eingriff-ersatzzahlung', bereich: 'eingriff', titel: 'Ersatzzahlung bei Masten ab 50 m (F12)',
schlagworte: 'ersatzzahlung windenergie mast 50 m baukosten prozent repowering vreg',
html:
'<p>Bei mastenartigen Eingriffen ab 50 m Gesamthöhe (Windenergieanlagen, Freileitungsmasten, ' +
'Funkmasten) gilt die Beeinträchtigung des Landschaftsbildes als nicht ausgleichbar; statt ' +
'Wertpunkten wird eine <b>Ersatzzahlung</b> berechnet:</p>' +
'<p><code>Ersatzzahlung = Σ Anteil der Stufe am Einwirkungsbereich [%] × Baukosten × Prozentsatz / 100</code></p>' +
tab(['Bewertungsstufe des Landschaftsbildes', 'Prozentsatz der Baukosten'], [
['sehr hoch', '10 %'], ['hoch', '5 %'], ['mittel', '3 %'], ['gering', '1 %'], ['sehr gering', '0 %']
]) +
'<p>Einzugeben: <b>Baukosten</b> (DIN 276, alle Anlagen), die <b>Anteile</b> der Stufen am ' +
'Einwirkungsbereich (Summe 100 %) und ggf. <b>Repowering</b>: −10 % innerhalb eines ' +
'Vorrang-/Eignungsgebiets, −15 % mit vollständigem Rückbau außerhalb, +10 % außerhalb. Das Ergebnis ' +
'E1 steht in der Gesamtbilanz F14; der Naturhaushalt (B1/L1) wird wie sonst bilanziert.</p>'
},
/* -------------------------------------------------------------- Kompensation */
{
id: 'komp-anlegen', bereich: 'kompensation', titel: 'Maßnahme anlegen',
schlagworte: 'maßnahme anlegen typ formblatt fläche zeichnen ausgangszustand zielzustand aufwertung planungswert',
html:
'<p>Oben im Reiter <b>Kompensation</b> zuerst den <b>Maßnahmentyp</b> wählen (die Zeile darunter ' +
'erklärt ihn), dann <b>Fläche zeichnen</b> oder <i class="bi bi-plus-lg"></i>. Jede Maßnahme ' +
'vergleicht:</p>' +
'<p><code>Aufwertung = Fläche × (Planungswert Ziel − Biotopwert Ausgang) × Bonus</code></p>' +
'<ul>' +
'<li><b>Ausgangszustand</b>: der heutige Biotoptyp der Maßnahmenfläche (Biotopwert BW).</li>' +
'<li><b>Zielzustand</b>: der Biotoptyp, der nach 25 Jahren Entwicklung erreicht ist (Planungswert PW).</li>' +
'<li><b>Bonus</b>: je Typ ein Faktor aus den Anlagen 6.3–6.8 — siehe die Themen zu den Typen.</li>' +
'</ul>' +
tab(['Typ', 'Wofür'], [
['<a data-hilfe="komp-f2">F2 Allgemein</a>', 'Biotopentwicklung, Erstaufforstung, Waldumbau, Sukzession, Baumpflanzung'],
['<a data-hilfe="komp-f3">F3 Entsiegelung</a>', 'Entsiegelung, Abriss von Hochbauten'],
['<a data-hilfe="komp-pik">F4 / F5 PIK</a>', 'produktionsintegrierte Maßnahmen auf Acker, Grünland, Weinberg; Artenschutz-PIK'],
['<a data-hilfe="komp-vernetzung">F6 / F7 Wiedervernetzung</a>', 'Biotopverbund flächig/Trittsteine; Querungshilfen'],
['<a data-hilfe="komp-f8">F8 Fließgewässer</a>', 'Querbauwerke, Rückstau, Umgehungsgerinne, Verbau, Auen'],
['<a data-hilfe="komp-f9-f11">F9–F11</a>', 'Naturwaldzelle, Mittel-/Hutewald, Moor, Stillgewässer, Offenland, Trockenmauer']
]) +
bild('massnahme', 'Eine Maßnahme des Typs F8: Steckbrief-Auswahl, Ausgangs- und Zielbiotoptyp, Fläche, übernommene Funktionsaufwertungsfaktoren und die Summen S1–S4.') +
'<p>Die Fußzeile der Maßnahme zeigt S1 (Biotoptypen mit Bonus), S2 (Funktionsaufwertung), S3 ' +
'(Abwertung), S4 (Landschaftsbild) und daraus <b>L1</b> und <b>L2</b>. Rote Hinweise darunter erklärt ' +
'<a data-hilfe="komp-warnungen">Warnhinweise</a>.</p>'
},
{
id: 'komp-f2', bereich: 'kompensation', titel: 'F2 Allgemeine Maßnahme und Baumpflanzung',
schlagworte: 'f2 allgemein biotopentwicklung erstaufforstung waldumbau sukzession baumpflanzung einzelbaum allee obstbaum kronentrauffläche',
html:
'<p>Der Regelfall ohne Bonus: Extensivierung, Anlage von Hecken, Feldgehölzen, Gewässerrandstreifen, ' +
'Erstaufforstung (Ziel = Waldtyp der natürlichen Vegetation), Waldumbau, Sukzession (Ziel Vorwald).</p>' +
'<p><b>Baumpflanzung (Anlage 6.1):</b> Haken setzen, Anzahl und Baumart eingeben. Die Fläche wird ' +
'pauschal gerechnet — <b>30 m²</b> je Laubbaum-Hochstamm, <b>20 m²</b> je Obstbaum — und der ' +
'Ausgangstyp auf „02.02.470 Fläche für Baumpflanzung" (0 WP) gesetzt. Als Ziel z. B. „02.02.410 Allee ' +
'und Baumreihe" (PW 21) oder „02.02.420 Obstbaumreihe" (PW 21).</p>' +
merk('Der Verlust von Einzelbäumen im <b>Eingriff</b> wird über die Kronentrauffläche (r²·π) als ' +
'Eingriffsfläche mit dem Baum-Biotoptyp erfasst; eine Baumschutzsatzung der Gemeinde hat Vorrang.')
},
{
id: 'komp-f3', bereich: 'kompensation', titel: 'F3 Entsiegelung und Abriss',
schlagworte: 'f3 entsiegelung abriss bonus bfe bauwerkshöhe kategorie 50 m² vorwald',
html:
'<p>Entsiegelung wird mit einem <b>Bonusfaktor BFE</b> auf die Wertpunkte belohnt, gestaffelt nach der ' +
'Höhe des abgerissenen Bauwerks:</p>' +
tab(['Kategorie', 'Bauwerkshöhe', 'BFE'], [
['0', 'Entsiegelung ohne Hochbau, unter 3 m', '3,0'],
['1', '3 bis unter 10 m', '4,0'],
['2', '10 bis unter 20 m', '5,0'],
['3', 'ab 20 m', '6,0']
]) +
'<p>Ausgangstyp ist die versiegelte Fläche (z. B. 11.04.200 Parkplatz, 11.06.110 Gebäude), Ziel ' +
'mindestens ein Vorwald nach 25 Jahren oder ein höherwertiger Zieltyp. Mindestgröße 50 m² (Warnung ' +
'darunter). Außer der landschaftsästhetischen Funktion sind keine weiteren Funktionsaufwertungen ' +
'zulässig; Entsiegelungen an Gewässern (Wehrrückbau) laufen über <a data-hilfe="komp-f8">F8</a>.</p>'
},
{
id: 'komp-pik', bereich: 'kompensation', titel: 'F4 / F5 Produktionsintegrierte Kompensation (PIK)',
schlagworte: 'pik produktionsintegriert acker blühstreifen brache randstreifen grünland extensiv säume altgras weinbau lerchenfenster kiebitz feldhamster bonus bfp zfk zfz',
html:
'<p>PIK sind Bewirtschaftungsauflagen auf landwirtschaftlichen Flächen, die weiter genutzt werden. ' +
'Ausgangs- und Zieltyp gibt der Steckbrief vor; die App belegt sie beim Wählen der PIK vor.</p>' +
tab(['PIK', 'Ausgang → Ziel', 'BFP'], [
['1 extensiver Ackerbau (Ackerwildkräuter)', 'Intensivacker → extensiv genutzter Acker nach Bodentyp', '1,7'],
['2 Ackerrandstreifen', 'Intensivacker → 07.05.100', '1,1'],
['3 Einsaatblühstreifen', 'Intensivacker → 07.04.100', '1,6'],
['4 Ackerbrache', 'Intensivacker → Brache nach Bodentyp; Selbstbegrünung 1,2 / Einsaat 1,6', '1,2 / 1,6'],
['5 extensive Grünlandnutzung', 'Intensivgrünland → artenreiches Feuchtgrünland / extensive Wiese / Weide', '1,2'],
['6 Altgrasstreifen', 'Intensivgrünland → 07.06.100', '1,1'],
['7 ökologisch wertvolle Säume', 'Intensivgrünland → Staudenfluren', '1,4'],
['8 Grünlandsondernutzungsformen', 'degenerierter Typ → nicht degeneriertes Pendant', '3,0 (bis 6,0)'],
['9 extensiver Weinbau', '10.04.200 → 10.04.100', '1,1'],
['10 Artenschutz-PIK (F5)', 'Feldlerchenfenster 1,1 (1.000 m² je zwei Fenster) · Kiebitzinsel 1,6 · Feldhamster 1,6', 'kein Biotoptypwechsel']
]) +
'<p><b>Zusatzfaktoren</b> je +0,2: Kombination von mindestens zwei PIK (ZFK) und erfüllte ' +
'Zusatzanforderung aus dem Steckbrief (ZFZ) — nicht bei PIK 6 und 8. Formel F4: ' +
'<code>(PW − BW) × Fläche × (BFP + ZFK + ZFZ)</code>; F5: <code>Bezugsfläche × (BFP + ZFK)</code>. ' +
'Funktionsaufwertungen nur für die landschaftsästhetische Funktion.</p>' +
warn('Mindestanforderungen der Steckbriefe (Breiten, Standzeiten, Fruchtfolge, Düngeverzicht) prüft ' +
'die App nicht — sie gehören in den Zulassungsbescheid.')
},
{
id: 'komp-vernetzung', bereich: 'kompensation', titel: 'F6 / F7 Wiedervernetzung',
schlagworte: 'wiedervernetzung biotopverbund trittstein querungshilfe grünbrücke amphibientunnel durchlass bfv af korridor leiteinrichtung',
html:
'<p><b>F6 nichttechnisch</b> (Hecken, Säume, Gehölzstreifen als Verbindung): Kategorie 1 ohne, ' +
'Kategorie 2 mit spezifischem Zielartenbezug; Form flächig oder Trittsteine.</p>' +
tab(['', 'flächig', 'Trittsteine'], [['Kat. 1', '1,4', '1,2'], ['Kat. 2 (Zielart)', '1,8', '1,6']]) +
'<p>Dazu als Funktionszeile die <b>Herstellung der Biotopverbundfunktion</b> mit dem Faktor der ' +
'Bewertungsstufe des Verbunds (Tab. 4-1). Retention und bioklimatischer Ausgleich dürfen hier nicht ' +
'zusätzlich angesetzt werden.</p>' +
'<p><b>F7 technisch</b> (Grünbrücke, Amphibientunnel, Otterdurchlass an <i>bestehenden</i> Straßen): ' +
'kein Biotoptypwechsel, sondern <code>Fläche der Querungsanlage × 1,8 + anzurechnende Fläche aF × 1,4</code>. ' +
'aF folgt der Anlage 6.5:</p>' +
'<ul>' +
'<li>gewässergebunden wandernde Arten (Fischotter): aF = (Breite Querung + 20 m) × hindernisfreie ' +
'Gewässerstrecke (max. 4.000 m) × Anteil geeigneter Habitate</li>' +
'<li>sonst: aF = (Breite Querung + Länge Leiteinrichtung) × Korridor bis zur nächsten Barriere ' +
'(max. 250 m kleinräumig, 500 m großräumig; Leiteinrichtung großräumig max. 2.500 m) × Anteil</li>' +
'</ul>' +
'<p>Die App rechnet aF aus den Eingaben; ein eigener Wert lässt sich eintragen. Bei Neubauten sind ' +
'Querungshilfen Vermeidung, keine Kompensation.</p>'
},
{
id: 'komp-f8', bereich: 'kompensation', titel: 'F8 Fließgewässer und Auen',
schlagworte: 'fließgewässer gewässer querbauwerk wehr sohlgleite rückstau umgehungsgerinne verrohrung uferverbau entwicklungsraum flutrinne altwasser aue bfr steckbrief faktoren bach fluss',
html:
'<p>Gewässermaßnahmen (Anlage 6.6) haben je Maßnahmentyp feste Bezugsflächen und Faktoren. Ablauf:</p>' +
'<ol>' +
'<li><b>Maßnahme</b> wählen (1a Komplettrückbau Querbauwerk … 7b Sekundäraue) und <b>Bach</b> oder ' +
'<b>Fluss</b> — davon hängen die Faktoren ab.</li>' +
'<li>Ausgangs- und Zieltyp der Gewässerstrecke (Mittelwasserlinie), z. B. 03.02.230 naturfremder Bach ' +
'(3) → 03.02.120 überwiegend naturnaher Bach (PW 22). Bei 4b/4c (Unterhaltung einstellen, ' +
'Strukturelemente) gilt automatisch Ausgang + 3 WP/m².</li>' +
'<li><b>Faktoren des Steckbriefs übernehmen</b>: legt die vorgesehenen Funktionsaufwertungen an ' +
'(Wiederherstellung Biotopverbund 1,4 / 1,8, Erhöhung 0,9 / 1,4, Landschaftsbild 1,4, Retention …); ' +
'je Zeile die <b>Bezugsfläche</b> laut Steckbrief eintragen (Querbauwerkbereich, Gewässer bis zum ' +
'nächsten Querbauwerk max. 4 km, Ufer, Flutrinne …).</li>' +
'<li><b>Bonus Gewässerrevitalisierung BFR 2,0</b> nur bei Rück-/Umbau von Querbauwerken, Beseitigung ' +
'von Rückstau und Entfernung massiven Verbaus — der Haken ist dort vorbelegt.</li>' +
'</ol>' +
warn('Wasserrecht beachten: Anlagen an Gewässern sind genehmigungspflichtig, wesentliche Umgestaltungen ' +
'brauchen ein Planfeststellungs- oder Plangenehmigungsverfahren. Das ersetzt die Bilanz nicht.')
},
{
id: 'komp-f9-f11', bereich: 'kompensation', titel: 'F9 Wald, F10 Weitere, F11 Trockenmauer',
schlagworte: 'wald naturwaldzelle mittelwald hutewald moor renaturierung stillgewässer offenland degeneriert trockenmauer bfn komplexmaßnahme',
html:
'<p><b>F9 Wald</b> (Anlage 6.7, Bonus × Fläche): Naturwaldzelle (Ziel 01.11.200, Bonus 3,0; 5,0 bei ' +
'BHD ≥ 50 cm der 100 stärksten Bäume oder ≥ 5 Biotopbäumen je ha; 6,0 bei beidem), Mittelwald ' +
'(01.12.200) und Hutewald (01.12.100) mit Bonus 3,0. Formel: <code>(PW − BW) × Fläche + Fläche × BFN</code>. ' +
'Erstaufforstung, Waldumbau und Sukzession laufen über <a data-hilfe="komp-f2">F2</a>.</p>' +
'<p><b>F10 Weitere</b> (Anlage 6.8, Bonus auf die Wertpunkte): Moorrenaturierung 3,0 (bis 6,0), ' +
'Wiederherstellung naturnaher Stillgewässer 2,0, Wiederherstellung degenerierter Offenlandbiotope ' +
'(Heiden, Magerrasen, Bergwiesen …) 3,0 (bis 6,0). Komplexmaßnahmen besonderer Bedeutung bis 2,0 ' +
'× Fläche zusätzlich (Ausnahme mit der Naturschutzbehörde).</p>' +
'<p><b>F11 Abweichende Flächenbilanz</b>, Beispiel Trockenmauer: Ausgang 09.07.320 eingefallen (13) → ' +
'Ziel 09.07.310 intakt (PW 23) mit getrennten Flächen der sichtbaren Maueroberfläche; dazu die ' +
'landschaftsästhetische Funktion (Wiederherstellung) mit mindestens Faktor 0,9.</p>'
},
{
id: 'komp-funktionen', bereich: 'kompensation', titel: 'Funktionsaufwertungen eintragen',
schlagworte: 'funktionsaufwertung faf herstellung erhöhung landschaftsbild abwertung s2 s3 s4 zeile funktion',
html:
'<p>Unter jeder Maßnahme steht die Tabelle <b>Auf-/Abwertung von Werten und Funktionen besonderer ' +
'Bedeutung</b>. <b>+ Funktion</b> fügt eine Zeile hinzu: Funktion, Einwirkungsbereich, Stufe, Art ' +
'(FH Herstellung / FE Erhöhung; FV/FS für eine Abwertung), Fläche, Faktor.</p>' +
'<ul>' +
'<li>Der Faktor kommt aus Tab. 4-1 (Platzhalter im Feld); ein Steckbrief-Wert oder eine abgestimmte ' +
'Abweichung wird eingetippt.</li>' +
'<li><i class="bi bi-arrow-down-left"></i> übernimmt die Maßnahmenfläche als Bezugsfläche.</li>' +
'<li><b>Landschaftsästhetische Funktion</b> zählt zu <b>S4 / L2</b>, alle anderen zu S2 (Aufwertung) ' +
'bzw. S3 (Abwertung).</li>' +
'</ul>' +
'<p>Voraussetzung ist eine dauerhafte, erhebliche Aufwertung einer Funktion mittlerer bis sehr hoher ' +
'Bedeutung (Anlage 4, Tab. 4-2/4-3) — etwa Retention durch Anbindung einer Flutrinne, ' +
'Biotopverbund durch eine neue Hecke im Verbundkorridor, Landschaftsbild durch eine Allee.</p>'
},
{
id: 'komp-warnungen', bereich: 'kompensation', titel: 'Warnhinweise verstehen',
schlagworte: 'warnung hinweis rot signifikanz 3 wertpunkte kategorie d planungswert fehlt mindestgröße',
html:
'<p>Rote Hinweise unter einer Maßnahme sperren nichts, zeigen aber Regeln der Anlagen an:</p>' +
tab(['Hinweis', 'Bedeutung'], [
['Aufwertung &lt; 3 WP/m²', 'Signifikanzkriterium (Anlage 6 Nr. 2): der Zieltyp muss mindestens 3 WP/m² über dem Bestand liegen — sonst zählt nur eine nachgewiesene Funktionsaufwertung.'],
['Zielbiotoptyp ohne Planungswert', 'Kategorie D (nicht wiederherstellbar) taugt nicht als Ziel — anderen Typ wählen.'],
['Mindestgröße Entsiegelung 50 m²', 'Kleinere Teilflächen sind nicht anerkennungsfähig (Anlage 6.3).'],
['Entsiegelung / PIK: keine Funktionsaufwertungen außer Landschaftsbild', 'Die Anlagen 6.3 und 6.4 schließen weitere Faktoren aus.'],
['Technische Wiedervernetzung: keine zusätzlichen Faktoren', 'Anlage 6.5 — der Bonus deckt alles ab.'],
['Bonusfaktor über dem Höchstwert', 'F10: Moor/Offenland höchstens 6,0, Stillgewässer 2,0, Komplex 2,0.'],
['Trockenmauer: mind. FAF 0,9', 'Anlage 6.8 Nr. 2 verlangt die Wiederherstellung der landschaftsästhetischen Funktion.']
]) +
'<p>Im Reiter <b>Eingriff</b> ist ein <b>negativer Kompensationsbedarf</b> (B1 &lt; 0) fast immer ein ' +
'Hinweis, dass Bestand und Zustand nach Eingriff vertauscht wurden.</p>'
},
/* --------------------------------------------------------------------- Bilanz */
{
id: 'bilanz-lesen', bereich: 'bilanz', titel: 'Die Bilanz lesen',
schlagworte: 'bilanz b1 b2 l1 l2 bedarf leistung bilanzwert kompensiert defizit f13 f14 orientierung',
html:
'<p>Der Reiter <b>Bilanz</b> stellt Bedarf und Leistung gegenüber:</p>' +
tab(['Größe', 'Herkunft'], [
['<b>B1</b> Kompensationsbedarf Naturhaushalt', 'F1: (A1 Biotoptypen + A2 Funktionen) − (P1 + P2)'],
['<b>B2</b> Kompensationsbedarf Landschaftsbild', 'F1: A3 − P3'],
['<b>L1</b> Kompensationsleistung Naturhaushalt', 'Summe L1 aller Maßnahmen (F2–F11)'],
['<b>L2</b> Kompensationsleistung Landschaftsbild', 'Summe L2 aller Maßnahmen'],
['<b>Bilanzwert</b> B1 − L1 und B2 − L2', '≤ 0: vollständig kompensiert (grün); &gt; 0: Defizit (rot)']
]) +
bild('bilanz', 'Die Gesamtbilanz: Bedarf, Leistung und Bilanzwert für Naturhaushalt und Landschaftsbild, darunter die Beiträge der Maßnahmen und die festgehaltenen Bilanzstände.') +
'<p>Die Tabelle <b>Beiträge der Maßnahmen</b> zeigt je Maßnahme Fläche, Aufwertung je m², Bonus, L1 ' +
'und L2 — und mit <i class="bi bi-exclamation-triangle"></i> offene Warnhinweise. Bei einem Defizit ' +
'nennt die Seite zur Orientierung, wie viel Fläche bei 10 WP/m² Aufwertung oder wie viele Laubbäume ' +
'fehlen. Bei Masten ab 50 m tritt die <a data-hilfe="eingriff-ersatzzahlung">Ersatzzahlung</a> an die ' +
'Stelle von B2/L2 (F14).</p>'
},
{
id: 'bilanz-stand', bereich: 'bilanz', titel: 'Bilanzstand festhalten',
schlagworte: 'bilanzstand festhalten snapshot nachweis naturschutzbehörde abstimmung verlauf server',
html:
'<p><b>Bilanzstand festhalten</b> (nur bei einem auf dem Server gespeicherten Vorhaben) legt die ' +
'aktuellen Summen B1, B2, L1, L2 und E1 mit Zeitpunkt, Bearbeiter und einer Bemerkung als ' +
'unveränderlichen Eintrag ab — etwa vor der Abstimmung mit der Naturschutzbehörde oder bei der ' +
'Einreichung.</p>' +
'<p>Die Liste darunter zeigt alle Stände des Vorhabens; der jüngste Bilanzwert erscheint auch in der ' +
'Vorhabenliste beim <b>Öffnen</b>. Die Fachdaten selbst (Flächen, Biotoptypen) werden davon nicht ' +
'eingefroren — der Stand ist der Nachweis, was zu einem Zeitpunkt gerechnet wurde.</p>'
},
{
id: 'bilanz-formblaetter', bereich: 'bilanz', titel: 'Formblätter und Druck',
schlagworte: 'formblätter f1 f2 f13 drucken pdf anlage 7 abkürzungen btc gbf bw pw bff bfb',
html:
'<p>Der Reiter <b>Formblätter</b> rendert die Tabellen nach Anlage 7: <b>F1</b> (Ausgangs- und ' +
'Planungszustand, Funktionen, Landschaftsbild, B1/B2), je Maßnahme das passende Formblatt ' +
'<b>F2–F11</b>, bei Masten ab 50 m <b>F12</b>, und die Gesamtbilanz <b>F13</b> bzw. <b>F14</b>.</p>' +
bild('formblatt', 'Formblatt F1 mit Bestandszeilen, Funktionen und Landschaftsbild — druckfertig.') +
'<p><i class="bi bi-printer"></i> <b>Drucken</b> öffnet den Druckdialog nur mit den Formblättern ' +
'(Karte und Eingabemasken werden ausgeblendet); über „Als PDF speichern" des Browsers entsteht die ' +
'PDF-Datei. Abkürzungen: BTC/BTB Biotoptypencode/-bezeichnung, GBF Größe der betroffenen Fläche, ' +
'BW/PW Biotop-/Planungswert, BSF Bewertungsstufe, AFB Art der Betroffenheit, FMF/FAF Minderungs-/' +
'Aufwertungsfaktor, BFB/BFF Bewertung nach Biotoptypen/Funktionen. Ein „+", „−" oder „+/−" am Code ' +
'zeigt angesetzte Auf-/Abschläge.</p>'
},
{
id: 'bilanz-geojson', bereich: 'bilanz', titel: 'GeoJSON für QGIS und Manager',
schlagworte: 'geojson export qgis karte flächen attribute epsg 25833 gis',
html:
'<p><i class="bi bi-geo"></i> <b>GeoJSON</b> exportiert alle gezeichneten Flächen im amtlichen ' +
'System EPSG:25833 mit den Bilanzattributen je Fläche (Biotoptypen, Werte, Fläche, Wertpunkte bzw. ' +
'L1/L2 der Maßnahme). Die Datei lässt sich in QGIS oder in die Verfahrenskarte laden — die ' +
'Kompensationsflächen können so in den Wege- und Gewässerplan wandern.</p>' +
'<p>Umgekehrt kommen Geometrien derzeit nur über das Zeichnen in die Bilanz; ein Import von ' +
'Flurstücken oder Shapes ist nicht vorgesehen.</p>'
},
/* --------------------------------------------------------------- Fachlich */
{
id: 'fach-biotopwert', bereich: 'fachlich', titel: 'Biotopwert und Planungswert',
schlagworte: 'biotopwert planungswert wertpunkte 30 bedeutungsklasse kag ausgleichbarkeit 25 jahre wiederherstellung',
html:
'<p>Jeder Biotoptyp der Biotopwertliste Sachsen trägt einen <b>Biotopwert BW</b> von 0 bis 30 ' +
'Wertpunkten je m² nach Natürlichkeit, Seltenheit/Gefährdung und Wiederherstellbarkeit:</p>' +
tab(['Klasse', 'WP/m²', 'Beispiele'], [
['sehr gering', '0–6', 'Straßen, Gebäude, Intensivacker (5), Ansaatgrünland (6)'],
['gering', '7–12', 'Intensivwiese (8), Scherrasen (7), Feldweg (12)'],
['mittel', '13–18', 'Kiefernforst (14), Ackerbrache (13–15), Staudenflur frisch (18)'],
['hoch', '19–24', 'Buchenforst (22), Feuchtgebüsch (23–26), Baumhecke (25)'],
['sehr hoch', '25–30', 'Magere Frischwiese (30), Bruchwald (30), naturnaher Bach (27–30)']
]) +
'<p>Der <b>Planungswert PW</b> ist der Wert, den ein <i>neu zu entwickelnder</i> Biotoptyp nach 25 ' +
'Jahren erreicht. Er liegt umso weiter unter dem Biotopwert, je größer das Wiederherstellungsrisiko ' +
'ist (Kategorie der Ausgleichbarkeit A1 = 0 Punkte Abzug … C2 = 5 Punkte); Kategorie D hat keinen ' +
'Planungswert. Deshalb zählt ein Eingriff mit dem BW des Bestands, eine Maßnahme aber nur mit dem PW ' +
'des Ziels — Verluste wiegen schwerer als Versprechen.</p>'
},
{
id: 'fach-formeln', bereich: 'fachlich', titel: 'Die Formeln der Formblätter',
schlagworte: 'formel rechnung a1 a2 a3 p1 p2 p3 s1 s2 s3 s4 b1 b2 l1 l2 bonus tab 4-1',
html:
tab(['Formblatt', 'Rechnung'], [
['F1 Biotoptypen', 'A1 = Σ Fläche × BW(Bestand) · P1 = Σ Fläche × PW(nach Eingriff)'],
['F1 Funktionen', 'A2 = Σ Funktionsraum × FMF (FV/FS) · P2 = Σ Funktionsraum × FAF (FH/FE)'],
['F1 Landschaftsbild', 'A3 = Σ WPK × Zonenfläche × Anteil × Faktor · P3 = Σ Fläche × FAF'],
['Bedarf', 'B1 = (A1 + A2) − (P1 + P2) · B2 = A3 − P3'],
['F2', 'S1 = (PW − BW) × Fläche'],
['F3', 'S1 = (PW − BW) × Fläche × BFE'],
['F4 / F5', 'S1 = (PW − BW) × Fläche × (BFP + ZFK + ZFZ) · F5: Bezugsfläche × (BFP + ZFK)'],
['F6 / F7', 'S1 = (PW − BW) × Fläche × BFV · F7: Fläche UE × 1,8 + aF × 1,4'],
['F8', 'S1 = (PW − BW) × Fläche × BFR (2,0 nur mit Bonus)'],
['F9', 'S1 = (PW − BW) × Fläche + Fläche × BFN'],
['F10', 'S1 = (PW − BW) × Fläche × BFN (Komplex: + Fläche × BFN)'],
['F11', 'S1 = PW × Fläche Planung − BW × Fläche Ausgang'],
['je Maßnahme', 'S2 = Σ Fläche × FAF (Funktionen) · S3 = Σ Fläche × FMF (Abwertung) · S4 = Landschaftsbild · L1 = S1 + S2 − S3 · L2 = S4'],
['F13 / F14', 'Bilanz = B1 − Σ L1 und B2 − Σ L2 (≤ 0 kompensiert); F14 mit Ersatzzahlung E1']
]) +
'<p>Wertpunkte werden auf zwei Nachkommastellen gerundet, Flächen in ganzen m² geführt. Die ' +
'Faktoren der Tab. 4-1 stehen unter <a data-hilfe="eingriff-funktionen">Funktionen</a>, die ' +
'Bonusfaktoren bei den Maßnahmentypen.</p>'
},
{
id: 'fach-quellen', bereich: 'fachlich', titel: 'Quellen und Grenzen',
schlagworte: 'quelle handlungsempfehlung 2009 kompensationsverordnung 2017 anlagen tu dresden smul grenzen nicht geprüft',
html:
'<p>Datenbasis sind die <b>Anlagen 1–7 der „Grundlagen für die Anlagen zur Sächsischen ' +
'Kompensationsverordnung"</b> (TU Dresden, Prof. Schmidt / Froelich &amp; Sporbeck, Stand 25.01.2017, ' +
'ausdrücklich ein Zwischenstand) auf Grundlage der <b>Handlungsempfehlung zur Bewertung und ' +
'Bilanzierung von Eingriffen im Freistaat Sachsen</b> (SMUL 2009). Die Biotopwertliste wurde ' +
'maschinell aus der PDF übernommen und gegen den Text geprüft; im Zweifel gilt die Quelle.</p>' +
'<p><b>Was die App nicht leistet:</b></p>' +
'<ul>' +
'<li>keine Prüfung der Mindestanforderungen aus den PIK-Steckbriefen und der fachlichen Voraussetzungen ' +
'der Anlagen 6.3–6.8;</li>' +
'<li>keine Verschneidung mit Fachdaten (Biotoptypenkartierung, Überschwemmungsgebiete, Regionalplan) — ' +
'Funktionsräume und Landschaftsbild-Anteile sind Einschätzungen des Bearbeiters;</li>' +
'<li>altersabhängige Kategorien (z. B. C1/B1/A1 bei Gehölzen) und Alternativwerte werden angezeigt, ' +
'nicht automatisch gewählt;</li>' +
'<li>die Bilanz ersetzt weder den landschaftspflegerischen Begleitplan noch die Abstimmung mit der ' +
'Naturschutzbehörde.</li>' +
'</ul>'
},
/* --------------------------------------------------------------- Technik */
{
id: 'tech-zugang', bereich: 'technik', titel: 'Zugang und Rechte',
schlagworte: 'zugang rechte anmelden verband tg vorsitz verfahren kein zugriff 403 login meinvln',
html:
'<p>Die EA-Bilanz ist Teil von <b>meinVLN</b> und nutzt dessen Anmeldung. Zugang haben ' +
'<b>Verbandsmitarbeiter</b> und <b>TG-Vorsitzende</b>; alle anderen sehen „Kein Zugriff".</p>' +
'<ul>' +
'<li>Der Verband sieht und bearbeitet alle Vorhaben, auch solche ohne Verfahren.</li>' +
'<li>TG-Vorsitzende sehen die Vorhaben ihrer Teilnehmergemeinschaft(en) und müssen beim Speichern ein ' +
'eigenes Verfahren gewählt haben.</li>' +
'</ul>' +
'<p>Die Kachel „EA-Bilanz" auf der Startseite von meinVLN führt zur Seite; ohne Anmeldung landet man ' +
'auf der Anmeldemaske und danach wieder hier.</p>'
},
{
id: 'tech-server', bereich: 'technik', titel: 'Speichern auf dem Server, Versionen, Konflikte',
schlagworte: 'server speichern öffnen version konflikt 409 überschreiben löschen strg s liste',
html:
'<p><i class="bi bi-cloud-arrow-up"></i> <b>Speichern</b> legt das Vorhaben in der Datenbank ab und ' +
'zählt seine <b>Version</b> hoch („Server: Version 3 · 08.09.2026 10:15" in der Leiste). ' +
'<i class="bi bi-folder2-open"></i> <b>Öffnen</b> listet alle Vorhaben im Zugriff mit Verfahren, ' +
'Status, letzter Änderung, Anzahl Flächen/Maßnahmen und dem jüngsten Bilanzwert.</p>' +
bild('oeffnen', 'Die Vorhabenliste: Öffnen lädt das Vorhaben samt Karte, der Papierkorb löscht es endgültig vom Server.') +
'<p><b>Konflikt:</b> Hat jemand anderes das Vorhaben inzwischen gespeichert, meldet der Server die ' +
'neuere Version. Die App fragt, ob der eigene Stand trotzdem gespeichert werden soll — „Abbrechen", ' +
'dann über Öffnen den fremden Stand laden und die eigenen Änderungen dort nachziehen.</p>' +
'<p><b>Löschen</b> entfernt das Vorhaben mit allen Flächen und Bilanzständen endgültig. Der lokale ' +
'Zwischenspeicher des eigenen Browsers bleibt davon unberührt.</p>'
},
{
id: 'tech-fehler', bereich: 'technik', titel: 'Wenn etwas nicht geht',
schlagworte: 'fehler problem karte grau lädt nicht fläche fehlt speichern fehlgeschlagen browser aktualisieren',
html:
'<p>Die häufigsten Fälle:</p>' +
'<ul>' +
'<li><b>Karte bleibt grau</b> — kurz warten (Kacheln laden) oder Seite neu laden; ohne Internetzugang ' +
'gibt es keinen Hintergrund, zeichnen geht trotzdem.</li>' +
'<li><b>Fläche steht auf 0</b> — die Zeile hat keine Geometrie oder eine überschriebene Handeingabe; ' +
'<i class="bi bi-arrow-repeat"></i> holt die Kartenfläche zurück.</li>' +
'<li><b>Speichern fehlgeschlagen: Kein Zugriff</b> — als TG-Vorsitz ein eigenes Verfahren wählen.</li>' +
'<li><b>Anmeldung abgelaufen</b> — Listen bleiben leer oder melden „Nicht angemeldet"; Seite neu laden ' +
'und anmelden. Der Zwischenspeicher hält die Eingaben.</li>' +
'<li><b>Eingaben nach Browserwechsel weg</b> — der Zwischenspeicher gilt je Gerät; Vorhaben auf dem ' +
'Server oder als Datei speichern.</li>' +
'</ul>' +
'<p>Bleibt es dabei: Wortlaut der Meldung, Vorhaben und Uhrzeit an den Verband melden — Serverfehler ' +
'werden automatisch als Vorgang im Entwicklungssystem erfasst.</p>'
}
];
/* ==========================================================================
Aufbau des Modals
========================================================================== */
var gebaut = false;
var aktuellesThema = null;
function skriptAdresse() {
var src = (document.currentScript && document.currentScript.src) || '';
if (!src) {
var skripte = document.getElementsByTagName('script');
for (var i = skripte.length - 1; i >= 0; i--) {
var s = skripte[i].getAttribute('src') || '';
if (s.indexOf('hilfe.js') >= 0) { src = s; break; }
}
}
return src;
}
var SKRIPT = skriptAdresse();
/** Stylesheet neben dem Skript: /eabilanz/static/hilfe.js → hilfe.css; Einzelseite js/hilfe.js → css/hilfe.css. */
function styleAdresse() {
if (!SKRIPT) return 'css/hilfe.css';
return SKRIPT.replace(/js\/hilfe\.js/, 'css/hilfe.css').replace(/hilfe\.js(\?|$)/, 'hilfe.css$1');
}
function styleLaden() {
if (document.getElementById('eab-hilfe-css')) return;
var link = document.createElement('link');
link.id = 'eab-hilfe-css'; link.rel = 'stylesheet'; link.href = styleAdresse();
document.head.appendChild(link);
}
function escapeHtml(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
function findeThema(id) {
if (!id) return null;
for (var i = 0; i < THEMEN.length; i++) if (THEMEN[i].id === id) return THEMEN[i];
for (var j = 0; j < THEMEN.length; j++) if (THEMEN[j].bereich === id) return THEMEN[j];
return null;
}
function bereichVon(id) {
for (var i = 0; i < BEREICHE.length; i++) if (BEREICHE[i].id === id) return BEREICHE[i];
return null;
}
function baueModal() {
if (gebaut) return;
styleLaden();
var el = document.createElement('div');
el.className = 'modal fade eab-hilfe';
el.id = MODAL_ID;
el.tabIndex = -1;
el.setAttribute('aria-hidden', 'true');
el.innerHTML =
'<div class="modal-dialog modal-xl modal-dialog-scrollable">' +
' <div class="modal-content">' +
' <div class="modal-header">' +
' <h5 class="modal-title"><i class="bi bi-question-circle"></i> Hilfe zur EA-Bilanz</h5>' +
' <div class="eab-hlp-suche"><i class="bi bi-search"></i>' +
' <input type="search" class="form-control form-control-sm" id="eab-hlp-suchfeld" placeholder="Hilfe durchsuchen …" autocomplete="off" aria-label="Hilfe durchsuchen">' +
' </div>' +
' <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>' +
' </div>' +
' <div class="modal-body"><div class="eab-hlp-raster">' +
' <nav class="eab-hlp-nav" id="eab-hlp-nav" aria-label="Hilfethemen"></nav>' +
' <article class="eab-hlp-inhalt" id="eab-hlp-inhalt" tabindex="-1"></article>' +
' </div></div>' +
' <div class="modal-footer">' +
' <span class="eab-hlp-fuss">EA-Bilanz — Eingriffs- und Kompensationsbilanz Sachsen · Biotopwertverfahren, Stand 01/2017</span>' +
' <button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Schließen</button>' +
' </div>' +
' </div></div>';
document.body.appendChild(el);
baueNavigation('');
el.querySelector('#eab-hlp-nav').addEventListener('click', function (ev) {
var a = ev.target.closest('[data-thema]'); if (!a) return;
ev.preventDefault(); zeigeThema(a.getAttribute('data-thema'));
});
el.querySelector('#eab-hlp-inhalt').addEventListener('click', function (ev) {
var a = ev.target.closest('[data-hilfe]'); if (!a) return;
ev.preventDefault(); ev.stopPropagation(); zeigeThema(a.getAttribute('data-hilfe'));
});
var suchfeld = el.querySelector('#eab-hlp-suchfeld');
suchfeld.addEventListener('input', function () { baueNavigation(suchfeld.value); });
suchfeld.addEventListener('keydown', function (ev) {
if (ev.key !== 'Enter') return;
ev.preventDefault();
var erster = el.querySelector('#eab-hlp-nav [data-thema]');
if (erster) zeigeThema(erster.getAttribute('data-thema'));
});
el.addEventListener('shown.bs.modal', function () { suchfeld.focus(); });
gebaut = true;
}
function passt(thema, suche) {
if (!suche) return true;
var heu = (thema.titel + ' ' + thema.schlagworte + ' ' + thema.html.replace(/<[^>]*>/g, ' ')).toLowerCase();
var worte = suche.toLowerCase().split(/\s+/).filter(Boolean);
for (var i = 0; i < worte.length; i++) if (heu.indexOf(worte[i]) < 0) return false;
return true;
}
function baueNavigation(suche) {
var nav = document.getElementById('eab-hlp-nav'); if (!nav) return;
var teile = [], treffer = 0;
for (var b = 0; b < BEREICHE.length; b++) {
var bereich = BEREICHE[b];
var themen = THEMEN.filter(function (t) { return t.bereich === bereich.id && passt(t, suche); });
if (!themen.length) continue;
treffer += themen.length;
teile.push('<div class="eab-hlp-gruppe"><div class="eab-hlp-gruppe-titel"><i class="bi ' + bereich.icon + '"></i>' + escapeHtml(bereich.titel) + '</div>');
for (var i = 0; i < themen.length; i++) {
var t = themen[i];
teile.push('<a href="#" class="eab-hlp-thema' + (aktuellesThema === t.id ? ' aktiv' : '') + '" data-thema="' + escapeHtml(t.id) + '">' + escapeHtml(t.titel) + '</a>');
}
teile.push('</div>');
}
if (!treffer) teile = ['<div class="eab-hlp-leer">Kein Thema zu „' + escapeHtml(suche) + '“.<br>Ein einzelnes Stichwort versuchen.</div>'];
nav.innerHTML = teile.join('');
}
function zeigeThema(id) {
var thema = findeThema(id);
var box = document.getElementById('eab-hlp-inhalt'); if (!box) return;
if (!thema) { box.innerHTML = '<div class="eab-hlp-leer">Dieses Thema gibt es nicht.</div>'; return; }
aktuellesThema = thema.id;
try { localStorage.setItem(LS_LETZTES, thema.id); } catch (e) { }
var bereich = bereichVon(thema.bereich);
box.innerHTML = '<div class="eab-hlp-kopf">' +
(bereich ? '<span class="eab-hlp-marke"><i class="bi ' + bereich.icon + '"></i>' + escapeHtml(bereich.titel) + '</span>' : '') +
'<h2>' + escapeHtml(thema.titel) + '</h2></div>' + thema.html;
var nav = document.getElementById('eab-hlp-nav');
if (nav) {
nav.querySelectorAll('[data-thema]').forEach(function (a) { a.classList.toggle('aktiv', a.getAttribute('data-thema') === thema.id); });
var aktiv = nav.querySelector('[data-thema].aktiv');
if (aktiv && aktiv.scrollIntoView) aktiv.scrollIntoView({ block: 'nearest' });
}
box.scrollTop = 0;
box.focus({ preventScroll: true });
}
function oeffnen(thema) {
baueModal();
var start = thema;
if (!start) { try { start = localStorage.getItem(LS_LETZTES) || ''; } catch (e) { start = ''; } }
if (!findeThema(start)) start = THEMEN[0].id;
var suchfeld = document.getElementById('eab-hlp-suchfeld');
if (suchfeld) suchfeld.value = '';
baueNavigation('');
zeigeThema(start);
bootstrap.Modal.getOrCreateInstance(document.getElementById(MODAL_ID)).show();
}
window.EABHilfe = { oeffnen: oeffnen, themen: THEMEN, bereiche: BEREICHE };
})();
+10 -4
View File
@@ -53,6 +53,7 @@ def main(wt):
<script>document.body.dataset.eabBase = "{{URL_MEIN}}/eabilanz/static/"; document.body.dataset.eabApi = "{{URL_MEIN}}/eabilanz/index.py";</script>
<script src="{{URL_MEIN}}/eabilanz/static/bilanz.js?v={{VERSION}}"></script>
<script src="{{URL_MEIN}}/eabilanz/static/karte.js?v={{VERSION}}"></script>
<script src="{{URL_MEIN}}/eabilanz/static/hilfe.js?v={{VERSION}}"></script>
<script src="{{URL_MEIN}}/eabilanz/static/app.js?v={{VERSION}}"></script>
{{>meinvln_footer}}
@@ -61,11 +62,16 @@ def main(wt):
open(ziel, "w", encoding="utf-8").write(tpl)
static = os.path.join(wt, "meinvln", "eabilanz", "static")
os.makedirs(static, exist_ok=True)
for q, z in [("css/app.css", "app.css"), ("js/bilanz.js", "bilanz.js"), ("js/karte.js", "karte.js"),
("js/app.js", "app.js"), ("data/biotopwertliste.json", "biotopwertliste.json"),
("data/faktoren.json", "faktoren.json")]:
dateien = [("css/app.css", "app.css"), ("css/hilfe.css", "hilfe.css"), ("js/bilanz.js", "bilanz.js"),
("js/karte.js", "karte.js"), ("js/hilfe.js", "hilfe.js"), ("js/app.js", "app.js"),
("data/biotopwertliste.json", "biotopwertliste.json"), ("data/faktoren.json", "faktoren.json")]
# Bilder der Nutzerhilfe (tools/hilfe_screenshots.py) — flach neben die Skripte, hilfe.js
# lädt sie über document.body.dataset.eabBase.
dateien += [("img/" + n, n) for n in sorted(os.listdir(os.path.join(SRC, "img")))
if n.startswith("hilfe-") and n.endswith(".png")]
for q, z in dateien:
shutil.copyfile(os.path.join(SRC, q), os.path.join(static, z))
print("Vorlage:", ziel, "|", len(tpl), "Zeichen; Statik kopiert nach", static)
print("Vorlage:", ziel, "|", len(tpl), "Zeichen;", len(dateien), "Dateien kopiert nach", static)
if __name__ == "__main__":
+202
View File
@@ -0,0 +1,202 @@
#!/usr/bin/env python3
"""Erzeugt die Bilder der Nutzerhilfe (img/hilfe-*.png) mit Playwright/Chromium.
Aufruf: python3 tools/hilfe_screenshots.py [http://localhost:8131/]
Lädt die Einzelseite, spielt ein Beispiel-Vorhaben in den Zwischenspeicher (localStorage) ein
und schaltet die Server-Elemente über eine API-Attrappe frei (Antworten für tgs/liste/staende),
damit die Bilder der meinVLN-Fassung entsprechen. Danach werden die Ansichten fotografiert, die
hilfe.js über bild('<name>', …) einbindet. Die Namen stehen in BILDER; wer ein Bild in hilfe.js
ergänzt, ergänzt es hier.
"""
import asyncio
import json
import os
import sys
from playwright.async_api import async_playwright
HIER = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(os.path.dirname(HIER), "img")
BASE = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8131/"
API = "/api/eabilanz"
TGS = [{"vkz": 4711, "name": "Freiberg-Nord"}, {"vkz": 4712, "name": "Mulda-Zethau"}, {"vkz": 4720, "name": "Oederan"}]
LISTE = [
{"id": 1, "uuid": "a1", "name": "Neubau Wirtschaftsweg W 12", "vkz": 4711, "vkz_name": "Freiberg-Nord", "ort": "Freiberg, Gemarkung Zug",
"status": "entwurf", "version": 3, "geaendert_am": "08.09.2026 10:15", "geaendert_von": "e.sefkow@vlnsachsen.de",
"n_flaechen": 2, "n_massnahmen": 2, "letzter_bilanzwert": -3120.5},
{"id": 2, "uuid": "a2", "name": "Rückbau Wehr Münzbach", "vkz": 4711, "vkz_name": "Freiberg-Nord", "ort": "Freiberg",
"status": "abgestimmt", "version": 7, "geaendert_am": "02.09.2026 16:40", "geaendert_von": "e.sefkow@vlnsachsen.de",
"n_flaechen": 1, "n_massnahmen": 1, "letzter_bilanzwert": -800},
{"id": 3, "uuid": "a3", "name": "Regenrückhaltebecken Oederan", "vkz": 4720, "vkz_name": "Oederan", "ort": "Oederan",
"status": "genehmigt", "version": 12, "geaendert_am": "21.08.2026 09:05", "geaendert_von": "k.mueller@vlnsachsen.de",
"n_flaechen": 4, "n_massnahmen": 3, "letzter_bilanzwert": 0},
]
STAENDE = [
{"id": 2, "berechnet_am": "08.09.2026 10:15", "berechnet_von": "e.sefkow@vlnsachsen.de", "b1": 128840.0, "b2": 4020.0, "l1": 131960.5, "l2": 540.0, "e1": None, "bemerkung": "nach Abstimmung UNB"},
{"id": 1, "berechnet_am": "01.09.2026 14:02", "berechnet_von": "e.sefkow@vlnsachsen.de", "b1": 128840.0, "b2": 4020.0, "l1": 96200.0, "l2": 0.0, "e1": None, "bemerkung": "Erstfassung"},
]
def projekt(c):
"""Beispiel-Vorhaben um den Mittelpunkt c (EPSG:25833)."""
x, y = c
def poly(pts):
return {"type": "Polygon", "coordinates": [[[x + dx, y + dy] for dx, dy in pts] + [[x + pts[0][0], y + pts[0][1]]]]}
features = [
{"type": "Feature", "id": "f1", "geometry": poly([(-150, -20), (140, 35), (140, 47), (-150, -8)]),
"properties": {"fid": "f1", "rolle": "eingriff", "label": "E1 Trasse Abschnitt 1", "ref": "ef:1"}},
{"type": "Feature", "id": "f2", "geometry": poly([(-150, -8), (140, 47), (140, 52), (-150, -3)]),
"properties": {"fid": "f2", "rolle": "eingriff", "label": "E2 Bankett", "ref": "ef:2"}},
{"type": "Feature", "id": "f3", "geometry": poly([(-40, -60), (100, -30), (110, 60), (-30, 40)]),
"properties": {"fid": "f3", "rolle": "funktionsraum", "label": "F3", "ref": "fk:3"}},
{"type": "Feature", "id": "f4", "geometry": poly([(-260, 60), (-120, 90), (-140, 170), (-280, 140)]),
"properties": {"fid": "f4", "rolle": "kompensation", "label": "M4 Extensivierung Grünland", "ref": "m:4"}},
{"type": "Feature", "id": "f5", "geometry": {"type": "Point", "coordinates": [x - 10, y + 15]},
"properties": {"fid": "f5", "rolle": "standort", "label": "Standort", "ref": "land"}},
]
return {
"version": 1, "seq": 12,
"server": {"id": 1, "uuid": "a1", "version": 3, "geaendert_am": "08.09.2026 10:15"},
"meta": {"name": "Neubau Wirtschaftsweg W 12", "vkz": "4711", "mkz": "", "ort": "Freiberg, Gemarkung Zug",
"traeger": "TG Freiberg-Nord", "bearbeiter": "E. Sefkow", "datum": "2026-09-08", "unb": "LRA Mittelsachsen",
"beschreibung": "Ausbau des Wirtschaftsweges W 12 in Asphalt, 3,50 m Fahrbahn mit Banketten; Länge 290 m.",
"einfachfall": False, "fall_b": True, "vermeidung": "Bauzeit außerhalb der Brutzeit (Oktober bis Februar), Schutz der angrenzenden Feldhecke nach DIN 18920.",
"konzept": "Ausgleich im räumlichen Zusammenhang durch Extensivierung des Grünlandes Flst. 123/4 und Alleepflanzung entlang des Weges.",
"status": "entwurf"},
"eingriff": {
"flaechen": [
{"id": 1, "fid": "f1", "bez": "Trasse Abschnitt 1", "bt_bestand": "06.02.110",
"aas_bestand": [{"key": "5b", "nr": 5, "delta": -3, "text": "erhebliche Flächenanteile invasiver Arten – mittlere Ausprägung"}],
"bt_planung": "11.04.130", "aas_planung": [], "gbf": 4180, "gbf_manuell": False, "kronen_dm": ""},
{"id": 2, "fid": "f2", "bez": "Bankett", "bt_bestand": "06.02.110", "aas_bestand": [], "bt_planung": "11.04.160",
"aas_planung": [], "gbf": 1480, "gbf_manuell": False, "kronen_dm": ""},
],
"funktionen": [
{"id": 3, "fid": "f3", "funktion": "retention", "ewb": "UE", "bsf": "hoch", "afb": "FS", "gbf": 12600,
"gbf_manuell": False, "faktor_override": "", "bemerkung": "überschwemmungsgefährdetes Gebiet Freiberger Mulde"},
],
"landschaft": {"typ": "sonstige", "hoehe": "", "radius1": "200", "radius2_override": "", "standort_fid": "f5",
"anteile": {"1": {"hoch": "40", "mittel": "60"}, "2": {}}, "fwz1": "", "fwz2": "",
"fwz1_manuell": False, "fwz2_manuell": False,
"aufwertungen": [{"id": 6, "bez": "Alleepflanzung entlang des Weges", "bsf": "mittel", "afb": "FH", "gbf": 600, "faktor_override": ""}],
"baukosten": "", "abl": {}, "repowering": "keins"},
},
"massnahmen": [
{"id": 4, "fid": "f4", "typ": "F2", "name": "Extensivierung Grünland Flst. 123/4", "bt_ausgang": "06.03.210", "aas_ausgang": [],
"bt_ziel": "06.02.210", "aas_ziel": [], "gbf": 12400, "gbf_manuell": False, "params": {},
"funktionen": [{"id": 7, "funktion": "spez_lebensraum", "ewb": "UE", "bsf": "hoch", "afb": "FH", "gbf": 12400, "faktor_override": "", "bez": "Wiesenbrüter (Braunkehlchen)"}]},
{"id": 8, "fid": None, "typ": "F8", "name": "Rückbau Wehr Münzbach", "bt_ausgang": "03.02.230", "aas_ausgang": [],
"bt_ziel": "03.02.120", "aas_ziel": [], "gbf": 450, "gbf_manuell": True, "params": {"grm": "1a", "gewtyp": "bach", "bonus": True},
"funktionen": [
{"id": 9, "grm": "1a", "funktion": "biotopverbund", "ewb": "UE", "bsf": "hoch", "afb": "FH", "gbf": 450, "faktor_override": 1.4, "bez": "Fläche Querbauwerkbereich"},
{"id": 10, "grm": "1a", "funktion": "landschaft", "ewb": "UE", "bsf": "hoch", "afb": "FH", "gbf": 450, "faktor_override": 1.4, "bez": "Fläche Querbauwerkbereich"},
{"id": 11, "grm": "1a", "funktion": "biotopverbund", "ewb": "UE", "bsf": "hoch", "afb": "FE", "gbf": 6200, "faktor_override": 0.9, "bez": "Gewässerfläche bis zum nächsten Querbauwerk ober-/unterhalb (max. 4 km)"},
]},
],
"features": {"type": "FeatureCollection", "features": features},
}
async def main():
os.makedirs(OUT, exist_ok=True)
async with async_playwright() as p:
browser = await p.chromium.launch()
ctx = await browser.new_context(viewport={"width": 1440, "height": 900}, device_scale_factor=1, locale="de-DE")
page = await ctx.new_page()
async def api(route, request):
url = request.url
if "action=tgs" in url:
await route.fulfill(json={"ok": True, "tgs": TGS, "verband": True})
elif "action=liste" in url:
await route.fulfill(json={"ok": True, "vorhaben": LISTE})
elif "action=staende" in url:
await route.fulfill(json={"ok": True, "staende": STAENDE})
else:
await route.fulfill(json={"ok": True, "id": 1, "uuid": "a1", "version": 4, "geaendert_am": "08.09.2026 10:30"})
await page.route("**" + API + "**", api)
async def seite(route, request):
r = await route.fetch()
html = await r.text()
html = html.replace('<body class="eab-standalone">',
'<body class="eab-standalone"><script>document.body.dataset.eabApi = "' + API + '";</script>', 1)
await route.fulfill(response=r, body=html, headers={**r.headers, "content-type": "text/html; charset=utf-8"})
await page.route(BASE, seite)
await page.route(BASE + "?*", seite)
# 1. Durchgang: Koordinaten des Beispielorts in 25833 holen (proj4 ist erst in der Seite da).
await page.goto(BASE, wait_until="networkidle")
c = await page.evaluate("ol.proj.fromLonLat([13.3355, 50.9260], 'EPSG:25833')")
await page.evaluate("(p) => localStorage.setItem('eingriffsbilanz.projekt.v1', JSON.stringify(p))", projekt(c))
await page.reload(wait_until="networkidle")
await page.wait_for_timeout(2500) # Kacheln nachladen
await page.evaluate("KARTE.map.updateSize(); KARTE.fitAll();")
await page.wait_for_timeout(2500)
async def tab(name):
await page.click('button[data-bs-target="#' + name + '"]')
await page.wait_for_timeout(600)
await tab("tab-eingriff")
await page.screenshot(path=os.path.join(OUT, "hilfe-ueberblick.png"))
await page.locator(".map-toolbar").screenshot(path=os.path.join(OUT, "hilfe-karte-werkzeuge.png"))
await page.locator('.card[data-kind="ef"][data-id="1"]').screenshot(path=os.path.join(OUT, "hilfe-eingriffsflaeche.png"))
await page.click('.card[data-kind="ef"][data-id="1"] .btn-aas[data-bt="bt_bestand"]')
await page.wait_for_selector("#modal-aas.show")
await page.wait_for_timeout(500)
await page.locator("#modal-aas .modal-content").screenshot(path=os.path.join(OUT, "hilfe-aas.png"))
await page.keyboard.press("Escape")
await page.wait_for_timeout(500)
await page.locator("#box-land").scroll_into_view_if_needed()
await page.locator("#box-land").screenshot(path=os.path.join(OUT, "hilfe-landschaft.png"))
await tab("tab-komp")
await page.locator('.card[data-kind="m"][data-id="8"]').scroll_into_view_if_needed()
await page.locator('.card[data-kind="m"][data-id="8"]').screenshot(path=os.path.join(OUT, "hilfe-massnahme.png"))
await tab("tab-bilanz")
await page.wait_for_timeout(800)
await page.locator("#tab-bilanz").screenshot(path=os.path.join(OUT, "hilfe-bilanz.png"))
await tab("tab-form")
await page.wait_for_timeout(600)
panel = await page.locator(".panel-col").bounding_box()
await page.screenshot(path=os.path.join(OUT, "hilfe-formblatt.png"),
clip={"x": panel["x"], "y": panel["y"], "width": panel["width"], "height": min(760, panel["height"])})
await page.click("#btn-liste")
await page.wait_for_selector("#modal-liste.show")
await page.wait_for_timeout(700)
await page.locator("#modal-liste .modal-content").screenshot(path=os.path.join(OUT, "hilfe-oeffnen.png"))
await page.keyboard.press("Escape")
await browser.close()
verkleinern()
for n in sorted(os.listdir(OUT)):
print(n, os.path.getsize(os.path.join(OUT, n)) // 1024, "KB")
def verkleinern():
"""PNG auf 256 Farben quantisieren (Pillow) — Kartenkacheln machen die Bilder sonst 700 KB groß."""
try:
from PIL import Image
except ImportError:
print("Pillow fehlt — Bilder bleiben unkomprimiert")
return
for n in sorted(os.listdir(OUT)):
if not (n.startswith("hilfe-") and n.endswith(".png")):
continue
p = os.path.join(OUT, n)
im = Image.open(p).convert("RGB")
im.quantize(colors=256, method=Image.Quantize.MEDIANCUT, dither=Image.Dither.FLOYDSTEINBERG).save(p, optimize=True)
if __name__ == "__main__":
asyncio.run(main())