feat(windkarte): permanente 2km/5km-Ringe togglebar in Legende
Zeigt 2km (indigo) und 5km (lila) Pufferringe für alle Gebiete gleichzeitig, unabhängig von Selektion. Default versteckt, Klick auf Legendenitem ein-/ausblenden. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,14 @@
|
|||||||
onready = null,
|
onready = null,
|
||||||
initialGebietsNr = null,
|
initialGebietsNr = null,
|
||||||
hiddenStatuses = [],
|
hiddenStatuses = [],
|
||||||
|
hiddenRings = ["2km", "5km"],
|
||||||
}: {
|
}: {
|
||||||
areas: WindArea[];
|
areas: WindArea[];
|
||||||
onselect: (area: WindArea | null, center: [number, number] | null) => void;
|
onselect: (area: WindArea | null, center: [number, number] | null) => void;
|
||||||
onready?: ((ctrl: { reset: () => void }) => void) | null;
|
onready?: ((ctrl: { reset: () => void }) => void) | null;
|
||||||
initialGebietsNr?: string | null;
|
initialGebietsNr?: string | null;
|
||||||
hiddenStatuses?: string[];
|
hiddenStatuses?: string[];
|
||||||
|
hiddenRings?: string[];
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
// Mirror prop into plain variable so Leaflet event handlers read current value.
|
// Mirror prop into plain variable so Leaflet event handlers read current value.
|
||||||
@@ -46,6 +48,20 @@
|
|||||||
let selectedSlug = $state<string | null>(null);
|
let selectedSlug = $state<string | null>(null);
|
||||||
let geojsonLayer: import("leaflet").GeoJSON | null = null;
|
let geojsonLayer: import("leaflet").GeoJSON | null = null;
|
||||||
let buffering = $state(false);
|
let buffering = $state(false);
|
||||||
|
let permanentRing2km = $state<import("leaflet").LayerGroup | null>(null);
|
||||||
|
let permanentRing5km = $state<import("leaflet").LayerGroup | null>(null);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
const hidden = hiddenRings;
|
||||||
|
for (const [key, layer] of [["2km", permanentRing2km], ["5km", permanentRing5km]] as [string, import("leaflet").LayerGroup | null][]) {
|
||||||
|
if (!layer || !map) continue;
|
||||||
|
if (hidden.includes(key)) {
|
||||||
|
if (map.hasLayer(layer)) map.removeLayer(layer);
|
||||||
|
} else {
|
||||||
|
if (!map.hasLayer(layer)) map.addLayer(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const COLORS: Record<string, { fill: string; stroke: string }> = {
|
const COLORS: Record<string, { fill: string; stroke: string }> = {
|
||||||
rechtskraeftig: { fill: "#2d7a45", stroke: "#1a4d28" },
|
rechtskraeftig: { fill: "#2d7a45", stroke: "#1a4d28" },
|
||||||
@@ -258,6 +274,19 @@
|
|||||||
map.on("zoomend", syncLabels);
|
map.on("zoomend", syncLabels);
|
||||||
syncLabels();
|
syncLabels();
|
||||||
|
|
||||||
|
// Permanent 2km / 5km rings for all areas (built async, shown/hidden via hiddenRings prop)
|
||||||
|
const { buffer: turfBuffer } = await import("@turf/buffer");
|
||||||
|
const r2 = L.layerGroup();
|
||||||
|
const r5 = L.layerGroup();
|
||||||
|
for (const feature of geo.features) {
|
||||||
|
const b2 = turfBuffer(feature, 2, { units: "kilometers" });
|
||||||
|
if (b2) L.geoJSON(b2, { style: { color: "#5e6fa3", fillColor: "#5e6fa3", fillOpacity: 0.04, weight: 1.5, dashArray: "10 5" }, interactive: false }).addTo(r2);
|
||||||
|
const b5 = turfBuffer(feature, 5, { units: "kilometers" });
|
||||||
|
if (b5) L.geoJSON(b5, { style: { color: "#8a567a", fillColor: "#8a567a", fillOpacity: 0.03, weight: 1.5, dashArray: "14 6" }, interactive: false }).addTo(r5);
|
||||||
|
}
|
||||||
|
permanentRing2km = r2;
|
||||||
|
permanentRing5km = r5;
|
||||||
|
|
||||||
// Auto-select from hash
|
// Auto-select from hash
|
||||||
if (initialGebietsNr) {
|
if (initialGebietsNr) {
|
||||||
const entry = layerMap.get(initialGebietsNr);
|
const entry = layerMap.get(initialGebietsNr);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ let areas = $state<WindArea[]>([]);
|
|||||||
let initialGebietsNr = $state<string | null>(null);
|
let initialGebietsNr = $state<string | null>(null);
|
||||||
let resetMap: (() => void) | null = null;
|
let resetMap: (() => void) | null = null;
|
||||||
let hiddenStatuses = $state<string[]>([]);
|
let hiddenStatuses = $state<string[]>([]);
|
||||||
|
let hiddenRings = $state<string[]>(["2km", "5km"]);
|
||||||
|
|
||||||
function toggleStatus(status: string) {
|
function toggleStatus(status: string) {
|
||||||
hiddenStatuses = hiddenStatuses.includes(status)
|
hiddenStatuses = hiddenStatuses.includes(status)
|
||||||
@@ -29,6 +30,12 @@ let areas = $state<WindArea[]>([]);
|
|||||||
: [...hiddenStatuses, status];
|
: [...hiddenStatuses, status];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleRing(ring: string) {
|
||||||
|
hiddenRings = hiddenRings.includes(ring)
|
||||||
|
? hiddenRings.filter((r) => r !== ring)
|
||||||
|
: [...hiddenRings, ring];
|
||||||
|
}
|
||||||
|
|
||||||
const MapComponent = browser
|
const MapComponent = browser
|
||||||
? import("$lib/components/WindkarteMap.svelte").then((m) => m.default)
|
? import("$lib/components/WindkarteMap.svelte").then((m) => m.default)
|
||||||
: null;
|
: null;
|
||||||
@@ -113,6 +120,7 @@ let areas = $state<WindArea[]>([]);
|
|||||||
{areas}
|
{areas}
|
||||||
{initialGebietsNr}
|
{initialGebietsNr}
|
||||||
{hiddenStatuses}
|
{hiddenStatuses}
|
||||||
|
{hiddenRings}
|
||||||
onselect={handleSelect}
|
onselect={handleSelect}
|
||||||
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
||||||
/>
|
/>
|
||||||
@@ -159,6 +167,18 @@ let areas = $state<WindArea[]>([]);
|
|||||||
{ring.label}
|
{ring.label}
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
|
{#each [{ key: "2km", color: "#5e6fa3", label: "2 km" }, { key: "5km", color: "#8a567a", label: "5 km" }] as ring}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onclick={() => toggleRing(ring.key)}
|
||||||
|
class="flex items-center gap-1.5 cursor-pointer select-none transition-opacity
|
||||||
|
{hiddenRings.includes(ring.key) ? 'opacity-35' : 'opacity-100'}"
|
||||||
|
title={hiddenRings.includes(ring.key) ? 'Einblenden (alle Gebiete)' : 'Ausblenden'}
|
||||||
|
>
|
||||||
|
<span class="dashed-line {hiddenRings.includes(ring.key) ? 'opacity-40' : ''}" style="border-color:{ring.color}"></span>
|
||||||
|
<span class="{hiddenRings.includes(ring.key) ? 'line-through' : ''}">{ring.label}</span>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user