Atlaslog / Field Notes / Coordinates & projections
Field note · Coordinates & projections
3857 metre values passed as lat/lng make markers vanish
Quick answer
The API returns Web Mercator metres such as 13522390, 3669872, but the code passes them to L.marker as latitude and longitude. The view jumps toward the Arctic, the marker is off-screen, and nothing is logged.
Symptom
- L.marker([3669872, 13522390]) sends the view to the North Pole as soon as you zoom, and no marker is visible.
- In OpenLayers, new ol.geom.Point([13522390, 3669872]) on a layer declared EPSG:4326 renders at longitude 13522390 degrees, far outside the view.
- map.fitBounds on the layer produces impossible bounds, yet the console stays silent.
Checklist
- Open the network panel and read the raw coordinate values in the response, not the rendered position.
- Compare both numbers with plus/minus 180 and plus/minus 90; anything outside is not a degree value.
- Look for srs, crs, epsg or spatialReference metadata in the response or the endpoint URL.
- Judge magnitude: China in EPSG:3857 has x 7.3e6~1.5e7 and y 2.4e6~6.1e6, so six- and seven-digit integers mean metres.
- Unproject once and check that the result falls inside Shanghai.
Fix
Unproject the whole GeoJSON before it reaches the render layer, e.g. proj4('EPSG:3857', 'EPSG:4326', [13522390, 3669872]) or L.CRS.EPSG3857.unproject(point); better still, have the server emit 4326 only.
Code
const p = L.CRS.EPSG3857.unproject(L.point(13522390, 3669872));
// => LatLng(31.2304, 121.4737)
L.marker(p).addTo(map);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); });
Watch out
- Calling map.setView with the metre values and blaming the tile layer for the blank map.
- Registering the data as EPSG:3857 but leaving the layer projection at 4326, so OpenLayers never reprojects.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). 3857 metre values passed as lat/lng make markers vanish. https://www.jingweizhi.com/en/cookbook/epsg3857-as-4326.html (accessed 2026-11-03).