Atlaslog / Field Notes / Loading & display
Field note · Loading & display
Polygon crossing the antimeridian renders as a band across the whole globe
Quick answer
A Fiji EEZ polygon lists longitudes from 177.3 down to -178.2. GeoJSON has no wraparound, so the renderer joins 179.5 straight to -179.5 across the map, and turf.area reports 4.9e14 square metres instead of about 1.1e12.
Symptom
- The polygon becomes a thin band spanning the full map width and cutting through Africa.
- turf.area returns about 4.9e14 square metres against a real area of roughly 1.1e12, two orders of magnitude off.
- The feature bbox is close to 360 degrees wide.
Checklist
- Scan consecutive vertices of the ring and log any pair whose longitude difference exceeds 180; the page shows [179.5, -16.8] followed by [-179.5, -16.9], a jump of 359.
- Check the feature bbox width; a value near 360 degrees confirms an antimeridian crossing.
- Compare turf.area with the known area; a result two orders of magnitude too large confirms it.
- Check whether the source came from a Shapefile, which also cannot represent crossing rings.
- Split the ring at the antimeridian, then re-measure and compare.
Fix
Unwrap the ring by shifting each vertex by plus or minus 360 until the step from the previous vertex stays within 180, then emit two polygons: one translated +360 for the western half and one translated -360 for the eastern half. The sum of turf.area over both halves should come back near 1.1e12 square metres.
Code
const ring = f.geometry.coordinates[0];
for (let i = 1; i < ring.length; i++) {
const d = Math.abs(ring[i][0] - ring[i - 1][0]);
if (d > 180) console.log('跨线点对', ring[i - 1], ring[i], d);
}
// [179.5, -16.8] [ -179.5, -16.9] d = 359function unwrapRing(ring) {
let prev = ring[0][0];
return ring.map(([x, y], i) => {
let nx = x;
if (i > 0) {
while (nx - prev > 180) nx -= 360;
while (nx - prev < -180) nx += 360;
}
prev = nx;
return [nx, y];
});
}
const u = unwrapRing(ring);
const left = u.map(([x, y]) => [x < 0 ? x + 360 : x, y]);
const right = u.map(([x, y]) => [x > 180 ? x - 360 : x, y]);
const polys = [left, right].map(r => ({
type: 'Feature',
properties: f.properties,
geometry: { type: 'Polygon', coordinates: [r] }
}));
Watch out
- Shifting every negative longitude by +360, which keeps the ring continuous but moves it outside the basemap tile range.
- Trying to solve it with a renderer option: Leaflet and Mapbox GL both treat geometry as planar, so the split has to happen in the data.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). Polygon crossing the antimeridian renders as a band across the whole globe. https://www.jingweizhi.com/en/cookbook/antimeridian-polygon.html (accessed 2026-11-03).