aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/components/ParkMap.astro
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-11-06 19:22:18 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-11-06 19:22:18 +0900
commit3df9fffd0e927f92dffe8b986d1ab8c61d4b6484 (patch)
tree532b2ab8489da60117749b37b56a77a4e387492a /src/components/ParkMap.astro
parent0c0c5de8c6bc2e06d0749188a9717475e1df60aa (diff)
parks: 公園を緑色で点滅させ、地図のリンクを2つに分ける
通常時は公園を緑色で点滅、絞り込み時は明るい緑で強調。近隣公園も同じ緑のスタイルにした。選択バーに「Googleマップ」と「徒歩の経路」を並べた。施設アイコンのズームを遊具と同じ17に揃え、消火栓・防火水槽はチェック時のみ表示する。
Diffstat (limited to 'src/components/ParkMap.astro')
-rw-r--r--src/components/ParkMap.astro128
1 files changed, 89 insertions, 39 deletions
diff --git a/src/components/ParkMap.astro b/src/components/ParkMap.astro
index a185fe3..6c10d93 100644
--- a/src/components/ParkMap.astro
+++ b/src/components/ParkMap.astro
@@ -101,9 +101,12 @@
background: #f1f5f9;
}
:global(.leaflet-overlay-pane path.park-selected) {
- filter: drop-shadow(0 0 6px rgba(230, 81, 0, 0.95));
+ filter: drop-shadow(0 0 6px rgba(27, 94, 32, 0.95));
animation: park-selected-pulse 1.2s ease-in-out infinite;
}
+ :global(.leaflet-overlay-pane path.park-blink) {
+ animation: park-blink-pulse 2.6s ease-in-out infinite;
+ }
@keyframes park-selected-pulse {
0%,
100% {
@@ -115,11 +118,26 @@
stroke-opacity: 0.35;
}
}
+ @keyframes park-blink-pulse {
+ 0%,
+ 100% {
+ fill-opacity: 0.45;
+ }
+ 50% {
+ fill-opacity: 0.12;
+ }
+ }
@media (prefers-reduced-motion: reduce) {
- :global(.leaflet-overlay-pane path.park-selected) {
+ :global(.leaflet-overlay-pane path.park-selected),
+ :global(.leaflet-overlay-pane path.park-blink) {
animation: none;
}
}
+ /* 消火栓・防火水槽はチェックオンのときだけ表示する */
+ :global(body:not(.show-fire) .park-fac-tank),
+ :global(body:not(.show-fire) .park-fac-hydrant) {
+ display: none;
+ }
.park-map-legend {
display: flex;
@@ -483,63 +501,70 @@
import parks from "@/data/kodaira-parks.json";
const MATCHED_STYLE = {
- color: "#b71c1c",
+ color: "#2e7d32",
weight: 2,
- fillColor: "#e53935",
- fillOpacity: 0.45,
+ fillColor: "#66bb6a",
+ fillOpacity: 0.35,
};
const UNMATCHED_STYLE = {
- color: "#ef5350",
+ color: "#a5d6a7",
weight: 1.2,
- fillColor: "#ffcdd2",
- fillOpacity: 0.3,
+ fillColor: "#c8e6c9",
+ fillOpacity: 0.25,
};
const DIM_STYLE = {
- color: "#ef9a9a",
+ color: "#c8e6c9",
weight: 0.8,
- fillColor: "#ffebee",
- fillOpacity: 0.03,
+ fillColor: "#e8f5e9",
+ fillOpacity: 0.05,
opacity: 0.2,
};
const SELECTED_STYLE = {
- color: "#e65100",
- weight: 5,
- fillColor: "#ffd54f",
- fillOpacity: 0.8,
- };
-
- // 選択中の公園を強調するためのクラス(グロー表示)
- const markSelected = (lyr: any, selected: boolean) => {
- const element = lyr?.getElement?.();
- if (element && element.classList) {
- element.classList.toggle("park-selected", selected);
- }
+ color: "#1b5e20",
+ weight: 4,
+ fillColor: "#69f0ae",
+ fillOpacity: 0.75,
};
const NEARBY_STYLE = {
- color: "#1565c0",
- weight: 1.5,
- fillColor: "#42a5f5",
- fillOpacity: 0.25,
+ color: "#2e7d32",
+ weight: 2,
+ fillColor: "#66bb6a",
+ fillOpacity: 0.35,
};
const NEARBY_POINT_STYLE = {
radius: 7,
- color: "#0d47a1",
+ color: "#1b5e20",
weight: 2,
- fillColor: "#42a5f5",
+ fillColor: "#66bb6a",
fillOpacity: 0.85,
};
const NEARBY_SELECTED_STYLE = {
- color: "#0d47a1",
- weight: 3,
- fillColor: "#1565c0",
- fillOpacity: 0.55,
+ color: "#1b5e20",
+ weight: 4,
+ fillColor: "#69f0ae",
+ fillOpacity: 0.75,
};
const NEARBY_DIM_STYLE = {
- color: "#90caf9",
+ color: "#c8e6c9",
weight: 0.8,
- fillColor: "#bbdefb",
+ fillColor: "#e8f5e9",
fillOpacity: 0.05,
- opacity: 0.3,
+ opacity: 0.2,
+ };
+
+ // 選択中の公園のグロー表示
+ const markSelected = (lyr: any, selected: boolean) => {
+ const element = lyr?.getElement?.();
+ if (element && element.classList) {
+ element.classList.toggle("park-selected", selected);
+ }
+ };
+ // フィルタがないときの位置点滅
+ const markBlink = (lyr: any, on: boolean) => {
+ const element = lyr?.getElement?.();
+ if (element && element.classList) {
+ element.classList.toggle("park-blink", on);
+ }
};
const el = document.getElementById("park-map");
@@ -756,6 +781,15 @@
new FullscreenControl({ position: "topright" }).addTo(map);
const layersByName = new Map<string, any>();
+
+ // 消火栓・防火水槽はチェックオンのときだけ表示する
+ const fireToggle = document.querySelector<HTMLInputElement>("[data-show-fire]");
+ if (fireToggle) {
+ const applyFire = () =>
+ document.body.classList.toggle("show-fire", fireToggle.checked);
+ fireToggle.addEventListener("change", applyFire);
+ applyFire();
+ }
const allLayers: any[] = [];
type NearbyEntry = { name: string; layer: any; city: string; key: string };
const nearbyEntries: NearbyEntry[] = [];
@@ -797,6 +831,7 @@
let selectedBar: HTMLElement | null = null;
let selectedNameEl: HTMLElement | null = null;
let selectedMapsLink: HTMLAnchorElement | null = null;
+ let selectedRouteLink: HTMLAnchorElement | null = null;
let selectedTableLink: HTMLAnchorElement | null = null;
let selectedNoteEl: HTMLElement | null = null;
let selectedOwnerEl: HTMLElement | null = null;
@@ -827,7 +862,12 @@
rec?.["緯度"] && rec?.["経度"]
? `${rec["緯度"]},${rec["経度"]}`
: query;
- selectedMapsLink.href = `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(destination)}`;
+ selectedMapsLink.href =
+ rec?.["地図URL"] ||
+ `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`;
+ if (selectedRouteLink) {
+ selectedRouteLink.href = `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(destination)}&travelmode=walking`;
+ }
selectedTableLink.dataset.parkRow = encodeURIComponent(ourName);
selectedTableLink.hidden = !listed;
if (selectedNoteEl) selectedNoteEl.hidden = listed;
@@ -846,11 +886,13 @@
'<span class="park-map-selected-name"></span>' +
'<span class="park-map-selected-owner" hidden></span>' +
'<span class="park-map-selected-note" hidden>一覧にない緑地・公園</span>' +
- '<a data-park-maps-link href="#" target="_blank" rel="noopener">現在地から経路</a>' +
+ '<a data-park-maps-link href="#" target="_blank" rel="noopener">Googleマップ</a>' +
+ '<a data-park-route-link href="#" target="_blank" rel="noopener">徒歩の経路</a>' +
'<a data-park-table-link href="#">一覧で見る</a>';
selectedBar = box;
selectedNameEl = box.querySelector<HTMLElement>(".park-map-selected-name");
selectedMapsLink = box.querySelector<HTMLAnchorElement>("[data-park-maps-link]");
+ selectedRouteLink = box.querySelector<HTMLAnchorElement>("[data-park-route-link]");
selectedTableLink = box.querySelector<HTMLAnchorElement>("[data-park-table-link]");
selectedNoteEl = box.querySelector<HTMLElement>(".park-map-selected-note");
selectedOwnerEl = box.querySelector<HTMLElement>(".park-map-selected-owner");
@@ -1182,7 +1224,7 @@
};
const updateFacilities = () => {
- if (map.getZoom() >= 16) {
+ if (map.getZoom() >= 17) {
if (!map.hasLayer(facilityLayer)) facilityLayer.addTo(map);
} else if (map.hasLayer(facilityLayer)) {
map.removeLayer(facilityLayer);
@@ -1224,16 +1266,19 @@
if (parkName === name) {
lyr.setStyle(SELECTED_STYLE);
markSelected(lyr, true);
+ markBlink(lyr, false);
lyr.bringToFront?.();
} else {
lyr.setStyle(parkName ? DIM_STYLE : UNMATCHED_STYLE);
markSelected(lyr, false);
+ markBlink(lyr, false);
}
});
nearbyEntries.forEach(({ name: nearbyName, layer: lyr }) => {
const selected = nearbyName === name;
lyr.setStyle(selected ? NEARBY_SELECTED_STYLE : NEARBY_DIM_STYLE);
markSelected(lyr, selected);
+ markBlink(lyr, false);
if (selected) lyr.bringToFront?.();
});
};
@@ -1314,10 +1359,12 @@
if (name && names.has(name)) {
lyr.setStyle(SELECTED_STYLE);
markSelected(lyr, true);
+ markBlink(lyr, false);
lyr.bringToFront?.();
} else {
lyr.setStyle(name ? MATCHED_STYLE : UNMATCHED_STYLE);
markSelected(lyr, false);
+ markBlink(lyr, false);
}
});
nearbyEntries.forEach(({ name, layer: lyr }) => {
@@ -1338,15 +1385,18 @@
if (!active) {
lyr.setStyle(name ? MATCHED_STYLE : UNMATCHED_STYLE);
markSelected(lyr, false);
+ markBlink(lyr, Boolean(name));
return;
}
if (name && names.has(name)) {
lyr.setStyle(SELECTED_STYLE);
markSelected(lyr, true);
+ markBlink(lyr, false);
lyr.bringToFront?.();
} else {
lyr.setStyle(DIM_STYLE);
markSelected(lyr, false);
+ markBlink(lyr, false);
}
});