fesmap / pj
forked from Ray8/pj
Newer
Older
pj / map.js
document.addEventListener('DOMContentLoaded', () => {
  const map = L.map('map').setView([38.9175, 139.8353], 16);

  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
  }).addTo(map);

  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);
          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 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();
    return now >= start && now <= end;
  }

  fetch('snack.csv')
    .then(response => response.text())
    .then(text => {
      const rows = text.split('\n').filter(row => row.trim());
      const headers = rows[0].split(',').map(h => h.trim());

      for (let i = 1; i < rows.length; i++) {
        const values = rows[i].split(',').map(v => v.replace(/^"|"$/g, '').trim());
        const data = {};
        headers.forEach((key, index) => data[key] = values[index] || '');

        const lat = parseFloat(data.latitude);
        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';

        const customIcon = L.icon({
          iconUrl: iconPath,
          iconSize: [32, 32],
          iconAnchor: [16, 32],
          popupAnchor: [0, -32]
        });

        // ポップアップ用説明文
        const description = [data.description1, data.description2]
          .filter(Boolean)
          .map(d => d.trim())
          .join('<br>');

        const image1 = data.img1 && data.img1.trim() !== '' ? data.img1 : 'images/snacktitle.png';
        const image2 = data.img2 && data.img2.trim() !== '' ? data.img2 : 'images/snacktitle.png';

        const popupContent = `
	<div class="popup-content">
	<h3>${data.name.replace(/"$/, '')}</h3>
	<p>${description}</p>
	<img src="${image1}" width="106" height="73" style="cursor: pointer;" onclick="openModal('${image1}')" />
	<img src="${image2}" width="106" height="73" style="cursor: pointer;" onclick="openModal('${image2}')" />
	<button onclick="addToFavorites('${data.name}')">行きたいお店リストに追加</button>
	</div>
	`;
        L.marker([lat, lng], { icon: customIcon }).addTo(map)
          .bindPopup(popupContent);
      }
    })
    .catch(error => {
      console.error('CSV読み込みエラー:', error);
    });
});