diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/ScheduleMap.astro | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/src/components/ScheduleMap.astro b/src/components/ScheduleMap.astro index bf84dd7..82e37bf 100644 --- a/src/components/ScheduleMap.astro +++ b/src/components/ScheduleMap.astro @@ -1,6 +1,7 @@ --- // カレンダーで選んだ日に開催される予定の会場を地図に表示する。 // 会場名から緯度・経度を引くため、公共施設のデータと、イベント会場の追加データを使う。 +// 地図の描画ライブラリ(Leaflet)は重いので、地図が画面に近づくまで読み込まない。 --- <div class="schedule-map-block"> @@ -10,8 +11,8 @@ </div> <script> - import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; + import type { Circle, LatLngTuple, LayerGroup, Marker } from 'leaflet'; import facilities from '@/data/kodaira-facilities.json'; import extraVenues from '@/data/kodaira-event-venues.json'; import boundary from '@/data/kodaira-boundary.json'; @@ -93,8 +94,9 @@ const el = document.getElementById('schedule-map'); const noteEl = document.getElementById('schedule-map-note'); - if (el && noteEl && !el.dataset.initialized) { - el.dataset.initialized = '1'; + async function initMap(el: HTMLElement, noteEl: HTMLElement) { + // Leaflet はこの関数が呼ばれたときに初めて読み込む(別チャンクになる)。 + const L = (await import('leaflet')).default; const map = L.map(el, { scrollWheelZoom: false, @@ -143,9 +145,9 @@ else map.fitBounds(currentBounds, { padding: [40, 40], maxZoom: 16 }); }; - let currentBounds: L.LatLngTuple[] = []; + let currentBounds: LatLngTuple[] = []; - let markers: L.LayerGroup | null = null; + let markers: LayerGroup | null = null; // 現在地表示。位置情報はボタンを押したときだけ取得する。 const locateStatusEl = document.getElementById('schedule-map-locate-status'); @@ -160,8 +162,8 @@ const ACTIVE_ICON = '<span aria-hidden="true"><svg viewBox="0 0 24 24" width="20" height="20"><circle cx="12" cy="12" r="2.5" fill="currentColor"/><circle cx="12" cy="12" r="7" fill="none" stroke="currentColor" stroke-width="2"/></svg></span>'; - let locationMarker: L.Marker | null = null; - let accuracyCircle: L.Circle | null = null; + let locationMarker: Marker | null = null; + let accuracyCircle: Circle | null = null; let locateButton: HTMLButtonElement | null = null; const updateLocateButton = () => { @@ -329,7 +331,7 @@ return; } - const bounds: L.LatLngTuple[] = []; + const bounds: LatLngTuple[] = []; for (const { venue, items } of groups.values()) { bounds.push([venue.lat, venue.lon]); @@ -383,4 +385,18 @@ window.setTimeout(() => refreshMap(true), 300); window.addEventListener('resize', () => refreshMap(false)); } + + // 地図が画面に近づいてから Leaflet を読み込む(初期表示を軽くする)。 + if (el && noteEl && !el.dataset.initialized) { + const observer = new IntersectionObserver( + (entries, obs) => { + if (!entries.some((entry) => entry.isIntersecting)) return; + obs.disconnect(); + el.dataset.initialized = '1'; + void initMap(el, noteEl); + }, + { rootMargin: '300px 0px' } + ); + observer.observe(el); + } </script> |
