LockTrace:用百度地图讲一个人生故事——轨迹地图引擎的设计与实现

目录

  1. 引言
  2. 软件概述
  3. 系统设计
  4. 功能模块设计
  5. 数据结构设计
  6. 关键技术实现
  7. 界面设计
  8. 部署与使用说明

1. 引言

1.1 编写目的

本说明书旨在详细描述 LockTrace行迹人生地图可视化软件 V1.0(以下简称"本软件")的系统架构、功能模块、数据结构和关键技术实现,为软件著作权登记提供技术文档支撑,同时作为软件维护与迭代的参考依据。

1.2 项目背景

本软件=属于"漏刻有时"品牌旗下的地图可视化产品线。产品定位于人物生平轨迹的地图叙事引擎,将历史人物或现代人物的人生事件映射到地理坐标上,配合时间线卡片、人物画廊、足迹动画等功能,形成可交互的数字人生叙事体验。

当前 Demo 以历史人物玄奘(西天取经)为示例数据。数据结构设计为通用模板,可替换为任意人物的轨迹数据。

1.3 术语定义

术语 说明
GCJ-02 火星坐标系,中国国家测绘局制定的地理坐标加密系统
BD-09 百度坐标系,在 GCJ-02 基础上的二次加密偏移
JS API JavaScript API,百度地图提供的网页端地图开发接口
AJAX Asynchronous JavaScript and XML,异步数据加载技术
Overlay 地图覆盖物,叠加在地图瓦片上方的自定义可视化元素
InfoWindow 信息窗口,点击地图标记后弹出的详情面板
Base64 一种二进制到文本的编码方式,用于将图片内嵌到 JSON 数据中

2. 软件概述

2.1 软件功能

本软件是一款基于百度地图 JavaScript API 的人生轨迹叙事引擎,核心功能是将人物的生平事件标注在地图上,以时间线串联空间足迹,在地图上讲述人物的完整人生故事。

核心功能列表:

  1. 时空轨迹地图 --- 在百度地图上标注人生事件地点,自动绘制事件间路线段,支持缩放、拖动、点击查看详情
  2. 时间线叙事 --- 右侧面板按年份排列事件卡片,展示标题、地点、描述、史料来源
  3. 人物画廊 --- 多图片轮播展示人物肖像和故事插图,支持导航、自动滚动、事件联动
  4. 足迹播放 --- 自动播放人生轨迹动画,按时间顺序激活标记、展开信息窗口、滚动时间线
  5. 阶段筛选 --- 按人生阶段筛选事件,地图和时间线同步过滤显示
  6. 可信度标注 --- 每个事件标注史料可信度等级,区分考据与演绎
  7. 主题切换 --- 暗色与亮色双主题,偏好自动记忆,切换时遮罩过渡
  8. AJAX异步加载 --- 事件数据与图片数据分离,fetch并行加载,页面骨架秒级渲染

2.2 性能特点

  • 纯前端架构: HTML + CSS + JavaScript 三文件分离,无后端依赖,无构建工具,可直接部署为静态网站
  • 数据驱动: 替换 JSON 数据文件即可定制任意人物轨迹,无需修改代码
  • 秒级渲染: 页面骨架(HTML + CSS)秒级加载,数据通过 AJAX 异步并行加载
  • 多重安全超时: 全局8秒、fetch 10秒、瓦片6秒、API 3秒四级超时保护,防止加载卡死
  • 响应式适配: 桌面端左右分栏,平板端自适应比例,手机端上下堆叠

2.3 运行环境

