diff --git a/map.js b/map.js index 833cad2..f1b7238 100644 --- a/map.js +++ b/map.js @@ -5,7 +5,88 @@ 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()]; + + 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); + if (date.getMonth() !== today.getMonth()) break; + if (date.getDay() === dayMap.indexOf(day)) count++; + if (date.getDate() === today.getDate() && count === nth) return true; + } + } + } + return false; + } + + function isOpenNow(desc2) { + if (!desc2) return false; + 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; + } + fetch('snack.csv') .then(response => response.text()) .then(text => { @@ -56,60 +137,49 @@ .catch(error => { console.error('CSV読み込みエラー:', error); }); - - // マーカーを追加し、ポップアップを設定 - snacks.forEach(snack => { - const markerIcon = L.icon({ - iconUrl: snack.icon || 'images/marker-icon.png', // 個別アイコンまたはデフォルトアイコン - iconSize: [32, 32], - iconAnchor: [16, 32], - popupAnchor: [0, -32] + + 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); + } }); - -const marker = L.marker([snack.lat, snack.lng], { icon: markerIcon }).addTo(map); - const popupContent = ` - -`; - - marker.bindPopup(popupContent); - markers.push({ marker, name: snack.name }); }); +}); -// リスト追加機能 -window.addToFavorites = function(name){ +window.addToFavorites = function(name) { const favorites = JSON.parse(localStorage.getItem('favorites') || '[]'); favorites.push({ name, addedAt: new Date().toISOString() }); localStorage.setItem('favorites', JSON.stringify(favorites)); alert(`${name}を行きたいお店リストに追加しました!`); - }; - -// モーダルの開閉操作 -window.openModal = function (imageSrc) { - const modal = document.getElementById('image-modal'); - const modalImage = document.getElementById('modal-image'); - modalImage.src = imageSrc; // クリックした画像のソースを設定 - modal.style.display = 'block'; // モーダルを表示 - }; +}; -window.closeModal = function () { - const modal = document.getElementById('image-modal'); - modal.style.display = 'none'; // モーダルを非表示 - }; +window.openModal = function(src) { + const modal = document.getElementById("modal"); + const modalImg = document.getElementById("modal-img"); + modal.style.display = "block"; + modalImg.src = src; +}; - // モーダル外をクリックして閉じる -window.onclick = function (event) { - const modal = document.getElementById('image-modal'); - if (event.target === modal) { - modal.style.display = 'none'; - } - }; -}); +window.closeModal = function() { + document.getElementById("modal").style.display = "none"; +};