New Chat
Plugins Scheduled Tasks
  • Get App
  • About Us
    • Visit Moonshot AI
    • Kimi Platform
    • Features
    • Terms of Service
    • Privacy Policy
  • Language
  • Get Help

思念地图右侧

快过年了,我想爸爸妈妈了,我想制作一个中国地图,标出我与妈妈的距离,然后使用飞线链接两个点,地图使用Echarts的地图组件,然后再加上一段话,表达我对爸爸妈妈的思念,结果输出为一个html页面
可定制双城距离思念交互地图
用户想在过年时制作一个表达思念父母的HTML页面,需求包括:
  1. 使用中国地图(ECharts地图组件)
  2. 标记两个点(用户位置和妈妈位置)
  3. 使用飞线连接两个点
  4. 添加一段表达思念的文字
  5. 输出为单个HTML文件
这是一个情感化的数据可视化项目,需要:
  • 使用ECharts(特别是map组件和lines系列用于飞线)
  • 需要中国地图的GeoJSON数据或直接使用ECharts内置地图
  • 需要模拟两个城市的位置(用户所在地和妈妈所在地)
  • 需要设计温馨的UI风格(春节/思念主题)
注意:ECharts自5.0版本后不再内置地图数据,需要引入外部GeoJSON或使用注册好的地图。我可以使用CDN引入中国地图数据。
让我构建一个温馨的单页面应用:
  1. 深色背景(夜空感),配合金色/红色(春节氛围)
  2. 中央是ECharts中国地图
  3. 两个闪烁的标记点(家和我的位置)
  4. 流动的飞线连接
  5. 底部或侧边的思念文字
  6. 添加一些粒子效果或飘落效果(雪花或灯笼)增强氛围
由于用户没有提供具体城市,我需要:
  • 让用户可以选择或输入两个城市
  • 或者预设两个代表性城市(比如北京和广州,一北一南,距离感明显)
  • 或者随机生成但可编辑
我觉得最好的方式是预设两个城市(比如"我"在上海,"妈妈"在成都),但提供输入框让用户修改,这样即开即用又能个性化。
技术实现:
  • 使用ECharts 5.x
  • 需要中国地图GeoJSON,可以用阿里DataV的地图服务
  • 使用effectScatter做闪烁点
  • 使用lines做飞线动画
  • 添加CSS动画做氛围效果
情感文案需要温馨感人,突出距离和思念,以及春节团圆的期盼。
界面布局:
  • 全屏地图
  • 左上角标题
  • 右下角或底部中央文案卡片
  • 简单的控制面板让用户修改城市(可选,为了美观可以做成悬浮输入框)
