目录
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 的人生轨迹叙事引擎,核心功能是将人物的生平事件标注在地图上,以时间线串联空间足迹,在地图上讲述人物的完整人生故事。
核心功能列表:
- 时空轨迹地图 --- 在百度地图上标注人生事件地点,自动绘制事件间路线段,支持缩放、拖动、点击查看详情
- 时间线叙事 --- 右侧面板按年份排列事件卡片,展示标题、地点、描述、史料来源
- 人物画廊 --- 多图片轮播展示人物肖像和故事插图,支持导航、自动滚动、事件联动
- 足迹播放 --- 自动播放人生轨迹动画,按时间顺序激活标记、展开信息窗口、滚动时间线
- 阶段筛选 --- 按人生阶段筛选事件,地图和时间线同步过滤显示
- 可信度标注 --- 每个事件标注史料可信度等级,区分考据与演绎
- 主题切换 --- 暗色与亮色双主题,偏好自动记忆,切换时遮罩过渡
- 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 mandatory和touch-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-theme和data-map-theme属性,切换地图样式 - 白屏防护: 切换前显示加载遮罩,设置容器背景色,
requestAnimationFrame延迟一帧再切换样式 - 偏好持久化: 切换后写入
localStorage,下次访问自动恢复
4.7 AJAX数据加载模块
数据加载模块在页面初始化时异步加载事件数据和图片数据。
加载流程:
- 检测
file://协议,提示用户通过 HTTP 服务访问 - 启动全局安全超时(8秒),防止加载卡死
- 使用
AbortController创建 10 秒 fetch 超时 Promise.all并行加载data.json和images.json- 解析 JSON 数据,获取 DOM 元素引用
- 调用
buildSideHead()、buildGallery()、buildTimelineCards()构建页面内容 - 调用
updateStats()更新统计数据 - 初始化画廊、主题和事件监听
- 调用
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 | 史料来源列表,每项含 label 和 url |
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,添加到markerPanedraw():地图缩放/拖动时重新计算像素位置,使用pointToOverlayPixel()show()/hide():控制覆盖物显示隐藏,用于阶段筛选getContent():返回内部 button 元素,用于状态同步
6.3 画廊无限轮播
画廊模块通过克隆首尾幻灯片实现无限循环滚动效果:
setupGalleryLoop():克隆第一张幻灯片追加到末尾,克隆最后一张幻灯片插入到开头normalizeGalleryLoop():滚动到克隆节点时静默跳转到真实节点(behavior: 'auto')showGallerySlide():计算目标位置,支持平滑滚动和自动跳转- 使用
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 主题切换白屏防护
切换地图主题时,瓦片需要重新加载,可能导致短暂白屏。防护措施:
- 切换前调用
showMapLoading()显示遮罩 - 设置地图容器背景色匹配目标主题(暗色
#06101f,亮色#e8eef2) - 使用
requestAnimationFrame延迟一帧再调用setMapStyle(),让遮罩先渲染 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 部署方式
本软件为纯前端静态网站,部署步骤如下:
- 将
life-trace-bmap/目录完整上传到 Web 服务器或静态托管平台 - 确保通过 HTTP/HTTPS 协议访问(如
http://localhost:8080/life-trace-bmap/index.html) - 本地开发可使用
python -m http.server 8080启动临时服务 - 支持部署到 GitHub Pages、Vercel、Netlify 等静态托管平台
⚠️ 注意: 不可通过
file://协议直接打开index.html,因为 AJAX 的fetch在file://协议下无法加载 JSON 文件。软件已内置协议检测并会显示提示信息。
8.2 数据定制
替换 js/data.json 和 js/images.json 即可定制任意人物的人生轨迹:
- 编辑
data.json:修改person对象的人物信息,替换events数组中的事件数据 - 准备图片:将人物肖像和故事插图转换为 Base64 编码
- 编辑
images.json:以事件 ID 为键,Base64 Data URI 为值 - 刷新页面即可看到新内容,无需修改任何代码
8.3 使用说明
| 操作 | 效果 |
|---|---|
| 点击地图标记 | 激活该事件,打开信息窗口,时间线滚动到对应卡片 |
| 点击时间线卡片 | 激活该事件,地图平移到对应位置,画廊切换到对应插图 |
| 点击"播放足迹" | 自动按时间顺序播放人生轨迹,可暂停 |
| 调节播放速度 | 选择 0.6×、1×、1.8× 三档速度 |
| 点击"重置" | 停止播放,回到起点,重置筛选和地图视野 |
| 点击阶段筛选按钮 | 按人生阶段过滤事件,地图和卡片同步更新 |
| 切换暗色/白色 | 切换地图主题,偏好自动记忆 |
| 左右滑动画廊 | 浏览人物肖像和故事插图 |
| 点击"在百度地图查看" | 在新标签页打开百度地图对应位置 |
8.4 在线演示
软件在线演示地址:https://geojson.lockdata.cn/trace/
@漏刻有时