把 CRS 改成 EPSG:4326,中国版图被压扁了
为了「让坐标直出度」,把地图 CRS 换成 4326,结果圆变成了椭圆,省界也矮了一截。
现象
初始化写成 L.map('map', { crs: L.CRS.EPSG4326 }),
底图换成按度切片的瓦片后,长江中下游的省界看起来明显横向拉长;
一个理论上正圆形的 1 公里缓冲区,屏幕上量出来宽高比约为 1.30。
在北京(北纬 39.9°)附近,同一条南北向的 10 公里道路, 在 4326 下的屏幕长度只有在 3857 下的 76.7%。
原因
L.CRS.EPSG4326 用一个统一的缩放因子 1/111319.49 同时处理经度和纬度,
即 1 度经差和 1 度纬差占同样多的像素,这叫等经纬度(plate carrée)投影。
但实地 1 度经差的长度随纬度收缩:111320·cos(lat)。
北纬 40° 处只有 85.3 公里,是 1 度纬差的 cos(40°)=0.766。
把两个方向画成等长,等于把纵向压扁到 76.6%,圆自然变成横椭圆。
L.CRS.EPSG3857 用的是墨卡托,纵向按 sec(lat) 拉伸,
正好抵消这个收缩,所以在中低纬度上形状是保角的。这也是 Leaflet 默认用它的原因。
| 纬度 | 1° 经差实地长度 | 4326 下纵向比例 |
|---|---|---|
| 0° | 111.3 km | 100% |
| 30° | 96.4 km | 86.6% |
| 40° | 85.3 km | 76.6% |
| 50° | 71.6 km | 64.3% |
排查过程
- 画一个已知边长的正方形(例如 1 km × 1 km 的矩形缓冲区),在屏幕上量宽高。
- 用
map.options.crs.code打印当前 CRS,确认是EPSG:4326还是EPSG:3857。 - 在
moveend里取map.getSize()和map.getBounds(),算像素/度,看两个方向是否相等。 - 换回默认 CRS 再量一次,若形状恢复正常,就是投影选择的问题。
map.on('moveend', () => {
const b = map.getBounds(), s = map.getSize();
const pxPerLon = s.x / (b.getEast() - b.getWest());
const pxPerLat = s.y / (b.getNorth() - b.getSouth());
console.log('px/度 经:', pxPerLon.toFixed(3), '纬:', pxPerLat.toFixed(3));
// EPSG:4326 下两者相等;3857 下 pxPerLat 会明显大于 pxPerLon
});
解决方案
展示用途保持默认的 EPSG:3857。确实需要等经纬度视图时(例如气象格点、全球热力图),
不要用它来承载需要保形的矢量数据。
// 默认写法,不传 crs 即为 EPSG:3857
const map = L.map('map', { center: [39.909, 116.397], zoom: 10 });
// 若底图本身是按度切片的 4326 瓦片,必须同时指定 CRS 与瓦片参数
const map4326 = L.map('map2', {
crs: L.CRS.EPSG4326,
center: [39.909, 116.397],
zoom: 5
});
L.tileLayer('https://example.com/4326/{z}/{y}/{x}.png', {
tileSize: 256,
noWrap: true,
bounds: [[-90, -180], [90, 180]]
}).addTo(map4326);
验证
用 turf 生成一个 1 km × 1 km 的矩形(turf.buffer 后取外接框),
在默认 3857 地图上屏幕宽高比应接近 1.00(误差小于 2%);
切到 4326 后宽高比会变成 1.30 左右。
const box = turf.bbox(turf.buffer(turf.point([116.397, 39.909]), 0.5, { units: 'kilometers' }));
// 4326 下屏幕宽高比 = (lon span * 111320*cos(lat)) / (lat span * 111320)
// 约等于 1/cos(39.9°) = 1.30
适用版本
| 库 | 版本 | 说明 |
|---|---|---|
| Leaflet | 1.x | 默认 L.CRS.EPSG3857,EPSG4326 需显式指定瓦片参数 |
| OpenLayers | 6.x ~ 9.x | View 的 projection 为 4326 时同样失真 |
| Mapbox GL JS | 2.x / 3.x | 固定 3857,不支持切换 |
经纬志(2026)。《把 CRS 改成 EPSG:4326,中国版图被压扁了》。https://www.jingweizhi.com/cookbook/leaflet-4326-stretch.html(访问日期 2026-11-03)。