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

把 3857 的米值当经纬度传入,标记点直接消失

先看结论

接口返回 13522390, 3669872,塞进 L.marker 后地图一 zoom 就飞到北极,标记也不见了。

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

现象

上海点位在 EPSG:3857 下是 x ≈ 13522390, y ≈ 3669872(米)。 直接写成 L.marker([3669872, 13522390]) 后: 地图要么瞬间缩放到最北边,要么整张图空白,控制台没有任何报错。

OpenLayers 里表现不同:new ol.Feature(new ol.geom.Point([13522390, 3669872])) 如果图层的 projection 声明为 EPSG:4326,点会被渲染到经纬度 13522390°,超出视野,同样看不见。

原因

Leaflet 的 L.latLng(lat, lng) 期望入参是度,内部再乘 1/111319.49 投影到像素。传入 3669872 这个数值,等于声称纬度 3669872°,远超 ±90°, 墨卡托投影把它夹到 85.0511°,于是地图定位到北极圈附近。

判断依据是数量级:经纬度经度范围 -180~180,纬度 -90~90; EPSG:3857 的 x 范围 ±20037508.34,y 同范围,中国区域的 x 在 7.3e6~1.5e7,y 在 2.4e6~6.1e6。只要看到六七位整数,就是米,不是度。

坐标系上海示例数值量级
EPSG:4326121.473701, 31.230416个位到三位
EPSG:385713522390, 3669872百万到千万
EPSG:4547(高斯 3 度带)500000, 3458000 左右十万到百万

排查过程

  1. 打开网络面板,看接口响应里坐标的原始数值,不要看地图上渲染后的结果。
  2. 把第一个坐标和第二个坐标分别与 ±180 / ±90 比较。任一超出,就不是经纬度。
  3. 在接口地址或响应字段里找 srs、crs、epsg、spatialReference 之类的元数据。
  4. 仍不确定时,用反投影算一遍,结果落在上海市范围内即可确认是 3857。
// Leaflet 内置反投影,直接把米转回经纬度
const p = L.CRS.EPSG3857.unproject(L.point(13522390, 3669872));
// => LatLng(31.2304, 121.4737)

L.marker(p).addTo(map);

解决方案

在数据进入渲染层之前统一反投影,而不是在渲染层逐个打补丁。 用 proj4js 可以一次性处理整份 GeoJSON。

// proj4js:3857 -> 4326 批量转换
const src = 'EPSG:3857', dst = 'EPSG:4326';

function reprojectGeometry(geom, fn) {
  if (geom.type === 'Point') return { ...geom, coordinates: fn(geom.coordinates) };
  if (geom.type === 'LineString' || geom.type === 'MultiPoint')
    return { ...geom, coordinates: geom.coordinates.map(fn) };
  if (geom.type === 'Polygon' || geom.type === 'MultiLineString')
    return { ...geom, coordinates: geom.coordinates.map(r => r.map(fn)) };
  return { ...geom, coordinates: geom.coordinates.map(p =>
    p.map(r => r.map(fn))) };
}

const fn = c => proj4(src, dst, c);
fc.features.forEach(f => { f.geometry = reprojectGeometry(f.geometry, fn); });

如果服务端可控,优先让服务端直接输出 4326(GeoJSON 的 RFC 7946 也只允许 4326), 前端就不需要承担投影转换的职责。

验证

转换后上海点应为 121.4737, 31.2304,纬度落在 31 附近,经度落在 121 附近; 用 map.fitBounds 能正常框住数据,不再跳到北极。

const ll = L.CRS.EPSG3857.unproject(L.point(13522390, 3669872));
console.assert(Math.abs(ll.lat - 31.2304) < 0.001, '纬度不对');
console.assert(Math.abs(ll.lng - 121.4737) < 0.001, '经度不对');

适用版本

库版本说明
Leaflet1.7 ~ 1.9L.CRS.EPSG3857.unproject 可直接用
OpenLayers6.x ~ 9.x数据需声明 projection,否则不参与重投影
proj4js2.9 及以上3857 与 4326 已内置,无需 defs
Cesium1.100 及以上WebMercatorTilingScheme 同样以米计
引用本文

经纬志(2026)。《把 3857 的米值当经纬度传入,标记点直接消失》。https://www.jingweizhi.com/cookbook/epsg3857-as-4326.html(访问日期 2026-11-03)。