让我开始编写代码...
我来为你制作一个充满温情的春节思念地图。这个页面将使用 ECharts 展示中国地图,用流动的飞线连接你和妈妈所在的城市,并配上温暖的思念文字。
HTML
Preview
Copy
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>思念的距离 - 献给爸爸妈妈</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
            background: linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #1e3c72 100%);
            overflow: hidden;
            position: relative;
            height: 100vh;
        }

        /* 飘落的花瓣/雪花效果 */
        .petal {
            position: absolute;
            background: rgba(255, 215, 0, 0.6);
            border-radius: 50% 0 50% 50%;
            animation: fall linear infinite;
            pointer-events: none;
        }

        @keyframes fall {
            to {
                transform: translateY(100vh) rotate(360deg);
            }
        }

        /* 地图容器 */
        #map-container {
            width: 100%;
            height: 100vh;
            position: relative;
            z-index: 1;
        }

        /* 标题 */
        .header {
            position: absolute;
            top: 30px;
            left: 50%;
            transform: translateX(-50%);
            text-align: center;
            z-index: 10;
            color: #ffd700;
            text-shadow: 0 2px 10px rgba(0,0,0,0.5);
        }

        .header h1 {
            font-size: 2.5em;
            font-weight: 300;
            letter-spacing: 0.2em;
            margin-bottom: 10px;
            background: linear-gradient(to right, #ffd700, #ffed4e, #ffd700);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-size: 200% auto;
            animation: shine 3s linear infinite;
        }

        @keyframes shine {
            to {
                background-position: 200% center;
            }
        }

        .header .subtitle {
            font-size: 1.1em;
            color: rgba(255, 255, 255, 0.8);
            font-weight: 300;
        }

        /* 思念文字卡片 */
        .letter-card {
            position: absolute;
            bottom: 40px;
            left: 50%;
            transform: translateX(-50%);
            width: 90%;
            max-width: 600px;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            padding: 30px;
            border-radius: 20px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3), 
                        inset 0 0 0 1px rgba(255,255,255,0.5);
            z-index: 10;
            border-left: 5px solid #e74c3c;
            animation: float 6s ease-in-out infinite;
        }

        @keyframes float {
            0%, 100% { transform: translateX(-50%) translateY(0px); }
            50% { transform: translateX(-50%) translateY(-10px); }
        }

        .letter-card::before {
            content: '❝';
            position: absolute;
            top: -20px;
            left: 20px;
            font-size: 60px;
            color: #e74c3c;
            opacity: 0.3;
            font-family: serif;
        }

        .letter-content {
            color: #2c3e50;
            line-height: 1.8;
            font-size: 1.1em;
            text-align: justify;
            position: relative;
            z-index: 1;
        }

        .letter-content .highlight {
            color: #e74c3c;
            font-weight: bold;
        }

        .signature {
            text-align: right;
            margin-top: 15px;
            color: #7f8c8d;
            font-style: italic;
        }

        /* 距离显示 */
        .distance-badge {
            position: absolute;
            top: 120px;
            right: 40px;
            background: rgba(231, 76, 60, 0.9);
            color: white;
            padding: 15px 25px;
            border-radius: 30px;
            font-size: 1.2em;
            font-weight: bold;
            box-shadow: 0 4px 15px rgba(231, 76, 60, 0.4);
            z-index: 10;
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.05); }
        }

        /* 城市选择器 */
        .city-selector {
            position: absolute;
            top: 120px;
            left: 40px;
            background: rgba(255, 255, 255, 0.95);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.2);
            z-index: 10;
            width: 200px;
        }

        .city-selector h3 {
            color: #2c3e50;
            margin-bottom: 15px;
            font-size: 1em;
            border-bottom: 2px solid #e74c3c;
            padding-bottom: 5px;
        }

        .city-selector select {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-family: inherit;
            outline: none;
            transition: border-color 0.3s;
        }

        .city-selector select:focus {
            border-color: #e74c3c;
        }

        .city-selector label {
            display: block;
            margin-bottom: 5px;
            color: #7f8c8d;
            font-size: 0.9em;
        }

        /* 响应式 */
        @media (max-width: 768px) {
            .header h1 { font-size: 1.8em; }
            .letter-card { 
                bottom: 20px; 
                padding: 20px;
                font-size: 0.9em;
            }
            .city-selector {
                top: auto;
                bottom: 200px;
                left: 20px;
                width: calc(100% - 40px);
                max-width: 200px;
            }
            .distance-badge {
                top: 100px;
                right: 20px;
                font-size: 1em;
                padding: 10px 15px;
            }
        }
    </style>
