经纬志
首页 / 实战手册 / 坐标与投影

把 CRS 改成 EPSG:4326,中国版图被压扁了

先看结论

为了「让坐标直出度」,把地图 CRS 换成 4326,结果圆变成了椭圆,省界也矮了一截。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

初始化写成 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 km100%
30°96.4 km86.6%
40°85.3 km76.6%
50°71.6 km64.3%

排查过程

  1. 画一个已知边长的正方形(例如 1 km × 1 km 的矩形缓冲区),在屏幕上量宽高。
  2. 用 map.options.crs.code 打印当前 CRS,确认是 EPSG:4326 还是 EPSG:3857。
  3. 在 moveend 里取 map.getSize() 和 map.getBounds(),算像素/度,看两个方向是否相等。
  4. 换回默认 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

适用版本

库版本说明
Leaflet1.x默认 L.CRS.EPSG3857,EPSG4326 需显式指定瓦片参数
OpenLayers6.x ~ 9.xView 的 projection 为 4326 时同样失真
Mapbox GL JS2.x / 3.x固定 3857,不支持切换
引用本文

经纬志(2026)。《把 CRS 改成 EPSG:4326,中国版图被压扁了》。https://www.jingweizhi.com/cookbook/leaflet-4326-stretch.html(访问日期 2026-11-03)。