高德地图坐标侧漂记录
这篇文档只记录一个问题:
- 照片 EXIF 里的 GPS 点位在高德地图上整体偏到一侧
- 点位群的形状大致还是对的,但整片点会整体偏东、偏北,或者偏到道路另一侧
这不是偶发 UI 问题,也不是经纬度顺序写反,而是典型的坐标系问题。
现象
在 Travel 地图里,照片点位会出现下面这种表现:
- 一组照片明明拍的是同一片街区,但标记整体落到街对面
- 点位之间的相对位置看起来基本正确,但整体平移了几十米到几百米
- 高德逆地理编码返回的地点名称是对的,但地图上的 marker 落点还是不准
只要出现“相对形状差不多,但整体平移”的症状,优先怀疑坐标系,不要先怀疑样式、缩放或 icon anchor。
根因
Travel 照片元数据里保存的是 EXIF 原始 GPS:
gps.latitudegps.longitudegps.coordsys: 'gps'
这套值本身是原始卫星坐标来源,和高德底图渲染使用的坐标系不是同一套。
当前项目里,照片元数据脚本在做高德逆地理编码时,已经明确把这批坐标声明成 coordsys: 'gps',所以地址文本可以是对的。
但如果前端把这组原始 GPS 直接传给:
new AMap.Marker({ position: [lng, lat] })map.setCenter([lng, lat])map.setZoomAndCenter(zoom, [lng, lat])
那 marker 会直接画在高德底图上,结果就是整片侧漂。
结论:
- 经纬度顺序
[lng, lat]可能是对的 - 但只要没做坐标系转换,点位仍然会漂
这次项目里具体错在哪
错误链路是这样的:
- 从照片 EXIF 提取出原始 GPS
- 把原始 GPS 存进
travelPhotoMetadata.generated.json - 生成 Travel 地图数据时继续直接使用这组原始 GPS
- 前端渲染 marker 时,直接把原始 GPS 喂给高德 JSAPI
其中第 4 步就是问题核心。
正确做法
原则只有一条:
- 原始 GPS 可以保留在数据层
- 但在高德底图上渲染前,必须先转换成高德可直接使用的坐标
在当前项目里,统一修复方式是:
- 保留
travelPhotoMetadata.generated.json里的原始gps - 生成
travelMap.generated.json时继续保 留原始点位,不在生成阶段硬改 - 前端真正渲染地图前,调用高德官方
AMap.convertFrom(..., 'gps') - 用转换后的点位再去创建
Marker、设置地图中心和fit view
这样做的好处是:
- 元数据仍然保持原始、可追溯
- 前端渲染逻辑集中处理坐标系,不会污染别的用途
- 后续换别的地图 SDK 时,仍然能从原始 GPS 出发重新转换
当前仓库里的落地位置
这次修复已经收敛到下面几处:
- shared.js
这里新增了批量
gps -> 高德坐标转换 helper,内部统一调用AMap.convertFrom(..., 'gps') - TravelStoryMap.js 文章页地图在创建 marker 前,先转换照片点位
- TravelOverviewMap.js 分类总览地图在创建地点 marker 前,先转换地点点位
以后如果再新增高德地图组件,优先复用这套 helper,不要重新各写一份转换逻辑。
禁止事项
以后在这个仓库里,下面这些做法都视为错误:
- 直接把
record.gps.latitude / record.gps.longitude传给高德 marker - 直接把 EXIF 原始 GPS 用来
setCenter或setZoomAndCenter - 看到点位侧漂后,只去调 icon anchor、offset、zoom 或容器样式
- 在生成脚本里偷偷把原始 GPS 覆盖成不明来源的“修正值”
- 没确认坐标系之前,就断言是“高德地图不准”
排查顺序
以后再遇到类似问题,固定按下面顺序排查:
- 看数据里保存的坐标系是不是原始 GPS
- 看高德逆地理编码时有没有显式传
coordsys: 'gps' - 看前端渲染前有没有调用
AMap.convertFrom(..., 'gps') - 确认传给 marker 的顺序仍然是
[lng, lat] - 转换后如果仍有个别小误差,再考虑手机 GPS 精度、楼宇遮挡、多路径反射
不要跳步骤。
如何判断已经修好
修好之后,应该看到的是:
- 整组点位不再整体平移到道路另一侧
- 点位能大致压在真实拍摄街区、景区或建筑群上
- 剩余误差如果存在,通常是单点级的小偏差,而不是整组统一偏移
如果“整组还是往同一个方向整体偏”,说明转换链路仍然有问题。
一句话规则
以后在这个项目里接高德地图时,永远先问自己一句:
这组坐标是原始 GPS,还是已经转成高德可直接渲染的坐标?
如果答案不明确,就不能直接画点。