</head>
<body>
    <!-- 飘落效果容器 -->
    <div id="petals-container"></div>

    <!-- 标题 -->
    <div class="header">
        <h1>思念的距离</h1>
        <div class="subtitle">无论多远,心永远在一起</div>
    </div>

    <!-- 距离显示 -->
    <div class="distance-badge" id="distance">距离:约 <span>0</span> 公里</div>

    <!-- 城市选择 -->
    <div class="city-selector">
        <h3>📍 设置位置</h3>
        <label>我的位置:</label>
        <select id="myCity">
            <option value=" Beijing|116.4074|39.9042">北京</option>
            <option value="Shanghai|121.4737|31.2304" selected>上海</option>
            <option value="Guangzhou|113.2644|23.1291">广州</option>
            <option value="Shenzhen|114.0579|22.5431">深圳</option>
            <option value="Chengdu|104.0668|30.5728">成都</option>
            <option value="Hangzhou|120.1551|30.2741">杭州</option>
            <option value="Wuhan|114.3054|30.5931">武汉</option>
            <option value="Xi'an|108.9398|34.3416">西安</option>
        </select>
        <label>妈妈的位置:</label>
        <select id="momCity">
            <option value="Beijing|116.4074|39.9042">北京</option>
            <option value="Shanghai|121.4737|31.2304">上海</option>
            <option value="Guangzhou|113.2644|23.1291">广州</option>
            <option value="Shenzhen|114.0579|22.5431">深圳</option>
            <option value="Chengdu|104.0668|30.5728" selected>成都</option>
            <option value="Hangzhou|120.1551|30.2741">杭州</option>
            <option value="Wuhan|114.3054|30.5931">武汉</option>
            <option value="Xi'an|108.9398|34.3416">西安</option>
        </select>
    </div>

    <!-- 地图 -->
    <div id="map-container"></div>

    <!-- 思念信件 -->
    <div class="letter-card">
        <div class="letter-content">
            亲爱的爸爸妈妈,<br><br>
            又是一年春节将至,地图上的这条飞线,连接着<span class="highlight">我所在的城市</span>与<span class="highlight">家乡的方向</span>。
            虽然相隔千里,但每一缕思念都顺着这条线飞向你们。<br><br>
            那些曾经的唠叨,如今成了最温暖的声音;那些日常的饭菜香,成了最怀念的味道。
            距离丈量的是空间,却量不尽我对你们的牵挂。<br><br>
            愿这条穿越山河的线,带去我的拥抱。等我回家,我们一起吃顿团圆饭。
        </div>
        <div class="signature">—— 想你们的孩子</div>
    </div>

    <script>
        // 创建飘落效果
        function createPetals() {
            const container = document.getElementById('petals-container');
            const petalCount = 30;
            
            for (let i = 0; i < petalCount; i++) {
                const petal = document.createElement('div');
                petal.className = 'petal';
                petal.style.left = Math.random() * 100 + '%';
                petal.style.width = (Math.random() * 10 + 5) + 'px';
                petal.style.height = (Math.random() * 10 + 5) + 'px';
                petal.style.animationDuration = (Math.random() * 10 + 10) + 's';
                petal.style.animationDelay = Math.random() * 10 + 's';
                petal.style.opacity = Math.random() * 0.5 + 0.3;
                container.appendChild(petal);
            }
        }
        createPetals();

        // 计算距离(简化的球面距离)
        function calculateDistance(lat1, lon1, lat2, lon2) {
            const R = 6371;
            const dLat = (lat2 - lat1) * Math.PI / 180;
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                    Math.sin(dLon/2) * Math.sin(dLon/2);
            const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            return Math.round(R * c);
        }

        // 初始化地图
        let myChart = null;
        
        async function initMap() {
            myChart = echarts.init(document.getElementById('map-container'));
            
            // 加载中国地图
            try {
                const response = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json');
                const chinaJson = await response.json();
                echarts.registerMap('china', chinaJson);
                
                updateMap();
            } catch (error) {
                console.error('地图加载失败:', error);
                document.getElementById('map-container').innerHTML = 
                    '<div style="color:white; text-align:center; padding-top:20%;">地图加载中,请稍候...</div>';
            }
        }

        function updateMap() {
            const mySelect = document.getElementById('myCity').value.split('|');
            const momSelect = document.getElementById('momCity').value.split('|');
            
            const myCity = {
                name: mySelect[0],
                value: [parseFloat(mySelect[1]), parseFloat(mySelect[2])]
            };
            const momCity = {
                name: momSelect[0],
                value: [parseFloat(momSelect[1]), parseFloat(momSelect[2])]
            };

            // 更新距离显示
            const dist = calculateDistance(myCity.value[1], myCity.value[0], momCity.value[1], momCity.value[0]);
            document.querySelector('#distance span').textContent = dist;

            const option = {
                backgroundColor: 'transparent',
                geo: {
                    map: 'china',
                    roam: true,
                    zoom: 1.2,
                    center: [105, 36],
                    label: {
                        emphasis: {
                            show: true,
                            color: '#fff'
                        }
                    },
                    itemStyle: {
                        normal: {
                            areaColor: 'rgba(255,255,255,0.1)',
                            borderColor: '#ffd700',
                            borderWidth: 1,
                            shadowColor: 'rgba(0, 0, 0, 0.5)',
                            shadowBlur: 10
                        },
                        emphasis: {
                            areaColor: 'rgba(255,215,0,0.3)'
                        }
                    }
                },
                series: [
                    // 我的位置
                    {
                        name: '我的位置',
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        data: [myCity],
                        symbolSize: 20,
                        showEffectOn: 'render',
                        rippleEffect: {
                            brushType: 'stroke',
                            scale: 4,
                            period: 4
                        },
                        label: {
                            show: true,
                            position: 'top',
                            formatter: '{b} (我)',
                            color: '#fff',
                            fontSize: 12,
                            fontWeight: 'bold',
                            backgroundColor: 'rgba(0,0,0,0.5)',
                            padding: [5, 10],
                            borderRadius: 4
                        },
                        itemStyle: {
                            color: '#3498db',
                            shadowBlur: 10,
                            shadowColor: '#3498db'
                        },
                        zlevel: 2
                    },
                    // 妈妈的位置
                    {
                        name: '妈妈的位置',
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        data: [momCity],
                        symbolSize: 20,
                        showEffectOn: 'render',
                        rippleEffect: {
                            brushType: 'stroke',
                            scale: 4,
                            period: 4
                        },
                        label: {
                            show: true,
                            position: 'top',
                            formatter: '{b} (妈妈)',
                            color: '#fff',
                            fontSize: 12,
                            fontWeight: 'bold',
                            backgroundColor: 'rgba(231, 76, 60, 0.8)',
                            padding: [5, 10],
                            borderRadius: 4
                        },
                        itemStyle: {
                            color: '#e74c3c',
                            shadowBlur: 10,
                            shadowColor: '#e74c3c'
                        },
                        zlevel: 2
                    },
                    // 飞线
                    {
                        name: '思念的线',
                        type: 'lines',
                        zlevel: 1,
                        effect: {
                            show: true,
                            period: 6,
                            trailLength: 0.7,
                            color: '#ffd700',
                            symbolSize: 3,
                            constantSpeed: 100
                        },
                        lineStyle: {
                            normal: {
                                color: '#ffd700',
                                width: 2,
                                curveness: 0.3,
                                opacity: 0.8,
                                type: 'solid'
                            }
                        },
                        data: [{
                            coords: [myCity.value, momCity.value],
                            lineStyle: {
                                color: {
                                    type: 'linear',
                                    x: 0, y: 0, x2: 1, y2: 0,
                                    colorStops: [
                                        {offset: 0, color: '#3498db'},
                                        {offset: 1, color: '#e74c3c'}
                                    ]
                                }
                            }
                        }]
                    }
                ]
            };

            myChart.setOption(option);
        }

        // 监听城市选择变化
        document.getElementById('myCity').addEventListener('change', updateMap);
        document.getElementById('momCity').addEventListener('change', updateMap);

        // 窗口大小改变时重绘
        window.addEventListener('resize', () => {
            if (myChart) myChart.resize();
        });

        // 初始化
        initMap();
    </script>
