From 93236c250c5b074d50418aefe8205d1e090b015d Mon Sep 17 00:00:00 2001
From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>
Date: Sat, 7 Nov 2026 14:15:45 +0900
Subject: park-icons.ts:
幼児用遊具と草地広場のアイコンを追加し、フィルタ時に地図をフォーカス
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 幼児用ブランコのアイコンを追加し、通常のブランコと区別
- 草地広場を地図上にも表示
- 「幼児用遊具」フィルタを追加
- フィルタ適用・解除時に該当範囲へフォーカス
- フキダシの「GMap」を「Google」に変更
---
src/components/ParkMap.astro | 73 ++++++++++++++++++++++++++++++++++-----
src/components/ParksFilters.astro | 4 +++
src/components/ParksTable.astro | 17 +++++----
src/data/park-icons.ts | 2 ++
4 files changed, 80 insertions(+), 16 deletions(-)
(limited to 'src')
diff --git a/src/components/ParkMap.astro b/src/components/ParkMap.astro
index 1d72565..3a208db 100644
--- a/src/components/ParkMap.astro
+++ b/src/components/ParkMap.astro
@@ -659,6 +659,12 @@
:global(.park-play-swing) {
color: #ef6c00;
}
+ :global(.park-play-toddler) {
+ color: #8e24aa;
+ }
+ :global(.park-play-grass) {
+ color: #2e7d32;
+ }
:global(.park-play-seesaw) {
color: #6d4c41;
}
@@ -1204,7 +1210,7 @@
rec?.["地図URL"] ||
`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`;
const route = `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(dest)}&travelmode=walking`;
- return `
`;
+ return ``;
};
const filterName = (name: string, scroll = false) => {
@@ -1652,6 +1658,7 @@
const PLAY_DEFS = [
{ tokens: ["ヒコーキ", "飛行機"], key: "airplane", title: PARK_ICONS.airplane.title, cls: "park-play-plane", icon: PARK_ICONS.airplane.svg },
{ tokens: ["ジャングル"], key: "climbing", title: PARK_ICONS.climbing.title, cls: "park-play-jungle", icon: PARK_ICONS.climbing.svg },
+ { tokens: [], key: "toddlerSwing", title: PARK_ICONS.toddlerSwing.title, cls: "park-play-toddler", icon: PARK_ICONS.toddlerSwing.svg },
{ tokens: ["ブランコ"], key: "swing", title: PARK_ICONS.swing.title, cls: "park-play-swing", icon: PARK_ICONS.swing.svg },
{ tokens: ["シーソー"], key: "seesaw", title: PARK_ICONS.teeter.title, cls: "park-play-seesaw", icon: PARK_ICONS.teeter.svg },
{ tokens: PLAY_SPRING_TOKENS, key: "spring", title: PARK_ICONS.spring.title, cls: "park-play-spring", icon: PARK_ICONS.spring.svg },
@@ -1661,6 +1668,7 @@
{ tokens: ["複合遊具"], key: "playground", title: PARK_ICONS.playground.title, cls: "park-play-complex", icon: PARK_ICONS.playground.svg },
{ tokens: [], key: "ball", title: PARK_ICONS.ball.title, cls: "park-play-ball", icon: PARK_ICONS.ball.svg },
{ tokens: [], key: "pond", title: PARK_ICONS.pond.title, cls: "park-play-pond", icon: PARK_ICONS.pond.svg },
+ { tokens: [], key: "grass", title: PARK_ICONS.grass.title, cls: "park-play-grass", icon: PARK_ICONS.grass.svg },
{ tokens: [], key: "special", title: PARK_ICONS.special.title, cls: "park-play-special", icon: PARK_ICONS.special.svg },
];
const playLegend = document.querySelector("[data-play-legend]");
@@ -1678,7 +1686,8 @@
const ballText = (p["ボール遊び"] || "").trim();
const hasBall = Boolean(ballText && ballText !== "禁止");
const hasPond = Boolean((p["じゃぶじゃぶ池"] || "").trim());
- if (!text && !hasBall && !hasPond) return;
+ const hasGrass = Boolean(String(p["草地広場"] || "").trim());
+ if (!text && !hasBall && !hasPond && !hasGrass) return;
const segments = text
.split(/[、,]/)
.map((s) => s.trim())
@@ -1693,19 +1702,32 @@
const isSpecial = segments.some(
(seg) => !PLAY_STANDARD_TOKENS.some((token) => seg.includes(token)),
);
+ // 幼児用ブランコと通常のブランコを区別する。
+ const hasToddlerSwing = segments.some(
+ (seg) => seg.includes("幼児") && seg.includes("ブランコ"),
+ );
+ const hasSwing = segments.some(
+ (seg) => seg.includes("ブランコ") && !seg.includes("幼児"),
+ );
const seen = new Set();
const icons: string[] = [];
for (const def of PLAY_DEFS) {
const matched =
def.key === "ball"
? hasBall
- : def.key === "pond"
- ? hasPond
- : def.key === "spring"
- ? isSpring
- : def.key === "special"
- ? isSpecial
- : def.tokens.some((token) => text.includes(token));
+ : def.key === "grass"
+ ? hasGrass
+ : def.key === "pond"
+ ? hasPond
+ : def.key === "toddlerSwing"
+ ? hasToddlerSwing
+ : def.key === "swing"
+ ? hasSwing
+ : def.key === "spring"
+ ? isSpring
+ : def.key === "special"
+ ? isSpecial
+ : def.tokens.some((token) => text.includes(token));
if (!matched) continue;
if (seen.has(def.key)) continue;
// ヒコーキジャングルはジャングルジムの一種なので、飛があればジは出さない。
@@ -1926,6 +1948,28 @@
focusPark(name, key);
});
+ // フィルタの対象(複数ならその範囲)に地図をフォーカスする。
+ let filterFocusTimer = 0;
+ const focusOnParks = (names: Set | null) => {
+ const bounds = L.latLngBounds([]);
+ const add = (lyr: any) => {
+ const b = lyr?.getBounds?.();
+ if (b && b.isValid()) bounds.extend(b);
+ };
+ if (names) {
+ allLayers.forEach((lyr) => {
+ if (names.has(lyr._parkName || "")) add(lyr);
+ });
+ nearbyEntries.forEach(({ name, layer }) => {
+ if (names.has(name)) add(layer);
+ });
+ } else {
+ allLayers.forEach(add);
+ }
+ if (!bounds.isValid()) return;
+ map.fitBounds(bounds, { padding: [40, 40], maxZoom: 16, animate: true });
+ };
+
// 選択中の公園を強調するためのクラス(グロー表示)
document.addEventListener("park:filter", (e: Event) => {
const detail = (e as CustomEvent).detail || {};
@@ -2009,6 +2053,17 @@
setFacilityOpacity(layer, !active || names.has(name));
});
applyIconFilter(active ? new Set(names) : null);
+
+ // フィルタの対象にフォーカスする(キーワード入力は少し待ってから)。
+ if (detail.focus) {
+ const run = () => focusOnParks(active ? names : null);
+ window.clearTimeout(filterFocusTimer);
+ if (detail.focus === "later") {
+ filterFocusTimer = window.setTimeout(run, 800);
+ } else {
+ run();
+ }
+ }
});
// 現在地表示(ボタン操作時のみ取得)
diff --git a/src/components/ParksFilters.astro b/src/components/ParksFilters.astro
index a41b00b..576c0ff 100644
--- a/src/components/ParksFilters.astro
+++ b/src/components/ParksFilters.astro
@@ -82,6 +82,10 @@ const facilityTypes = [
スイング遊具
+