# ThreeJs_map **Repository Path**: KAIIWEN/three-js_map ## Basic Information - **Project Name**: ThreeJs_map - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-23 - **Last Updated**: 2026-05-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 全球景点粒子地球 (Map All World) 基于 Three.js 的交互式3D粒子地球,展示全球111个著名景点,支持景点详情查看、图片幻灯片、飞行定位等功能。 ## 在线预览 ```bash npm install npm run dev # 访问 http://localhost:5300/particle-globe.html ``` ## 项目结构 ``` map-allworld/ ├── particle-globe.html # 主页面(粒子地球模式) ├── globe.html # 地形地球模式 ├── index.html # 地形模式入口 ├── vite.config.js # Vite 构建配置 ├── src/ │ ├── main-particle-globe.js # 粒子地球主入口 │ ├── main-globe.js # 地形地球主入口 │ ├── main.js # 地形模式入口 │ ├── config/ │ │ ├── app.js # 应用配置 │ │ ├── landmark-images.json # 景点图片ID缓存(核心数据) │ │ ├── terrainLayers.js # 地形图层配置 │ │ └── terrainParams.js # 地形参数 │ ├── data/ │ │ ├── landmarks.js # 景点数据聚合入口 │ │ ├── legends.js # 景点传说与故事(独立管理) │ │ ├── regions/ │ │ │ ├── asia.js # 亚洲景点(30+) │ │ │ ├── europe.js # 欧洲景点(30+) │ │ │ ├── americas.js # 美洲景点(25+) │ │ │ ├── africa.js # 非洲景点(15+) │ │ │ ├── mideast.js # 中东景点(10+) │ │ │ └── oceania.js # 大洋洲景点(10+) │ │ ├── themes.js # 主题配色方案 │ │ └── ... # 地形/DEM/掩码数据 │ ├── scene/ │ │ ├── ParticleGlobe.js # 粒子地球渲染 │ │ ├── LandmarkLayer.js # 景点3D标记层(LOD) │ │ ├── LandmarkUI.js # 景点详情面板+幻灯片 │ │ ├── Atmosphere.js # 大气层效果 │ │ └── ... # 其他视觉效果 │ ├── services/ │ │ └── PexelsImageService.js # 图片加载服务 │ └── controls/ │ └── CameraController.js # 相机控制 ├── scripts/ │ └── fetch-new-pexels-ids.mjs # 图片ID爬取脚本(核心) └── tests/ # Vitest 测试 ``` ## 核心功能 - **粒子地球**:基于经纬度掩码数据生成粒子化地球,支持6种科技感主题切换 - **111个全球景点**:按6大洲分区管理,包含坐标、简介、票价、避坑指南等完整信息 - **景点传说故事**:每个景点配有神话传说或历史故事,独立于景点数据管理 - **LOD标记系统**:远距离只显示发光点,中距离显示名称,近距离显示光柱脉冲 - **景点详情面板**:幻灯片图片展示(10秒自动切换)、左右导航、点击放大 - **飞行定位**:点击景点自动飞行到对应位置,相机平滑过渡 - **区域/类别筛选**:按大洲或类型(文化遗产/自然奇观/现代地标)筛选 --- ## 图片获取方案(重点) ### 设计原则 **所有景点图片均通过浏览器从 Pexels 网站获取,不使用 API Key,不使用第三方图片服务。** ### 架构流程 ``` Pexels 网站 ──(Puppeteer浏览器)──> 图片ID ──(缓存到JSON)──> 运行时构造URL ``` 1. **爬取阶段**:使用 Puppeteer 可见模式浏览器,逐个搜索景点关键词,从搜索结果页面提取图片 ID 2. **缓存阶段**:将图片 ID 保存到 `src/config/landmark-images.json` 3. **运行阶段**:`PexelsImageService.js` 读取 JSON 中的图片 ID,构造 Pexels CDN 图片 URL ### 为什么不用 API Key? Pexels API 需要 API Key 且有调用限制。本项目采用浏览器自动化方式,直接从 Pexels 网站搜索结果中提取图片 ID,完全免费无限制。 ### 爬取脚本使用方法 ```bash # 安装依赖(puppeteer 为 devDependency) npm install # 运行爬取脚本 node scripts/fetch-new-pexels-ids.mjs ``` **脚本工作流程:** 1. 打开 Pexels 首页,等待 Cloudflare 人机验证通过(需手动完成) 2. 验证通过后,自动逐个搜索景点关键词(如 "temple of heaven beijing") 3. 从搜索结果页面提取图片 ID(使用多种选择器策略兼容页面变化) 4. 每获取3个景点自动保存进度,支持 Ctrl+C 中断后断点续传 5. 结果写入 `src/config/landmark-images.json` **关键特性:** - **Cloudflare 验证处理**:自动检测验证页面,等待用户手动完成验证后继续 - **多策略提取**:依次尝试 `article.photo-item`、`img[src*="pexels.com"]`、`[data-photo-id]`、页面源码正则匹配 - **断点续传**:已有图片 ID 的景点自动跳过,中断后重新运行只爬缺失部分 - **搜索关键词映射**:`SEARCH_KEYWORDS` 对象为每个景点 ID 配置了优化的英文搜索关键词 ### 图片 ID 缓存格式 `src/config/landmark-images.json` 示例: ```json { "forbidden_city": ["12112852", "7265335", "18549556", "36541909"], "great_wall_badaling": ["19031655", "18709771", "6187742", "5714061"], "eiffel_tower": ["532436", "3629519", "2363901", "416645"] } ``` 每个景点缓存4张图片 ID,用于幻灯片轮播。 ### 运行时图片加载 `PexelsImageService.js` 核心逻辑: ```javascript // 根据 Pexels 图片 ID 构造 CDN 图片 URL function buildPexelsImageUrl(photoId, { w = 800, h = 500 } = {}) { return `https://images.pexels.com/photos/${photoId}/pexels-photo-${photoId}.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=${h}&w=${w}`; } // 获取景点的图片 URL 列表 function getLandmarkImages(landmarkId) { const photoIds = LANDMARK_IMAGE_IDS[landmarkId]; return photoIds.map(id => buildPexelsImageUrl(id)); } ``` ### 添加新景点图片 1. 在 `src/data/regions/` 对应文件中添加景点数据(含 `id` 字段) 2. 在 `scripts/fetch-new-pexels-ids.mjs` 的 `SEARCH_KEYWORDS` 中添加搜索关键词映射 3. 运行 `node scripts/fetch-new-pexels-ids.mjs`,脚本会自动只爬取新增景点 --- ## 景点传说故事 每个景点都配有相关的神话传说或历史故事,以独立文件 `src/data/legends.js` 管理,通过景点 ID 关联。 ### 设计思路 传说数据独立于景点数据,原因: - 传说内容较长(100-300字),混入景点数据会使文件臃肿 - 传说是可选内容,部分景点可能暂无传说 - 便于单独维护和扩展 ### 数据结构 ```javascript // src/data/legends.js export const LEGENDS = { forbidden_city: '传说紫禁城有9999间半房屋,因天帝天宫有万间...', great_wall_badaling: '孟姜女千里寻夫哭倒长城的传说流传千年...', // ... 100+ 景点传说 }; ``` ### 使用方式 在 `LandmarkUI.js` 中通过景点 ID 查找传说: ```javascript import { LEGENDS } from '../data/legends.js'; const legend = LEGENDS[landmarkId]; if (legend) { // 显示传说区域 } ``` ### 传说覆盖 - 亚洲:故宫、长城、兵马俑、富士山、吴哥窟、泰姬陵等 - 欧洲:埃菲尔铁塔、卢浮宫、圣家堂、巨石阵、雅典卫城等 - 美洲:自由女神像、大峡谷、马丘比丘、基督像、伊瓜苏瀑布等 - 非洲:金字塔、帝王谷、乞力马扎罗、维多利亚瀑布等 - 中东:哈利法塔、西墙、死海、瓦迪拉姆等 - 大洋洲:悉尼歌剧院、大堡礁、乌鲁鲁、霍比屯等 --- ## 景点数据结构 每个景点包含以下字段: ```javascript { id: 'forbidden_city', // 唯一标识(用于图片缓存关联) name: '故宫博物院', // 中文名称 nameEn: 'Forbidden City', // 英文名称 country: '中国', // 所属国家 region: 'asia', // 大洲(asia/europe/americas/africa/mideast/oceania) lat: 39.9163, // 纬度(WGS84) lng: 116.3972, // 经度(WGS84) category: 'heritage', // 类别(heritage/nature/landmark) description: '...', // 景点描述 ticket: '...', // 票价信息 ticketNote: '...', // 票价备注 bestTime: '...', // 最佳游览时间 tips: '...', // 游览建议 warnings: '...', // 注意事项/避坑指南 } ``` --- ## 主题系统 内置6种科技感主题: | 主题 | 风格 | |------|------| | 赛博青 | Cyberpunk HUD 风格,青色主调 | | 矩阵绿 | Matrix 终端风格,绿色主调 | | 暗金 | Tron Legacy 风格,金色主调 | | 军事绿 | Military HUD 风格,橄榄绿主调 | | 合成波 | Synthwave 风格,紫粉渐变 | | 深海蓝 | Deep Sea 风格,深蓝主调 | --- ## 技术栈 - **Three.js** - 3D 渲染引擎 - **Vite** - 构建工具 - **Vitest** - 测试框架 - **Puppeteer** - 图片 ID 爬取 - **CSS2DRenderer** - 景点标签渲染 ## 测试 ```bash npx vitest run ``` 当前测试覆盖:291 个测试用例,12 个测试文件。