</body>
</html>
这个 HTML 页面包含以下温馨功能:
🗺️ 地图功能
  • 使用 ECharts 渲染中国地图,采用深蓝色夜空背景配合金色边框
  • 两个闪烁的动态标记点:蓝色代表"我",红色代表"妈妈"
  • 金色流动飞线连接两点,象征着思念的传递
✨ 视觉效果
  • 飘落的花瓣/灯笼动画,营造春节氛围
  • 距离实时计算显示(右上角红色徽章)
  • 悬浮的思念信笺卡片,带有微微的浮动动画
📝 情感表达
  • 内置了一段温馨的思念文字,表达了游子在春节对父母的牵挂
  • 文字卡片采用书信样式,带有引号和签名
🎛️ 交互功能
  • 左上角提供城市选择器,可以修改"我"和"妈妈"所在的城市
  • 选择后地图会自动更新飞线轨迹和距离数据
  • 支持地图缩放和拖动查看
你可以直接保存这个代码为 .html 文件打开使用。如果需要修改文字内容,可以在代码中找到 letter-content 类的 div 进行编辑。
文字把地图挡住了,放到右侧吧!
将信件卡片移至右侧并调整响应式布局
用户说文字把地图挡住了,想要把文字放到右侧。我需要查看之前的代码,发现信件卡片(letter-card)是放在底部的,确实可能会挡住地图。
我需要做以下修改:
  1. 将信件卡片从底部移到右侧
  2. 调整响应式布局,确保在移动设备上也能正常显示
  3. 可能需要调整地图的中心位置或缩放,以确保主要地图区域不被遮挡
  4. 保持整体美观和春节氛围
