参考(地图)

<!-- 地图逻辑 -->

(function() {
    'use strict';

    // ========== 数据读取 ==========
    let travelData = [];
    try {
        const labelData = '<%= note.getLabelValue("travelData") || "" %>';
        if (labelData) {
            travelData = JSON.parse(labelData);
        } else {
            let contentData = `<%- content %>`;
            if (contentData.includes('<pre>')) {
                contentData = contentData.replace(/<\/?pre>/g, '').trim();
            }
            contentData = contentData.replace(/[\r\n\t]/g, '').trim();
            if (contentData && contentData.startsWith('[')) {
                travelData = JSON.parse(contentData);
            }
        }
        console.log('✅ 加载了', travelData.length, '个地点');
    } catch(e) {
        console.error('❌ 数据解析失败:', e);
    }

    // ========== 统计功能 ==========
    function calculateStats(data) {
        const countries = new Set();
        const provinces = new Set();
        const cities = new Set();

        data.forEach(place => {
            // 从 location 字段解析 (格式: "国家/省份/城市" 或 "省份/城市")
            if (place.location) {
                const parts = place.location.split('/').map(s => s.trim());
                if (parts.length === 3) {
                    countries.add(parts[0]);
                    provinces.add(parts[1]);
                    cities.add(parts[2]);
                } else if (parts.length === 2) {
                    provinces.add(parts[0]);
                    cities.add(parts[1]);
                    countries.add('中国'); // 默认
                }
            }

            // 备用:从 tags 中解析 (如果有 "国家:XXX", "省份:XXX", "城市:XXX" 格式的标签)
            if (place.tags) {
                place.tags.forEach(tag => {
                    if (tag.startsWith('国家:')) countries.add(tag.split(':')[1]);
                    if (tag.startsWith('省份:')) provinces.add(tag.split(':')[1]);
                    if (tag.startsWith('城市:')) cities.add(tag.split(':')[1]);
                });
            }
        });

        return {
            countries: countries.size,
            provinces: provinces.size,
            cities: cities.size
        };
    }

    const stats = calculateStats(travelData);

    if (travelData.length === 0) {
        document.getElementById('places-list').innerHTML =
            '<p style="text-align:center;color:#999;padding:30px 20px;">暂无足迹数据<br><small>请在笔记中添加 JSON 格式的地点信息</small></p>';
    }

    // ========== DOM 元素 ==========
    const mapEl = document.getElementById('travel-map');
    const sidebar = document.getElementById('travel-sidebar');
    const toggleBtn = document.getElementById('toggle-sidebar-btn');
    const closeBtn = document.getElementById('close-sidebar-btn');
    const placesList = document.getElementById('places-list');
    const searchInput = document.getElementById('place-search');
    const placesCountBadge = document.getElementById('places-count');
    const modal = document.getElementById('place-modal');
    const modalBody = document.getElementById('modal-body');
    const modalClose = document.querySelector('.modal-close');

    // 统计数字元素
    const statCountries = document.getElementById('stat-countries');
    const statProvinces = document.getElementById('stat-provinces');
    const statCities = document.getElementById('stat-cities');

    // 更新统计数字 (带动画)
    function animateCount(element, target) {
        let current = 0;
        const increment = target / 30;
        const timer = setInterval(() => {
            current += increment;
            if (current >= target) {
                element.textContent = target;
                clearInterval(timer);
            } else {
                element.textContent = Math.floor(current);
            }
        }, 30);
    }

    animateCount(statCountries, stats.countries);
    animateCount(statProvinces, stats.provinces);
    animateCount(statCities, stats.cities);

    // ========== 地图初始化 ==========
    const map = L.map('travel-map').setView([35.0, 110.0], 4);

    L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
        subdomains: ['1', '2', '3', '4'],
        attribution: '&copy; 高德地图'
    }).addTo(map);

    let markers = [];

    // ========== 侧边栏控制 ==========
    toggleBtn.addEventListener('click', () => {
        sidebar.classList.toggle('collapsed');
    });

    closeBtn.addEventListener('click', () => {
        sidebar.classList.add('collapsed');
    });

    // ========== 渲染列表 ==========
    function renderPlacesList(places = travelData) {
        placesCountBadge.textContent = places.length;
        placesList.innerHTML = '';

        if (places.length === 0) {
            placesList.innerHTML = '<p style="text-align:center;color:#999;padding:20px;">无匹配结果</p>';
            return;
        }

        places.forEach(place => {
            const item = document.createElement('div');
            item.className = 'place-item';
            item.dataset.id = place.id;

            item.innerHTML = `
                <div class="place-title">${place.title}</div>
                <div class="place-date">📅 ${place.date}</div>
                ${place.tags ? `<div class="place-tags">${place.tags.map(t => `<span class="place-tag">${t}</span>`).join('')}</div>` : ''}
            `;

            item.addEventListener('click', () => {
                showPlaceDetail(place);
                document.querySelectorAll('.place-item').forEach(i => i.classList.remove('active'));
                item.classList.add('active');
                map.flyTo([place.lat, place.lng], 12, { duration: 1.5 });
            });

            placesList.appendChild(item);
        });
    }

    // ========== 添加标记 ==========
    function addMarkers() {
        markers.forEach(m => map.removeLayer(m));
        markers = [];

        travelData.forEach(place => {
            const marker = L.marker([place.lat, place.lng]);
            marker.bindPopup(`
                <div style="min-width:180px;">
                    <h3 style="margin:0 0 8px 0;font-size:1.1em;">${place.title}</h3>
                    <p style="margin:5px 0;font-size:0.9em;color:#666;">📅 ${place.date}</p>
                </div>
            `);
            marker.on('click', () => {
                showPlaceDetail(place);
                document.querySelectorAll('.place-item').forEach(item => {
                    if (item.dataset.id === place.id) {
                        item.classList.add('active');
                        item.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
                    } else {
                        item.classList.remove('active');
                    }
                });
                sidebar.classList.remove('collapsed');
            });
            marker.addTo(map);
            markers.push(marker);
        });

        if (markers.length > 0) {
            const group = L.featureGroup(markers);
            map.fitBounds(group.getBounds().pad(0.1));
        }
    }

    // ========== 显示详情 ==========
    function showPlaceDetail(place) {
        modalBody.innerHTML = `
            <h2 class="modal-title">${place.title}</h2>
            <div class="modal-meta">
                <span>📅 ${place.date}</span>
                <span>📍 ${place.lat.toFixed(4)}, ${place.lng.toFixed(4)}</span>
                ${place.location ? `<span>🌏 ${place.location}</span>` : ''}
            </div>
            ${place.description ? `<div class="modal-description">${place.description}</div>` : ''}
            ${place.tags ? `<div style="margin-bottom:25px;">${place.tags.map(t => `<span class="place-tag" style="background:#5986D1;color:white;padding:6px 14px;margin-right:8px;font-size:0.9em;">${t}</span>`).join('')}</div>` : ''}
            ${place.photos ? `<div class="modal-photos">${place.photos.map(p => `<img src="${p}" class="modal-photo" data-fancybox="gallery-${place.id}" alt="${place.title}">`).join('')}</div>` : ''}
        `;
        modal.classList.add('show');

        if (typeof Fancybox !== 'undefined' && place.photos) {
            Fancybox.bind(`[data-fancybox="gallery-${place.id}"]`, { Hash: false });
        }
    }

    // ========== 搜索 ==========
    searchInput.addEventListener('input', (e) => {
        const term = e.target.value.toLowerCase();
        const filtered = term ? travelData.filter(p =>
            p.title.toLowerCase().includes(term) ||
            (p.description && p.description.toLowerCase().includes(term)) ||
            (p.location && p.location.toLowerCase().includes(term)) ||
            (p.tags && p.tags.some(t => t.toLowerCase().includes(term)))
        ) : travelData;
        renderPlacesList(filtered);
    });

    // ========== 关闭弹窗 ==========
    modalClose.addEventListener('click', () => modal.classList.remove('show'));
    modal.addEventListener('click', (e) => {
        if (e.target === modal) modal.classList.remove('show');
    });

    // ========== 初始化 ==========
    renderPlacesList();
    addMarkers();

    console.log('🗺️ 地图初始化完成 | 统计:', stats);
})();


项目分区导航:⬅️ 02-参考(图谱) | 03-参考(地图) | ➡️ 04-古建筑