@@ -381,11 +381,60 @@ function computeBbox(d) {
381381 return turfBbox ( d ) ;
382382}
383383
384+ /**
385+ * Pick a compact longitude range for `fitbounds`-style auto-framing when the
386+ * data straddles the antimeridian (±180°).
387+ *
388+ * Longitude is cyclic, so the naive [min, max] range used by the autorange
389+ * machinery can include a large empty span when points sit on both sides of
390+ * ±180° (e.g. lon = [131.8855, -179] spans ~311° the long way round, when the
391+ * compact view spans ~49° across the antimeridian). This finds the largest gap
392+ * between consecutive longitudes and, when that gap is wider than the gap across
393+ * the antimeridian, returns the complementary range so the map shows the dense
394+ * cluster of points rather than the empty ocean between them.
395+ *
396+ * The returned upper bound may exceed 180°; downstream `makeRangeBox` (and
397+ * MapLibre's `LngLatBounds`) handle ranges that cross the antimeridian without
398+ * ambiguity.
399+ *
400+ * @param {Array } lons - longitude values (may contain non-finite entries)
401+ * @return {Array|null } [lonStart, lonEnd] when an antimeridian-crossing range is
402+ * more compact, otherwise null (caller keeps the autorange result).
403+ */
404+ function getFitboundsLonRange ( lons ) {
405+ const sorted = lons . filter ( isFinite ) . sort ( ( a , b ) => a - b ) ;
406+ if ( sorted . length < 2 ) return null ;
407+
408+ const n = sorted . length ;
409+ const naiveSpan = sorted [ n - 1 ] - sorted [ 0 ] ;
410+ // Data already wraps the whole globe; there is nothing to compact.
411+ if ( naiveSpan >= 360 ) return null ;
412+
413+ // Widest gap between consecutive longitudes.
414+ let maxGap = - Infinity ;
415+ let gapStart = - 1 ;
416+ for ( let i = 0 ; i < n - 1 ; i ++ ) {
417+ const gap = sorted [ i + 1 ] - sorted [ i ] ;
418+ if ( gap > maxGap ) {
419+ maxGap = gap ;
420+ gapStart = i ;
421+ }
422+ }
423+
424+ // Only worth wrapping when an interior gap is wider than the gap that the
425+ // naive [min, max] range already leaves open across the antimeridian.
426+ const antimeridianGap = 360 - naiveSpan ;
427+ if ( maxGap <= antimeridianGap ) return null ;
428+
429+ return [ sorted [ gapStart + 1 ] , sorted [ gapStart ] + 360 ] ;
430+ }
431+
384432module . exports = {
385- locationToFeature : locationToFeature ,
386- feature2polygons : feature2polygons ,
387- getTraceGeojson : getTraceGeojson ,
388- extractTraceFeature : extractTraceFeature ,
389- fetchTraceGeoData : fetchTraceGeoData ,
390- computeBbox : computeBbox
433+ locationToFeature,
434+ feature2polygons,
435+ getTraceGeojson,
436+ extractTraceFeature,
437+ fetchTraceGeoData,
438+ computeBbox,
439+ getFitboundsLonRange
391440} ;
0 commit comments