项目 要求
操作系统 跨平台(Windows / macOS / Linux / iOS / Android)
运行环境 支持 HTML5 的现代 Web 浏览器
推荐浏览器 Chrome 90+ / Edge 90+ / Safari 14+ / Firefox 88+
访问协议 HTTP / HTTPS(不支持 file:// 协议,AJAX 需 HTTP 服务)
地图服务 百度地图 JavaScript API 3.0(通过代理服务调用)
屏幕分辨率 自适应,最低支持 320px 宽度

3. 系统设计

3.1 总体架构

本软件采用纯前端单页应用(SPA)架构,无后端服务依赖。整个应用由 HTML 骨架、CSS 样式和 JavaScript 逻辑三个核心文件组成,运行时通过 AJAX 异步加载 JSON 数据文件。

三层架构:

复制代码
┌─────────────────────────────────────────────────────────────┐
│  表现层(Presentation Layer)                                │
│  ┌──────────────┬──────────────┬──────────────────────────┐ │
│  │ index.html   │ style.css    │ app.js                   │ │
│  │ HTML骨架     │ 样式表       │ 应用逻辑                  │ │
│  └──────────────┴──────────────┴──────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│  逻辑层(Logic Layer)                                       │
│  ┌────────┬──────────┬────────┬────────┬────────┐          │
│  │地图引擎│时间线叙事│画廊轮播│足迹播放│主题切换│          │
│  │BMap API│Timeline  │Gallery │Playback│Theme   │          │
│  └────────┴──────────┴────────┴────────┴────────┘          │
├─────────────────────────────────────────────────────────────┤
│  数据层(Data Layer)· AJAX异步加载                           │
│  ┌──────────────────────┬──────────────────────────────┐   │
│  │ data.json · 事件数据 │ images.json · 图片数据        │   │
│  └──────────────────────┴──────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

3.2 文件结构

复制代码
life-trace-bmap/
├── index.html          # HTML骨架(页面结构、地图容器、加载遮罩)
├── css/
│   └── style.css       # CSS样式表(布局、主题、动画、响应式)
├── js/
│   ├── app.js          # JavaScript应用逻辑(全部功能实现)
│   ├── data.json       # 事件数据(AJAX加载,15个事件+人物信息)
│   └── images.json     # 图片数据(AJAX加载,Base64编码)
├── images/
│   └── xuxiake/        # 徐霞客图片素材(8张)
└── product-info.html   # 产品说明与免责声明文档

3.3 技术选型

技术项 选型 选型理由
地图引擎 百度地图 JS API 3.0 国内地图服务覆盖完善,支持自定义覆盖物和样式
架构模式 纯前端 SPA 无需后端服务,部署简单,适合静态网站托管
数据加载 Fetch API + Promise.all 原生异步并行加载,无需第三方库
数据格式 JSON 轻量、通用、易于编辑和替换
图片编码 Base64 Data URI 图片内嵌JSON,减少HTTP请求,支持离线运行
主题存储 localStorage 原生浏览器存储,记忆用户主题偏好
构建工具 源码即部署代码,无需编译打包

4. 功能模块设计

4.1 地图引擎模块

地图引擎模块是本软件的核心,负责百度地图的初始化、事件标记渲染、路线段绘制和信息窗口管理。

主要功能:

  • 地图初始化(initBmap()): 加载百度地图 JS API,创建地图实例,设置中心点和缩放级别,启用滚轮缩放、拖动、双击缩放和键盘操作
  • 自定义标记(LifeMarkerOverlay): 继承 BMap.Overlay 实现自定义覆盖物,每个标记是一个可交互的 button 元素,带有发光效果和激活状态
  • 路线段绘制: 在相邻事件之间绘制 BMap.Polyline 折线,交替使用红色和金色,默认隐藏,播放时按顺序显示
  • 信息窗口(openInfo()): 点击标记或卡片时弹出 BMap.InfoWindow,展示事件标题、年份、地点和描述
  • 地图样式切换: 暗色主题使用自定义 styleJson 配置,亮色主题使用默认 normal 样式

关键代码结构:

javascript 复制代码
// 自定义地图覆盖物
function LifeMarkerOverlay(point, btn, idx) {
  this._point = point;
  this._button = btn;
  this._index = idx;
}
LifeMarkerOverlay.prototype = new BMap.Overlay();
LifeMarkerOverlay.prototype.initialize = function(map) {
  this._map = map;
  this._div = document.createElement('div');
  this._div.style.position = 'absolute';
  this._div.style.zIndex = String(100 + this._index);
  this._div.appendChild(this._button);
  map.getPanes().markerPane.appendChild(this._div);
  return this._div;
};
LifeMarkerOverlay.prototype.draw = function() {
  var px = this._map.pointToOverlayPixel(this._point);
  this._div.style.left = (px.x - 9) + 'px';
  this._div.style.top = (px.y - 9) + 'px';
};

4.2 时间线叙事模块

时间线模块在右侧面板按年份排列事件卡片,每张卡片包含年份、可信度标签、古地名/现代地名、故事标签、事件标题、事件描述和史料来源链接。

主要功能:

  • 动态构建卡片(buildTimelineCards()): 遍历 DATA.events 数组,为每个事件生成 HTML 卡片
  • 卡片点击联动: 点击卡片激活对应地图标记,平移地图中心,打开信息窗口
  • 百度地图链接: 每张卡片底部生成百度地图 marker URL,含 GCJ-02→BD-09 坐标转换
  • 史料来源折叠: 使用 <details> 元素实现史料来源的折叠展开

4.3 人物画廊模块

画廊模块实现人物肖像和故事插图的轮播展示,支持无限循环滚动。

主要功能:

  • 幻灯片构建(buildGallery()): 主肖像 + 每个带 storyImage 的事件插图组成幻灯片列表
  • 无限轮播(setupGalleryLoop()): 克隆首尾幻灯片实现无缝循环,滚动到边界时静默跳转
  • 事件联动(syncGalleryFromEvent()): 激活事件时自动切换到对应故事插图
  • 手势支持: 使用 scroll-snap-type: x mandatorytouch-action: pan-x 支持触摸滑动

4.4 足迹播放模块

足迹播放模块实现人生轨迹的自动动画播放,按时间顺序依次激活事件。

主要功能:

  • 播放控制(step()): 使用 setTimeout 递归调用,按速度系数计算间隔时间
  • 进度条更新(updateProgress()): 实时更新进度条宽度和计数文本
  • 速度调节: 支持 0.6×、1×、1.8× 三档播放速度
  • 重置(resetPlayback()): 停止播放,回到第一个事件,重置筛选和地图视野

4.5 阶段筛选模块

阶段筛选模块按人生阶段过滤事件,地图标记、路线段和时间线卡片同步更新。

  • DATA.events 提取不重复的 phase 值生成筛选按钮
  • 点击筛选按钮时,非匹配阶段的卡片添加 hidden 类,地图标记调用 hide()/show()
  • 地图视野自动调整到筛选后事件的范围(map.setViewport()

4.6 主题切换模块

主题切换模块管理暗色/亮色双主题的切换和持久化。

  • 主题读取(readStoredTheme()):localStorage 读取上次保存的主题
  • 主题应用(applyTheme()): 设置 data-themedata-map-theme 属性,切换地图样式
  • 白屏防护: 切换前显示加载遮罩,设置容器背景色,requestAnimationFrame 延迟一帧再切换样式
  • 偏好持久化: 切换后写入 localStorage,下次访问自动恢复

4.7 AJAX数据加载模块

数据加载模块在页面初始化时异步加载事件数据和图片数据。

加载流程:

  1. 检测 file:// 协议,提示用户通过 HTTP 服务访问
  2. 启动全局安全超时(8秒),防止加载卡死
  3. 使用 AbortController 创建 10 秒 fetch 超时
  4. Promise.all 并行加载 data.jsonimages.json
  5. 解析 JSON 数据,获取 DOM 元素引用
  6. 调用 buildSideHead()buildGallery()buildTimelineCards() 构建页面内容
  7. 调用 updateStats() 更新统计数据
  8. 初始化画廊、主题和事件监听
  9. 调用 initBmap() 初始化地图

多重安全超时机制: 全局8秒 → fetch 10秒(AbortController)→ 瓦片6秒 → API 3秒(loadBmap轮询),确保任何环节失败都能隐藏加载遮罩并显示错误信息。


5. 数据结构设计

5.1 事件数据结构(data.json)

事件数据文件包含人物信息和事件列表,采用 JSON 格式存储。每个事件对象包含以下字段:

字段名 类型 说明
id String 事件唯一标识,如 "zhuo-161"
year String 事件发生年份,如 "161"
place String 古地名,如 "涿郡涿县"
modernPlace String 现代对应地名,如 "河北省保定市涿州市"
title String 事件标题,如 "生于涿郡"
description String 事件详细描述
phase String 人生阶段,用于阶段筛选
coordinates Array 地理坐标 经度, 纬度,使用 GCJ-02 坐标系
confidence String 可信度等级:confirmed / inferred / disputed / literary
sources Array 史料来源列表,每项含 labelurl
storyTag String (可选)故事标签,如 "桃园结义"
storyTagType String (可选)标签类型,如 "文学典故"
storyImage Boolean (可选)是否有故事插图
storyImageAlt String (可选)插图替代文本

6. 关键技术实现

6.1 坐标转换算法(GCJ-02 → BD-09)

百度地图使用 BD-09 坐标系,而数据源使用 GCJ-02(火星坐标系)。软件内置坐标转换函数,在渲染标记和路线时实时转换。

javascript 复制代码
function gcjToBd(c) {
  const x = 3.141592653589793 * 3000 / 180;
  const lng = c[0], lat = c[1];
  const z = Math.sqrt(lng * lng + lat * lat)
           + .00002 * Math.sin(lat * x);
  const t = Math.atan2(lat, lng)
           + .000003 * Math.cos(lng * x);
  return [z * Math.cos(t) + .0065,
          z * Math.sin(t) + .006];
}

该函数在以下场景被调用:标记创建、路线段绘制、信息窗口定位、百度地图链接生成、地图视野设置。

6.2 自定义地图覆盖物

软件通过继承 BMap.Overlay 实现自定义标记覆盖物 LifeMarkerOverlay,相比百度地图原生 Marker,自定义覆盖物可以使用 HTML 元素作为标记内容,支持 CSS 样式和事件绑定。

  • initialize():创建容器 div,设置绝对定位和 z-index,添加到 markerPane
  • draw():地图缩放/拖动时重新计算像素位置,使用 pointToOverlayPixel()
  • show()/hide():控制覆盖物显示隐藏,用于阶段筛选
  • getContent():返回内部 button 元素,用于状态同步

6.3 画廊无限轮播

画廊模块通过克隆首尾幻灯片实现无限循环滚动效果:

  1. setupGalleryLoop():克隆第一张幻灯片追加到末尾,克隆最后一张幻灯片插入到开头
  2. normalizeGalleryLoop():滚动到克隆节点时静默跳转到真实节点(behavior: 'auto'
  3. showGallerySlide():计算目标位置,支持平滑滚动和自动跳转
  4. 使用 scroll-snap-type: x mandatory 确保每次滚动对齐到幻灯片边界

6.4 地图加载遮罩与安全超时

为解决地图瓦片加载延迟导致的白屏问题和加载卡死问题,软件实现了多重安全超时机制:

超时层级 时间 触发条件与处理
全局安全超时 8秒 无论什么状态,强制隐藏加载遮罩
fetch 超时 10秒 AbortController 中止 fetch 请求
瓦片加载超时 6秒 tilesloaded 事件未触发时强制隐藏遮罩
API 加载超时 3秒 loadBmap() 轮询 30 次(100ms间隔)后超时
遮罩自动隐藏 3.5秒 showMapLoading() 中的安全计时器

所有错误路径(catch 块、超时回调)都会调用 hideMapLoading() 确保遮罩不会永久卡住。

6.5 主题切换白屏防护

切换地图主题时,瓦片需要重新加载,可能导致短暂白屏。防护措施:

  1. 切换前调用 showMapLoading() 显示遮罩
  2. 设置地图容器背景色匹配目标主题(暗色 #06101f,亮色 #e8eef2
  3. 使用 requestAnimationFrame 延迟一帧再调用 setMapStyle(),让遮罩先渲染
  4. tilesloaded 事件触发后隐藏遮罩

7. 界面设计

7.1 布局结构

软件采用左右分栏布局:左侧为地图区域(约65%宽度),右侧为信息面板(约35%宽度)。

  • 地图区域: 顶部叠加标题栏(品牌标识、地图工具、主题切换),底部叠加统计数据和播放控制面板,中央为地图画布
  • 信息面板: 顶部为人物信息头(名称、简介、阶段筛选),中部为人物画廊,下部为时间线事件卡片列表
  • 响应式断点: 1050px隐藏徽章和统计、900px改为上下堆叠、560px优化触摸操作

7.2 暗色/亮色双主题

主题 配色方案 适用场景
暗色主题 深蓝黑底(#030913)+ 青蓝发光(#5cd6ff)+ 金色高亮(#ffc857)+ 红色标记(#ff4f3d) 展厅展示、夜间浏览、科技感场景
亮色主题 博物馆纸感(#eef3f6)+ 深墨文字(#172437)+ 暖金强调(#a56500)+ 朱红标记(#a92f24) 日间浏览、学术阅读、打印输出

两个主题均采用"历史博物馆"视觉风格,暗色主题强调科技沉浸感,亮色主题强调纸本阅读感。

7.3 响应式适配

css 复制代码
/* 桌面端:左右分栏 */
.shell { grid-template-columns: minmax(0, 2.12fr) minmax(390px, 1fr); }

/* 平板端:调整比例 */
@media (max-width: 1050px) {
  .shell { grid-template-columns: minmax(0, 1.75fr) minmax(350px, 1fr); }
}

/* 手机端:上下堆叠 */
@media (max-width: 900px) {
  .shell { display: block; }
  .map-stage { height: 72vh; }
}

/* 小屏手机:优化触摸 */
@media (max-width: 560px) {
  .map-stage { height: 76vh; }
  .play-actions { display: grid; }
}

8. 部署与使用说明

8.1 部署方式

本软件为纯前端静态网站,部署步骤如下:

  1. life-trace-bmap/ 目录完整上传到 Web 服务器或静态托管平台
  2. 确保通过 HTTP/HTTPS 协议访问(如 http://localhost:8080/life-trace-bmap/index.html
  3. 本地开发可使用 python -m http.server 8080 启动临时服务
  4. 支持部署到 GitHub Pages、Vercel、Netlify 等静态托管平台

⚠️ 注意: 不可通过 file:// 协议直接打开 index.html,因为 AJAX 的 fetchfile:// 协议下无法加载 JSON 文件。软件已内置协议检测并会显示提示信息。

8.2 数据定制

替换 js/data.jsonjs/images.json 即可定制任意人物的人生轨迹:

  1. 编辑 data.json:修改 person 对象的人物信息,替换 events 数组中的事件数据
  2. 准备图片:将人物肖像和故事插图转换为 Base64 编码
  3. 编辑 images.json:以事件 ID 为键,Base64 Data URI 为值
  4. 刷新页面即可看到新内容,无需修改任何代码

8.3 使用说明

操作 效果
点击地图标记 激活该事件,打开信息窗口,时间线滚动到对应卡片
点击时间线卡片 激活该事件,地图平移到对应位置,画廊切换到对应插图
点击"播放足迹" 自动按时间顺序播放人生轨迹,可暂停
调节播放速度 选择 0.6×、1×、1.8× 三档速度
点击"重置" 停止播放,回到起点,重置筛选和地图视野
点击阶段筛选按钮 按人生阶段过滤事件,地图和卡片同步更新
切换暗色/白色 切换地图主题,偏好自动记忆
左右滑动画廊 浏览人物肖像和故事插图
点击"在百度地图查看" 在新标签页打开百度地图对应位置

8.4 在线演示

软件在线演示地址:https://geojson.lockdata.cn/trace/


@漏刻有时

相关推荐
小磊哥er6 分钟前
深入解构Claude Code - 第 5 篇 · 每次提问都给 AI 塞了什么资料
javascript·ai编程
小磊哥er10 分钟前
深入解构Claude Code - 第 4 篇 · 工具:AI 的手
javascript·ai编程
子非鱼a22 分钟前
【WEB】[NewStarCTF 公开赛赛道]UnserializeOne
前端·javascript·html
小磊哥er1 小时前
深入解构Claude Code - 第 3 篇 · 一问一答怎么转起来
javascript·ai编程
小磊哥er2 小时前
深入解构Claude Code - 第 2 篇 · 启动的秘密
javascript·ai编程
月月大王的3D日记2 小时前
Three.js 入门系列(9):从零搭一座“闹鬼小屋”
前端·javascript
开开心心就好3 小时前
电子教鞭工具支持画框写字插图片功能齐全
android·开发语言·前端·javascript·人工智能·pdf·html
Dovis(誓平步青云)3 小时前
拍视频前先把镜头想清楚:做一个分镜取景辅助器
android·java·服务器·javascript·人工智能
2601_962071574 小时前
Java进阶(vue基础)
前端·javascript·vue.js
研☆香4 小时前
数组方法 splice讲解 拓展
开发语言·前端·javascript