feat(windkarte): Legend-Toggle — Status ein-/ausblendbar per Klick
Klick auf Legendenitem blendet den Status aus (opacity 0, kein Klick, kein Hover). Panel schließt sich wenn der Status des gewählten Gebiets ausgeblendet wird. Visuell: opacity + line-through auf versteckten Items. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,13 +8,37 @@
|
|||||||
onselect,
|
onselect,
|
||||||
onready = null,
|
onready = null,
|
||||||
initialGebietsNr = null,
|
initialGebietsNr = null,
|
||||||
|
hiddenStatuses = [],
|
||||||
}: {
|
}: {
|
||||||
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[];
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
|
// Mirror prop into plain variable so Leaflet event handlers read current value.
|
||||||
|
let _hidden: string[] = [];
|
||||||
|
$effect(() => {
|
||||||
|
_hidden = hiddenStatuses;
|
||||||
|
if (!geojsonLayer) return;
|
||||||
|
restyleAll(selectedSlug);
|
||||||
|
// Deselect if selected area's status was just hidden.
|
||||||
|
if (selectedSlug) {
|
||||||
|
geojsonLayer.eachLayer((l) => {
|
||||||
|
const f = (l as import("leaflet").Path & { feature?: GeoJSON.Feature }).feature;
|
||||||
|
if (f?.properties?.name === selectedSlug) {
|
||||||
|
const s = f.properties?.status ?? "rechtskraeftig";
|
||||||
|
if (_hidden.includes(s)) {
|
||||||
|
selectedSlug = null;
|
||||||
|
onselect(null, null);
|
||||||
|
bufferLayer?.clearLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mapEl: HTMLDivElement;
|
let mapEl: HTMLDivElement;
|
||||||
let map: import("leaflet").Map | null = null;
|
let map: import("leaflet").Map | null = null;
|
||||||
let bufferLayer: import("leaflet").LayerGroup | null = null;
|
let bufferLayer: import("leaflet").LayerGroup | null = null;
|
||||||
@@ -46,7 +70,11 @@
|
|||||||
const f = (l as import("leaflet").Path & { feature?: GeoJSON.Feature }).feature;
|
const f = (l as import("leaflet").Path & { feature?: GeoJSON.Feature }).feature;
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
const s = f.properties?.status ?? "rechtskraeftig";
|
const s = f.properties?.status ?? "rechtskraeftig";
|
||||||
|
if (_hidden.includes(s)) {
|
||||||
|
(l as import("leaflet").Path).setStyle({ opacity: 0, fillOpacity: 0, weight: 0 });
|
||||||
|
} else {
|
||||||
(l as import("leaflet").Path).setStyle(style(s, f.properties?.name === sel));
|
(l as import("leaflet").Path).setStyle(style(s, f.properties?.name === sel));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,19 +196,23 @@
|
|||||||
|
|
||||||
// Hover highlight
|
// Hover highlight
|
||||||
layer.on("mouseover", () => {
|
layer.on("mouseover", () => {
|
||||||
if (feature.properties?.name !== selectedSlug) {
|
|
||||||
const s = feature.properties?.status ?? "rechtskraeftig";
|
const s = feature.properties?.status ?? "rechtskraeftig";
|
||||||
|
if (_hidden.includes(s)) return;
|
||||||
|
if (feature.properties?.name !== selectedSlug) {
|
||||||
(layer as import("leaflet").Path).setStyle(style(s, false, true));
|
(layer as import("leaflet").Path).setStyle(style(s, false, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
layer.on("mouseout", () => {
|
layer.on("mouseout", () => {
|
||||||
if (feature.properties?.name !== selectedSlug) {
|
|
||||||
const s = feature.properties?.status ?? "rechtskraeftig";
|
const s = feature.properties?.status ?? "rechtskraeftig";
|
||||||
|
if (_hidden.includes(s)) return;
|
||||||
|
if (feature.properties?.name !== selectedSlug) {
|
||||||
(layer as import("leaflet").Path).setStyle(style(s, false, false));
|
(layer as import("leaflet").Path).setStyle(style(s, false, false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
layer.on("click", async (e) => {
|
layer.on("click", async (e) => {
|
||||||
|
const s = feature.properties?.status ?? "rechtskraeftig";
|
||||||
|
if (_hidden.includes(s)) return;
|
||||||
L.DomEvent.stopPropagation(e);
|
L.DomEvent.stopPropagation(e);
|
||||||
await selectFeature(L, feature, layer, area);
|
await selectFeature(L, feature, layer, area);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ let areas = $state<WindArea[]>([]);
|
|||||||
let mapReady = $state(false);
|
let mapReady = $state(false);
|
||||||
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[]>([]);
|
||||||
|
|
||||||
|
function toggleStatus(status: string) {
|
||||||
|
hiddenStatuses = hiddenStatuses.includes(status)
|
||||||
|
? hiddenStatuses.filter((s) => s !== status)
|
||||||
|
: [...hiddenStatuses, status];
|
||||||
|
}
|
||||||
|
|
||||||
const MapComponent = browser
|
const MapComponent = browser
|
||||||
? import("$lib/components/WindkarteMap.svelte").then((m) => m.default)
|
? import("$lib/components/WindkarteMap.svelte").then((m) => m.default)
|
||||||
@@ -105,6 +112,7 @@ let areas = $state<WindArea[]>([]);
|
|||||||
<Map
|
<Map
|
||||||
{areas}
|
{areas}
|
||||||
{initialGebietsNr}
|
{initialGebietsNr}
|
||||||
|
{hiddenStatuses}
|
||||||
onselect={handleSelect}
|
onselect={handleSelect}
|
||||||
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
onready={(ctrl) => { resetMap = ctrl.reset; }}
|
||||||
/>
|
/>
|
||||||
@@ -127,18 +135,22 @@ let areas = $state<WindArea[]>([]);
|
|||||||
|
|
||||||
<!-- Legend -->
|
<!-- Legend -->
|
||||||
<div class="mt-2 flex flex-wrap gap-x-5 gap-y-1.5 text-xs text-stein-400">
|
<div class="mt-2 flex flex-wrap gap-x-5 gap-y-1.5 text-xs text-stein-400">
|
||||||
<span class="flex items-center gap-1.5">
|
{#each [
|
||||||
<span class="inline-block size-2.5 rounded-sm" style="background:#2d7a45; opacity:.7"></span>
|
{ status: "rechtskraeftig", color: "#2d7a45", label: t(T.windkarte_legend_rechtskraeftig) },
|
||||||
{t(T.windkarte_legend_rechtskraeftig)}
|
{ status: "entwurf_2", color: "#b08a52", label: t(T.windkarte_legend_entwurf_2) },
|
||||||
</span>
|
{ status: "entwurf_2_voraussichtlich", color: "#d4752a", label: t(T.windkarte_legend_entwurf_2_voraussichtlich) },
|
||||||
<span class="flex items-center gap-1.5">
|
] as item}
|
||||||
<span class="inline-block size-2.5 rounded-sm" style="background:#b08a52; opacity:.7"></span>
|
<button
|
||||||
{t(T.windkarte_legend_entwurf_2)}
|
type="button"
|
||||||
</span>
|
onclick={() => toggleStatus(item.status)}
|
||||||
<span class="flex items-center gap-1.5">
|
class="flex items-center gap-1.5 transition-opacity cursor-pointer select-none
|
||||||
<span class="inline-block size-2.5 rounded-sm" style="background:#d4752a; opacity:.7"></span>
|
{hiddenStatuses.includes(item.status) ? 'opacity-35' : 'opacity-100'}"
|
||||||
{t(T.windkarte_legend_entwurf_2_voraussichtlich)}
|
title={hiddenStatuses.includes(item.status) ? 'Einblenden' : 'Ausblenden'}
|
||||||
</span>
|
>
|
||||||
|
<span class="inline-block size-2.5 rounded-sm shrink-0" style="background:{item.color}; opacity:.7"></span>
|
||||||
|
<span class="{hiddenStatuses.includes(item.status) ? 'line-through' : ''}">{item.label}</span>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
<span class="flex items-center gap-x-3 gap-y-1 flex-wrap text-stein-300">
|
<span class="flex items-center gap-x-3 gap-y-1 flex-wrap text-stein-300">
|
||||||
<span class="text-stein-400">{t(T.windkarte_legend_distances)}</span>
|
<span class="text-stein-400">{t(T.windkarte_legend_distances)}</span>
|
||||||
{#each [{ color: "#e35651", label: "200 m" }, { color: "#b08a52", label: "600 m" }, { color: "#436e85", label: "1 km" }] as ring}
|
{#each [{ color: "#e35651", label: "200 m" }, { color: "#b08a52", label: "600 m" }, { color: "#436e85", label: "1 km" }] as ring}
|
||||||
|
|||||||
Reference in New Issue
Block a user