Dog-Map:我给自己做的一张路线地图

Dog-Map:我给自己做的一张路线地图

2026年09月07日
1881 字 · 7 分钟

Dog-Map 是我最近做的一张个人路线地图。

它以南京大学苏州校区为起点,记录我去过的地方、走过的路线和在现场留下的照片。现在地图里已经放入了南京大学苏州校区、南京大学鼓楼校区、东渚夜市、拙政园、狮子林、留园和苏州万象天地。

我想记录的不是一串地点名称。照片可以放进相册,文字可以写进文章,但它们很难直接表现“这些地方在哪里”“它们之间是什么关系”。所以我做了 Dog-Map,把地点、时间、照片和一些现场记录放回地图中。

一、地图样式

Dog-Map 的视觉样式受《Persona 5 Royal》地图界面的启发。这里参考的不是具体素材,而是它处理地图信息的方式:地点像贴纸一样被放在地图上,不同地点有自己的图标,颜色、斜切边缘和文字共同构成了一个比较明确的界面语言。

我没有使用地图 SDK 默认的标记点,而是为地点设计了自己的图标。南京大学苏州校区、东渚夜市、拙政园、狮子林和留园都使用不同的黑白图案;地图上的地点标记则使用红色和米白色的标签显示名称与距离。

Dog-Map 当前地点图标总览

当前版本的地点图标都来自项目自己的素材目录,分别对应南京大学苏州校区、南京大学鼓楼校区、东渚夜市、拙政园、狮子林、留园和苏州万象天地。项目源码与添加地点的说明放在 Dog-Map 仓库 中。

地图本身采用深色底图,主要使用黑色、深蓝、米白、红色和黄色。底图需要足够安静,不能和地点图标争夺注意力;地点图标则要有足够的对比度,用户缩小地图后仍然能知道这里有一个值得查看的地点。

我还给地图加入了 3D 城市场景和地形效果。它们不是为了把地图做得更像游戏,而是让地图不再只是平面上的线条和文字。地点图标悬在地图上方,路线和城市道路保持在下面,地图因此有了比较清楚的层次。

这部分是我自己比较在意的地方。高德地图或其他地图服务可以提供底图和地理数据,但它们不会决定 Dog-Map 应该使用什么颜色、地点应该用什么图标,也不会替我组织这些地点和照片。地图服务提供了基础能力,最终的视觉样式和内容结构仍然需要自己设计。

二、技术实现

项目使用 React、TypeScript 和 Vite 构建,地图渲染使用 MapLibre GL。当前默认地图样式来自 OpenFreeMap,栅格回退使用 OpenStreetMap。地图底图、坐标和地图交互由这些基础服务提供,地点数据和详情内容则由 Dog-Map 自己管理。

整个页面可以理解成两部分:左侧是可以缩放和移动的地图,右侧是点击地点后打开的详情抽屉。地图上的标记不是写死在组件里的,而是从 src/data/places.json 读取。

一个地点大致包含这些字段:

type Place = {
id: string
title: string
subtitle: string
date: string
coordinates: [number, number]
coordinateSource: 'photo-exif' | 'map-poi'
coordinateReference: string
description: string
media: MediaItem[]
shops?: Shop[]
}

这样做的好处是,地点内容和页面组件分开了。添加一个地点时,主要工作是准备数据、照片和坐标,不需要再修改地图组件本身。

点击南京大学苏州校区后,地图会把视角移动到对应地点,同时打开右侧详情。详情中显示地点图标、中文名、英文名、日期、说明和照片。照片可以点击打开大图,也可以使用键盘切换。

南京大学苏州校区的地点详情

东渚夜市是另一个例子。它除了地点照片,还包含一条“椒点川菜”的探店记录。探店记录有自己的分类、简介、标签和照片,但它仍然属于东渚夜市这个地点,而不是一个和夜市并列的地图标记。

东渚夜市的地点详情和探店入口

打开探店记录以后,详情抽屉会切换到店铺内容,保留返回地点的入口。这让一张地图可以继续承载照片和文字,而不只是点击标记后显示一个名称。

椒点川菜的探店详情

地图上的图标还会随着缩放比例调整大小。地点相近时,代码会计算标记之间的距离,给发生重叠的图标安排偏移;移动端则使用更紧凑的布局。这样做不是为了让所有标记永远保持完全不动,而是让它们在不同的地图比例下仍然可以点击。

除了页面本身,项目还保留了坐标来源和坐标依据。有些地点的坐标来自照片 EXIF,有些来自地图 POI。添加地点时需要明确填写来源,构建前还会运行坐标校验脚本。这样可以避免照片、地点文字和地图位置之间出现明显不一致。

项目也预留了媒体 API。当前页面可以直接使用静态照片,后续也可以从远程媒体服务读取内容。服务端已经准备了 JSON catalog、PostgreSQL catalog、本地存储和 R2 存储的接口,但这部分不是页面运行的必要条件。

三、添加地点

Dog-Map 对我来说最重要的使用方式很简单:到一个地方,就给它添加一个地点。

我会记录这个地方的名称、日期、坐标和一两句说明,再把现场照片放进对应的媒体目录。如果这次经历中有一条路线,或者有一家值得单独记录的店,也可以继续添加路线和探店内容。

例如,南京大学苏州校区是这张地图的起点。东渚夜市记录了一次骑车夜访,里面还有椒点川菜的探店照片。拙政园、狮子林和留园则来自同一次苏州园林之行,但它们仍然分别保留自己的地点和照片。

这套记录方式和相册的区别在于,每张照片都有一个地点,每个地点都处在地图上的具体位置。以后我再去到一个新的地方,不需要先考虑它应该属于哪个复杂的内容分类,只要把它添加到地图上,写下当时留下的记录即可。

结尾

Dog-Map 现在还只是一个个人项目。它没有试图覆盖所有地图功能,也没有把每次出行都整理成完整的游记;它只保留我确实去过的地方,以及那些值得在以后重新定位的照片和记录。

到一个地方,我就会留下一点纪念。可能是一张照片,一段文字,或者只是一个坐标。Dog-Map 做的事情,就是把这些零散的纪念放回它们原本的位置。


Thanks for reading!

Dog-Map:我给自己做的一张路线地图

2026年09月07日
1881 字 · 7 分钟
加载中...

评论 (需 GitHub 账号登录)

正在加载评论...