Atlaslog / Field Notes / Coordinates & projections
Field note · Coordinates & projections
Latitude 89 in Web Mercator yields Infinity and NaN tile indices
Quick answer
Web Mercator y = R*ln(tan(PI/4 + phi/2)) diverges at the poles, and EPSG:3857 is clipped at plus/minus 85.0511287798. Beyond that y exceeds 20037508 or becomes Infinity, so tile indices become NaN and the layer silently stops rendering.
Symptom
- A station at latitude -89.0 disappears in Leaflet while every other point renders.
- In OpenLayers the whole layer goes blank, but source.getFeatures().length still reports the correct count.
- A custom tile script prints NaN indices and request URLs containing undefined.
Checklist
- Run L.CRS.EPSG3857.latLngToPoint(L.latLng(-89, 0), 0) and check whether y exceeds 20037508.
- Scan the data bbox for records with abs(lat) above 85.05; usually only a handful exist.
- Check whether the tile index code validates Math.floor output with Number.isFinite.
- Remove the offending point and reload; a restored layer confirms the diagnosis.
Fix
Clamp latitude to plus/minus 85.0511287798 before projecting, and use a polar stereographic projection when polar regions must really be shown.
Code
const p = L.CRS.EPSG3857.latLngToPoint(L.latLng(-89, 0), 0);
console.log(p.y); // 3.0e7 左右,已超出 20037508
console.log(Number.isFinite(p.y)); // true,但越界
const bad = L.CRS.EPSG3857.latLngToPoint(L.latLng(-90, 0), 0);
console.log(bad.y); // Infinity
console.log(Math.floor(bad.y / 256)); // NaNconst MAX_LAT = 85.0511287798;
function clampLat(lat) {
return Math.max(-MAX_LAT, Math.min(MAX_LAT, lat));
}
function toMercator(lng, lat) {
const phi = clampLat(lat) * Math.PI / 180;
const x = lng * 20037508.34 / 180;
let y = Math.log(Math.tan(Math.PI / 4 + phi / 2)) * 6378137;
y = Math.max(-20037508.34, Math.min(20037508.34, y));
return [x, y];
}
function tileIndex(lng, lat, z) {
const [x, y] = toMercator(lng, lat);
const n = Math.pow(2, z);
const tx = Math.floor((x + 20037508.34) / (2 * 20037508.34) * n);
const ty = Math.floor((20037508.34 - y) / (2 * 20037508.34) * n);
if (!Number.isFinite(tx) || !Number.isFinite(ty)) return null;
return [tx, ty];
}
Watch out
- Clamping after projection, where y is already Infinity and no arithmetic can recover it.
- Raising maxBounds or lowering minZoom in the hope that the library will filter the point out.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). Latitude 89 in Web Mercator yields Infinity and NaN tile indices. https://www.jingweizhi.com/en/cookbook/mercator-lat-limit.html (accessed 2026-11-03).