Projection
把经纬度换算成平面坐标的投影实现,Leaflet 自带三种,均以 project / unproject 两个方法暴露。
内置投影
| 投影 | 输出单位 | 说明 |
|---|---|---|
L.Projection.LonLat | 度 | 不做投影,经纬度直接当平面坐标,适合小范围平面图 |
L.Projection.SphericalMercator | 米 | 球面墨卡托,把地球当正球体,公式比椭球简单 |
L.Projection.Mercator | 米 | 椭球墨卡托,带偏心率修正,EPSG:3395 使用 |
三个对象都有 project、unproject 与 bounds。
bounds 是投影平面上的有效范围,单位与输出一致。
方法
| 方法 | 返回 | 说明 |
|---|---|---|
project(latlng) | Point | 经纬度 → 平面坐标 |
unproject(point) | LatLng | 平面坐标 → 经纬度 |
bounds | Bounds | 投影能表达的范围,超出后结果失真 |
常量与极值处理
| 常量 | 所属 | 值 | 含义 |
|---|---|---|---|
R | 两者都有 | 6378137 | 长半轴,单位米 |
R_MINOR | Mercator | 6356752.314245179 | 短半轴,用于计算偏心率 |
MAX_LATITUDE | SphericalMercator | 85.0511287798 | 可表达的最大纬度 |
bounds | 两者都有 | Bounds | 投影平面上的有效范围 |
SphericalMercator 在 project 里把纬度钳制到 ±MAX_LATITUDE;
Mercator 没有这个常量,改用 log 输入的下限避免在极点附近发散。
两种实现在极区都只能给出示意结果。
一次投影与反投影
var latlng = L.latLng(39.907359, 116.391263);
var meters = L.Projection.Mercator.project(latlng);
console.log(meters.x, meters.y); // 单位米
var back = L.Projection.Mercator.unproject(meters);
console.log(back.equals(latlng)); // true
/* 纬度接近极区时先钳制,再投影 */
var safe = L.latLng(
Math.max(-85, Math.min(85, latlng.lat)),
latlng.lng
);
反投影的误差在浮点范围内,equals 能通过;
用 distanceTo 比较时不要期望严格为零。
两种墨卡托的差别
SphericalMercator 假设地球是正球,公式只有 log(tan(π/4 + φ/2));
Mercator 额外引入偏心率 e,在纬度 40 度附近两者纵坐标相差数十公里。
瓦片底图几乎都是 EPSG:3857,它使用球面公式;
需要与 EPSG:3395 数据对齐时才用椭球版本。
| CRS | 使用的投影 | 常见来源 |
|---|---|---|
EPSG:3857 | SphericalMercator | OSM、天地图、多数在线瓦片 |
EPSG:3395 | Mercator | 部分海外商业地图 |
EPSG:4326 | LonLat | 直接以经纬度出图的场景 |
投影不等于坐标转换
投影只处理「同一基准面下的球面到平面」。 国内常见的 GCJ-02 偏移属于基准面与加密算法问题,投影层不解决, 需要先用独立算法把坐标纠偏,再交给 Leaflet。
不要手写 lat * 20037508 / 180 之类的近似。
project 已包含钳制与偏心率处理,近似公式在纬度 60 度以上偏差迅速放大。
需要平面坐标时直接调用投影对象。
经纬志(2026)。《Projection》。https://www.jingweizhi.com/leaflet/api/projection.html(访问日期 2026-11-03)。