GeoJSON 在 Web 墨卡托(EPSG:3857)下的坐标换算与精度陷阱
GeoJSON 用经纬度(WGS84)存坐标,浏览器地图却跑在 Web 墨卡托投影(EPSG:3857)上。Leaflet、高德、天地图底图,都是先把球面坐标压平,再切成瓦片。搞清楚这套换算,做自定义渲染、算距离、叠底图时能少踩几个坑。
为什么需要投影
经纬度是球面坐标,直接画会变形,格陵兰看着比非洲还大。投影把球面摊平,Web 墨卡托是 Web 地图的默认选择:把地球当正球体,按墨卡托公式展开,再用 256×256 瓦片分级。
换算公式
地球半径 R = 6378137 米:
x = R · λ (λ 是经度弧度) y = R · ln(tan(π/4 + φ/2)) (φ 是纬度弧度)
JS 里这么写:
const R = 6378137;
function lngLatToMercator(lng, lat) {
const x = R * (lng * Math.PI / 180);
const y = R * Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI / 180) / 2));
return [x, y];
}
// 反向换算:墨卡托米坐标 → 经纬度
function mercatorToLngLat(x, y) {
const lng = (x / R) * 180 / Math.PI;
const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * 180 / Math.PI;
return [lng, lat];
}
前端用这个精度够了,但它不含 WGS84 椭球修正。源数据若是 GCJ-02 偏移坐标(国内地图常这么干),记得先回偏再投影,不然跟底图错开几米到几十米。偏移坐标的取舍我们在 WGS84 与 GCJ-02 坐标系怎么选 里写过。
不同纬度的经度分辨率
同样一个像素宽,纬度越高能塞下的经度越窄:
| 纬度 | 1 像素(缩放 18 级)对应经度 |
|---|---|
| 0° | 约 0.00021° |
| 30° | 约 0.00018° |
| 60° | 约 0.00011° |
高纬度地区同样缩放下细节更密,GeoJSON 体积也跟着涨。做体积优化别光看要素数量,见 GeoJSON 体积优化七招。
落到本站数据
geojsoncn.com 上省、市、区县边界都是标准 WGS84 经纬度 GeoJSON,投影渲染交给地图库在客户端做。渲染原理看 用 Leaflet 渲染 GeoJSON 行政区,格式字段含义看 GeoJSON 格式规范与字段含义。
本站所有边界数据预览免费、下载付费:先在网页里把省/市/区县边界拖出来看效果,确认无误再付费下载对应的 GeoJSON / SVG / PNG 文件。
顺带一句:墨卡托在两极附近会发散,85.05° 以上算不出值。行政区数据基本都在 ±85° 以内,实际不用管它。