修改策略:
  • 将 .letter-card 的 bottom: 40px; left: 50%; transform: translateX(-50%); 改为右侧定位,比如 right: 40px; top: 50%; transform: translateY(-50%);
  • 调整宽度和高度,使其适合竖向放在右侧
  • 调整 max-width 和添加 max-height 防止超出屏幕
  • 修改浮动动画,从上下浮动改为左右浮动(或者保持上下但调整位置)
  • 调整响应式布局,在小屏幕上可能改为底部或左上角,避免遮挡
同时检查其他元素的位置:
  • 标题在顶部中央
  • 距离徽章在右上角(可能需要移到左上角避免与信件重叠,或者保持右上角但调整信件位置)
  • 城市选择器在左上角
更好的布局方案:
  • 右侧放信件卡片,竖向排列
  • 左上角放城市选择器
  • 右上角放距离显示
  • 标题保持在顶部中央
让我修改代码。
我来调整布局,将思念文字移到右侧,让地图完整展现:
HTML
Preview
Copy
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>思念的距离 - 献给爸爸妈妈</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
            background: linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #1e3c72 100%);
            overflow: hidden;
            position: relative;
            height: 100vh;
        }

        /* 飘落的花瓣/雪花效果 */
        .petal {
            position: absolute;
            background: rgba(255, 215, 0, 0.6);
            border-radius: 50% 0 50% 50%;
            animation: fall linear infinite;
            pointer-events: none;
        }

        @keyframes fall {
            to {
                transform: translateY(100vh) rotate(360deg);
            }
        }

        /* 地图容器 */
        #map-container {
            width: 100%;
            height: 100vh;
            position: relative;
            z-index: 1;
        }

        /* 标题 */
        .header {
            position: absolute;
            top: 30px;
            left: 50%;
            transform: translateX(-50%);
            text-align: center;
            z-index: 10;
            color: #ffd700;
            text-shadow: 0 2px 10px rgba(0,0,0,0.5);
            pointer-events: none;
        }

        .header h1 {
            font-size: 2.5em;
            font-weight: 300;
            letter-spacing: 0.2em;
            margin-bottom: 10px;
            background: linear-gradient(to right, #ffd700, #ffed4e, #ffd700);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-size: 200% auto;
            animation: shine 3s linear infinite;
        }

        @keyframes shine {
            to {
                background-position: 200% center;
            }
        }

        .header .subtitle {
            font-size: 1.1em;
            color: rgba(255, 255, 255, 0.8);
            font-weight: 300;
        }

        /* 思念文字卡片 - 移到右侧 */
        .letter-card {
            position: absolute;
            right: 40px;
            top: 50%;
            transform: translateY(-50%);
            width: 320px;
            max-height: 70vh;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            padding: 30px;
            border-radius: 20px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3), 
                        inset 0 0 0 1px rgba(255,255,255,0.5);
            z-index: 10;
            border-left: 5px solid #e74c3c;
            overflow-y: auto;
            scrollbar-width: thin;
            scrollbar-color: #e74c3c #f0f0f0;
        }

        /* 自定义滚动条 */
        .letter-card::-webkit-scrollbar {
            width: 6px;
        }
        .letter-card::-webkit-scrollbar-track {
            background: #f0f0f0;
            border-radius: 3px;
        }
        .letter-card::-webkit-scrollbar-thumb {
            background: #e74c3c;
            border-radius: 3px;
        }

        .letter-card::before {
            content: '❝';
            position: absolute;
            top: 10px;
            left: 20px;
            font-size: 50px;
            color: #e74c3c;
            opacity: 0.2;
            font-family: serif;
        }

        .letter-content {
            color: #2c3e50;
            line-height: 1.8;
            font-size: 1em;
            text-align: justify;
            position: relative;
            z-index: 1;
            margin-top: 20px;
        }

        .letter-content .highlight {
            color: #e74c3c;
            font-weight: bold;
        }

        .signature {
            text-align: right;
            margin-top: 20px;
            color: #7f8c8d;
            font-style: italic;
            font-size: 0.9em;
        }

        /* 距离显示 - 移到左上角 */
        .distance-badge {
            position: absolute;
            top: 120px;
            left: 40px;
            background: linear-gradient(135deg, #e74c3c, #c0392b);
            color: white;
            padding: 15px 25px;
            border-radius: 30px;
            font-size: 1.2em;
            font-weight: bold;
            box-shadow: 0 4px 15px rgba(231, 76, 60, 0.4);
            z-index: 10;
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.05); }
        }

        /* 城市选择器 - 保持左上但在距离下方 */
        .city-selector {
            position: absolute;
            top: 200px;
            left: 40px;
            background: rgba(255, 255, 255, 0.95);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.2);
            z-index: 10;
            width: 200px;
        }

        .city-selector h3 {
            color: #2c3e50;
            margin-bottom: 15px;
            font-size: 1em;
            border-bottom: 2px solid #e74c3c;
            padding-bottom: 5px;
        }

        .city-selector select {
            width: 100%;
            padding: 10px;
            margin-bottom: 12px;
            border: 1px solid #ddd;
            border-radius: 8px;
            font-family: inherit;
            outline: none;
            transition: all 0.3s;
            cursor: pointer;
        }

        .city-selector select:hover {
            border-color: #e74c3c;
        }

        .city-selector select:focus {
            border-color: #e74c3c;
            box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
        }

        .city-selector label {
            display: block;
            margin-bottom: 6px;
            color: #555;
            font-size: 0.9em;
            font-weight: 500;
        }

        /* 响应式调整 */
        @media (max-width: 968px) {
            .letter-card {
                right: 20px;
                width: 280px;
                padding: 20px;
            }
        }

        @media (max-width: 768px) {
            .header h1 { font-size: 1.8em; }
            .header { top: 20px; }
            
            /* 手机上改为底部横向滚动或折叠 */
            .letter-card {
                right: auto;
                left: 50%;
                top: auto;
                bottom: 20px;
                transform: translateX(-50%);
                width: 90%;
                max-height: 25vh;
                max-width: 500px;
            }
            
            .city-selector {
                top: 100px;
                left: 20px;
                width: calc(50% - 30px);
                min-width: 150px;
                padding: 15px;
            }
            
            .distance-badge {
                top: 100px;
                right: 20px;
                left: auto;
                font-size: 1em;
                padding: 10px 15px;
            }
        }

        @media (max-width: 480px) {
            .city-selector {
                width: calc(100% - 40px);
                top: 100px;
            }
            .distance-badge {
                top: 280px;
                right: auto;
                left: 20px;
            }
        }
    </style>
