diff options
Diffstat (limited to 'src/components/ParkMap.astro')
| -rw-r--r-- | src/components/ParkMap.astro | 73 |
1 files changed, 64 insertions, 9 deletions
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 `<div class="park-popup"><strong>${name}</strong>${owner ? `<span class="park-popup-owner">${escapePopup(owner)}</span>` : ""}${addr || area || type ? `<div class="park-popup-meta">${[addr, area, type].filter(Boolean).join(" ・ ")}</div>` : ""}${detailHtml}<div class="park-popup-links"><a href="${maps}" target="_blank" rel="noopener">🌏GMap</a><a href="${route}" target="_blank" rel="noopener">🚶経路</a></div></div>`; + return `<div class="park-popup"><strong>${name}</strong>${owner ? `<span class="park-popup-owner">${escapePopup(owner)}</span>` : ""}${addr || area || type ? `<div class="park-popup-meta">${[addr, area, type].filter(Boolean).join(" ・ ")}</div>` : ""}${detailHtml}<div class="park-popup-links"><a href="${maps}" target="_blank" rel="noopener">🌏Google</a><a href="${route}" target="_blank" rel="noopener">🚶経路</a></div></div>`; }; 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<HTMLElement>("[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<string>(); 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<string> | 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(); + } + } }); // 現在地表示(ボタン操作時のみ取得) |
