diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-11-03 23:57:23 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-11-03 23:57:23 +0900 |
| commit | e167f560415238a682e60461d779580744f1faee (patch) | |
| tree | dff2cd36c45b21bf0c69eff4b71880f1d3f1fabf | |
| parent | b9151a737c7697f3e6b58d9e22e5249adbf8f261 (diff) | |
parks: 選択中のポリゴンを点滅させ、フィルタ時のアイコンを絞る
選択中の公園を点滅(塗り・枠の透明度をアニメーション)させた。フィルタ中や公園フォーカス時は、該当しない公園の設備・遊具アイコンを隠す。
| -rw-r--r-- | src/components/ParkMap.astro | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/src/components/ParkMap.astro b/src/components/ParkMap.astro index 3cccc7c..47dae97 100644 --- a/src/components/ParkMap.astro +++ b/src/components/ParkMap.astro @@ -62,7 +62,24 @@ background: #f1f5f9; } :global(.leaflet-overlay-pane path.park-selected) { - filter: drop-shadow(0 0 5px rgba(230, 81, 0, 0.95)); + filter: drop-shadow(0 0 6px rgba(230, 81, 0, 0.95)); + animation: park-selected-pulse 1.2s ease-in-out infinite; + } + @keyframes park-selected-pulse { + 0%, + 100% { + fill-opacity: 0.85; + stroke-opacity: 1; + } + 50% { + fill-opacity: 0.2; + stroke-opacity: 0.35; + } + } + @media (prefers-reduced-motion: reduce) { + :global(.leaflet-overlay-pane path.park-selected) { + animation: none; + } } .park-map-legend { @@ -909,6 +926,8 @@ // 拡大時だけ表示する設備アイコン(トイレ・水飲み場) // 一覧と一致した公園のポリゴン内にだけ表示する。 const facilityLayer = L.layerGroup(); + const facilityMarkersByName = new Map<string, any[]>(); + const playMarkersByName = new Map<string, any[]>(); layersByName.forEach((lyr, name) => { const p = parkDataByName.get(name); if (!p) return; @@ -947,7 +966,7 @@ } if (!icons.length) return; const center = centerOfLayer(lyr); - L.marker([center.lat, center.lng], { + const marker = L.marker([center.lat, center.lng], { icon: L.divIcon({ className: "park-fac-markers", html: `<span class="park-fac-list">${icons.join("")}</span>`, @@ -957,6 +976,9 @@ riseOnHover: false, interactive: false, }).addTo(facilityLayer); + const list = facilityMarkersByName.get(name) || []; + list.push(marker); + facilityMarkersByName.set(name, list); }); // 拡大時だけ表示する遊具アイコン。 @@ -1006,7 +1028,7 @@ } if (!icons.length) return; const center = centerOfLayer(lyr); - L.marker([center.lat, center.lng], { + const marker = L.marker([center.lat, center.lng], { icon: L.divIcon({ className: "park-play-markers", html: `<span class="park-play-list">${icons.join("")}</span>`, @@ -1016,8 +1038,27 @@ riseOnHover: false, interactive: false, }).addTo(playLayer); + const list = playMarkersByName.get(name) || []; + list.push(marker); + playMarkersByName.set(name, list); }); + // フィルタ中は、該当しない公園の設備・遊具アイコンを隠す + const applyIconFilter = (names: Set<string> | null) => { + const toggle = (markersByName: Map<string, any[]>, layer: any) => { + markersByName.forEach((markers, name) => { + const show = !names || names.has(name); + markers.forEach((marker) => { + const has = layer.hasLayer(marker); + if (show && !has) layer.addLayer(marker); + else if (!show && has) layer.removeLayer(marker); + }); + }); + }; + toggle(facilityMarkersByName, facilityLayer); + toggle(playMarkersByName, playLayer); + }; + const updateFacilities = () => { if (map.getZoom() >= 16) { if (!map.hasLayer(facilityLayer)) facilityLayer.addTo(map); @@ -1055,6 +1096,7 @@ // 1つの公園だけを強調表示にする(ほかは薄くする) const highlightOnly = (name: string) => { + applyIconFilter(new Set([name])); allLayers.forEach((lyr) => { const parkName = lyr._parkName || ""; if (parkName === name) { @@ -1165,6 +1207,7 @@ facilityMarkers.forEach(({ layer }) => { setFacilityOpacity(layer, true); }); + applyIconFilter(new Set(names)); return; } @@ -1205,6 +1248,7 @@ facilityMarkers.forEach(({ name, layer }) => { setFacilityOpacity(layer, !active || names.has(name)); }); + applyIconFilter(active ? new Set(names) : null); }); // 現在地表示(ボタン操作時のみ取得) |