</head>
<body>
    <!-- 飘落的效果容器 -->
    <div id="petals-container"></div>

    <!-- 标题 -->
    <div class="header">
        <h1>思念的距离</h1>
        <div class="subtitle">无论多远,心永远在一起</div>
    </div>

    <!-- 距离显示 - 左上 -->
    <div class="distance-badge" id="distance">距离:约 <span>0</span> 公里</div>

    <!-- 城市选择 - 左中 -->
    <div class="city-selector">
        <h3>📍 设置位置</h3>
        <label>我的位置:</label>
        <select id="myCity">
            <option value="Beijing|116.4074|39.9042">北京</option>
            <option value="Shanghai|121.4737|31.2304" selected>上海</option>
            <option value="Guangzhou|113.2644|23.1291">广州</option>
            <option value="Shenzhen|114.0579|22.5431">深圳</option>
            <option value="Chengdu|104.0668|30.5728">成都</option>
            <option value="Hangzhou|120.1551|30.2741">杭州</option>
            <option value="Wuhan|114.3054|30.5931">武汉</option>
            <option value="Xi'an|108.9398|34.3416">西安</option>
            <option value="Chongqing|106.5516|29.5630">重庆</option>
            <option value="Nanjing|118.7969|32.0603">南京</option>
        </select>
        <label>妈妈的位置:</label>
        <select id="momCity">
            <option value="Beijing|116.4074|39.9042">北京</option>
            <option value="Shanghai|121.4737|31.2304">上海</option>
            <option value="Guangzhou|113.2644|23.1291">广州</option>
            <option value="Shenzhen|114.0579|22.5431">深圳</option>
            <option value="Chengdu|104.0668|30.5728" selected>成都</option>
            <option value="Hangzhou|120.1551|30.2741">杭州</option>
            <option value="Wuhan|114.3054|30.5931">武汉</option>
            <option value="Xi'an|108.9398|34.3416">西安</option>
            <option value="Chongqing|106.5516|29.5630">重庆</option>
            <option value="Harbin|126.5340|45.8038">哈尔滨</option>
        </select>
    </div>

    <!-- 地图 -->
    <div id="map-container"></div>

    <!-- 思念信件 - 右侧垂直居中 -->
    <div class="letter-card">
        <div class="letter-content">
            亲爱的爸爸妈妈:<br><br>
            又是一年春节将至,地图上的这条金色飞线,连接着<span class="highlight">我所在的城市</span>与<span class="highlight">家乡的方向</span>。
            虽然相隔千里,但每一缕思念都顺着这条线飞向你们。<br><br>
            那些曾经的唠叨,如今成了最温暖的声音;那些日常的饭菜香,成了最怀念的味道。
            距离丈量的是空间,却量不尽我对你们的牵挂。<br><br>
            愿这条穿越山河的线,带去我的拥抱。等我回家,我们一起吃顿团圆饭。🧧
        </div>
        <div class="signature">—— 想你们的孩子<br>敬上</div>
    </div>

    <script>
        // 创建飘落效果
        function createPetals() {
            const container = document.getElementById('petals-container');
            const petalCount = 25;
            
            for (let i = 0; i < petalCount; i++) {
                const petal = document.createElement('div');
                petal.className = 'petal';
                petal.style.left = Math.random() * 100 + '%';
                petal.style.width = (Math.random() * 8 + 4) + 'px';
                petal.style.height = (Math.random() * 8 + 4) + 'px';
                petal.style.animationDuration = (Math.random() * 8 + 8) + 's';
                petal.style.animationDelay = Math.random() * 8 + 's';
                petal.style.opacity = Math.random() * 0.5 + 0.2;
                container.appendChild(petal);
            }
        }
        createPetals();

        // 计算距离
        function calculateDistance(lat1, lon1, lat2, lon2) {
            const R = 6371;
            const dLat = (lat2 - lat1) * Math.PI / 180;
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                    Math.sin(dLon/2) * Math.sin(dLon/2);
            const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            return Math.round(R * c);
        }

        // 初始化地图
        let myChart = null;
        
        async function initMap() {
            myChart = echarts.init(document.getElementById('map-container'));
            
            try {
                const response = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json');
                const chinaJson = await response.json();
                echarts.registerMap('china', chinaJson);
                
                updateMap();
            } catch (error) {
                console.error('地图加载失败:', error);
                document.getElementById('map-container').innerHTML = 
                    '<div style="color:white; text-align:center; padding-top:20%; font-size:1.2em;">地图加载中,请检查网络连接...</div>';
            }
        }

        function updateMap() {
            const mySelect = document.getElementById('myCity').value.split('|');
            const momSelect = document.getElementById('momCity').value.split('|');
            
            const myCity = {
                name: mySelect[0],
                value: [parseFloat(mySelect[1]), parseFloat(mySelect[2])]
            };
            const momCity = {
                name: momSelect[0],
                value: [parseFloat(momSelect[1]), parseFloat(momSelect[2])]
            };

            const dist = calculateDistance(myCity.value[1], myCity.value[0], momCity.value[1], momCity.value[0]);
            document.querySelector('#distance span').textContent = dist.toLocaleString();

            // 根据距离调整地图中心点
            const centerLng = (myCity.value[0] + momCity.value[0]) / 2;
            const centerLat = (myCity.value[1] + momCity.value[1]) / 2;

            const option = {
                backgroundColor: 'transparent',
                geo: {
                    map: 'china',
                    roam: true,
                    zoom: 1.1,
                    center: [centerLng, centerLat + 5], // 稍微偏移以平衡右侧文字
                    label: {
                        emphasis: {
                            show: true,
                            color: '#fff'
                        }
                    },
                    itemStyle: {
                        normal: {
                            areaColor: 'rgba(255,255,255,0.08)',
                            borderColor: '#ffd700',
                            borderWidth: 1.5,
                            shadowColor: 'rgba(0, 0, 0, 0.5)',
                            shadowBlur: 10
                        },
                        emphasis: {
                            areaColor: 'rgba(255,215,0,0.2)'
                        }
                    }
                },
                series: [
                    {
                        name: '我的位置',
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        data: [myCity],
                        symbolSize: 25,
                        showEffectOn: 'render',
                        rippleEffect: {
                            brushType: 'stroke',
                            scale: 4,
                            period: 4
                        },
                        label: {
                            show: true,
                            position: 'top',
                            formatter: '{b}\n(我在这儿)',
                            color: '#fff',
                            fontSize: 12,
                            fontWeight: 'bold',
                            backgroundColor: 'rgba(52, 152, 219, 0.8)',
                            padding: [5, 10],
                            borderRadius: 4,
                            distance: 10
                        },
                        itemStyle: {
                            color: '#3498db',
                            shadowBlur: 20,
                            shadowColor: '#3498db'
                        },
                        zlevel: 2
                    },
                    {
                        name: '妈妈的位置',
                        type: 'effectScatter',
                        coordinateSystem: 'geo',
                        data: [momCity],
                        symbolSize: 25,
                        showEffectOn: 'render',
                        rippleEffect: {
                            brushType: 'stroke',
                            scale: 4,
                            period: 4
                        },
                        label: {
                            show: true,
                            position: 'top',
                            formatter: '{b}\n(妈妈在这儿)',
                            color: '#fff',
                            fontSize: 12,
                            fontWeight: 'bold',
                            backgroundColor: 'rgba(231, 76, 60, 0.9)',
                            padding: [5, 10],
                            borderRadius: 4,
                            distance: 10
                        },
                        itemStyle: {
                            color: '#e74c3c',
                            shadowBlur: 20,
                            shadowColor: '#e74c3c'
                        },
                        zlevel: 2
                    },
                    {
                        name: '思念的线',
                        type: 'lines',
                        zlevel: 1,
                        effect: {
                            show: true,
                            period: 5,
                            trailLength: 0.8,
                            color: '#ffd700',
                            symbolSize: 4,
                            constantSpeed: 120
                        },
                        lineStyle: {
                            normal: {
                                width: 3,
                                curveness: 0.2,
                                opacity: 0.9,
                                type: 'solid'
                            }
                        },
                        data: [{
                            coords: [myCity.value, momCity.value],
                            lineStyle: {
                                color: {
                                    type: 'linear',
                                    x: 0, y: 0, x2: 1, y2: 0,
                                    colorStops: [
                                        {offset: 0, color: '#3498db'},
                                        {offset: 0.5, color: '#ffd700'},
                                        {offset: 1, color: '#e74c3c'}
                                    ]
                                }
                            }
                        }]
                    }
                ]
            };

            myChart.setOption(option);
        }

        document.getElementById('myCity').addEventListener('change', updateMap);
        document.getElementById('momCity').addEventListener('change', updateMap);

        window.addEventListener('resize', () => {
            if (myChart) myChart.resize();
        });

        initMap();
    </script>
</body>
</html>
主要调整:
  1. 📜 文字卡片移到右侧 - 垂直居中显示,不遮挡地图主体
  2. 📍 距离显示移到左上 - 与右侧文字形成视觉平衡
  3. 🗺️ 地图自适应 - 根据两座城市自动调整中心点,确保连线完整可见
  4. ✨ 优化了飞线效果 - 增加金色过渡,更醒目
  5. 📱 响应式改进 - 手机屏幕下文字自动回到底部,避免右侧空间不足
现在地图可以完整展示,右侧的书信卡片像一封竖着的情书,静静诉说着思念。