diff --git a/map.js b/map.js index f1b7238..803c0ac 100644 --- a/map.js +++ b/map.js @@ -1,42 +1,31 @@ document.addEventListener('DOMContentLoaded', () => { const map = L.map('map').setView([38.9175, 139.8353], 16); - const markers = []; L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); - - // 現在地表示 - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition(position => { - const lat = position.coords.latitude; - const lng = position.coords.longitude; - L.marker([lat, lng], { - icon: L.icon({ - iconUrl: 'images/favicon-32x32-now.png', - iconSize: [24, 24], - iconAnchor: [12, 12] - }) - }).addTo(map).bindPopup('現在地'); - }); - } const dayMap = ['日', '月', '火', '水', '木', '金', '土']; const today = new Date(); const todayStr = dayMap[today.getDay()]; + // 複雑な定休日判定(例:第3日曜日、不定休含む) function isClosedToday(desc1) { if (!desc1) return false; + const closed = desc1.replace('定休日:', '').replace(/:/g, '').split(/[、,/・\/\s]/).filter(Boolean); + for (let entry of closed) { entry = entry.trim(); if (entry.includes('不定休')) return true; if (entry.includes(todayStr) && !entry.match(/第\d/)) return true; + const nthMatch = entry.match(/第(\d)(.)曜日/); if (nthMatch) { const nth = parseInt(nthMatch[1], 10); const day = nthMatch[2]; if (day !== todayStr) continue; + let count = 0; for (let d = 1; d <= 31; d++) { const date = new Date(today.getFullYear(), today.getMonth(), d); @@ -46,45 +35,26 @@ } } } + return false; } + // 営業時間判定 function isOpenNow(desc2) { if (!desc2) return false; + const match = desc2.match(/営業時間\s*[::]?\s*(\d{1,2}[::]\d{2})〜(\d{1,2}[::]\d{2})/); + if (!match) return false; + + const [ , startStr, endStr ] = match; + const to24 = t => t.replace(':', ':'); + const todayStr = new Date().toISOString().split('T')[0]; + + const start = new Date(`${todayStr}T${to24(startStr)}:00`); + let end = new Date(`${todayStr}T${to24(endStr)}:00`); + if (end <= start) end.setDate(end.getDate() + 1); + const now = new Date(); - const day = now.getDay(); - const time = now.getHours() * 60 + now.getMinutes(); - const segments = desc2.split(/\/|\\n|\\r\\n/); - for (let segment of segments) { - const match = segment.match(/(月|火|水|木|金|土|日)(?:~(月|火|水|木|金|土|日))?[::]?\s*(\d{1,2})[::](\d{2})\s*〜\s*(\d{1,2})[::](\d{2})/); - if (match) { - const [_, startDay, endDay, sh, sm, eh, em] = match; - const startMin = parseInt(sh) * 60 + parseInt(sm); - let endMin = parseInt(eh) * 60 + parseInt(em); - const dayIndex = { '日': 0, '月': 1, '火': 2, '水': 3, '木': 4, '金': 5, '土': 6 }; - let validDay = false; - if (!endDay) { - validDay = day === dayIndex[startDay]; - } else { - const startIdx = dayIndex[startDay]; - const endIdx = dayIndex[endDay]; - validDay = startIdx <= endIdx ? day >= startIdx && day <= endIdx : day >= startIdx || day <= endIdx; - } - if (!validDay) continue; - if (endMin <= startMin) endMin += 1440; - const currentTime = time < startMin ? time + 1440 : time; - if (currentTime >= startMin && currentTime <= endMin) return true; - } - const simple = segment.match(/(\d{1,2})[::](\d{2})\s*〜\s*(\d{1,2})[::](\d{2})/); - if (simple) { - const startMin = parseInt(simple[1]) * 60 + parseInt(simple[2]); - let endMin = parseInt(simple[3]) * 60 + parseInt(simple[4]); - if (endMin <= startMin) endMin += 1440; - const currentTime = time < startMin ? time + 1440 : time; - if (currentTime >= startMin && currentTime <= endMin) return true; - } - } - return false; + return now >= start && now <= end; } fetch('snack.csv') @@ -102,6 +72,7 @@ const lng = parseFloat(data.longitude); if (isNaN(lat) || isNaN(lng)) continue; + // 営業中判定 const isOpen = !isClosedToday(data.description1) && isOpenNow(data.description2); const iconPath = isOpen ? (data.icon || 'images/snack-icon.png') : 'images/favicon-door-32x32.png'; @@ -112,6 +83,7 @@ popupAnchor: [0, -32] }); + // ポップアップ用説明文 const description = [data.description1, data.description2, data.description3, data.mama] .filter(Boolean) .map(d => d.trim()) @@ -121,51 +93,24 @@ const image2 = data.img2 && data.img2.trim() !== '' ? data.img2 : 'images/snacktitle.png'; const popupContent = ` - `; - - const marker = L.marker([lat, lng], { icon: customIcon }).addTo(map).bindPopup(popupContent); - marker.isOpen = isOpen; - markers.push(marker); + + `; + L.marker([lat, lng], { icon: customIcon }).addTo(map) + .bindPopup(popupContent); } }) .catch(error => { console.error('CSV読み込みエラー:', error); }); - - const toggleBtn = document.createElement('button'); - toggleBtn.textContent = '営業中の店を表示'; - toggleBtn.style.position = 'absolute'; - toggleBtn.style.top = '10px'; - toggleBtn.style.right = '10px'; - toggleBtn.style.zIndex = 1000; - toggleBtn.style.padding = '10px 10px'; - toggleBtn.style.background = '#f3e8ff'; - toggleBtn.style.color = '#3e004f'; - toggleBtn.style.border = '1px solid #3e004f'; - toggleBtn.style.cursor = 'pointer'; - document.body.appendChild(toggleBtn); - - let showingOnlyOpen = false; - toggleBtn.addEventListener('click', () => { - showingOnlyOpen = !showingOnlyOpen; - toggleBtn.textContent = showingOnlyOpen ? '全ての店を表示' : '営業中の店を表示'; - markers.forEach(marker => { - if (showingOnlyOpen) { - if (marker.isOpen) marker.addTo(map); - else map.removeLayer(marker); - } else { - marker.addTo(map); - } - }); - }); }); +// 行きたいお店リスト保存 window.addToFavorites = function(name) { const favorites = JSON.parse(localStorage.getItem('favorites') || '[]'); favorites.push({ name, addedAt: new Date().toISOString() }); @@ -173,6 +118,7 @@ alert(`${name}を行きたいお店リストに追加しました!`); }; +// モーダル開く window.openModal = function(src) { const modal = document.getElementById("modal"); const modalImg = document.getElementById("modal-img"); @@ -180,6 +126,7 @@ modalImg.src = src; }; +// モーダル閉じる window.closeModal = function() { document.getElementById("modal").style.display = "none"; };