Mapbox fitbounds() - Invalid LngLat object: (NaN, NaN)
Asked Answered
B

7

7

I have been banging my head against the desk for the last few hours.

I am trying to get Mapbox to zoom in on load to the bounding area of all my markers.

However, this is the error I am getting for the code below.

This error comes after the console log image below, so the lat lng coordinates are definitely there.

Uncaught Error: Invalid LngLat object: (NaN, NaN)

  const onLoad = () => {

    let points = [];

    props.cats.forEach(cat => (
      points.push([ cat.lat, cat.lng ])
    ));

    points.length > 0 && ref.current.getMap().fitBounds(points, {
      padding: { top: 50, bottom: 50, left: 50, right: 50 },
      easing(t) {
          return t * (2 - t);
      },
    });

  };

Console log of points

Bakken answered 23/7, 2020 at 14:20 Comment(1)
The official issue on Mapbox GitHub: github.com/mapbox/mapbox-gl-js/issues/10476Nerissa
T
5

If you have more than a pair of coordinates, you should first reduce the array with coordinates.reduce, and then define the bounds through new mapboxgl.LngLatBounds. After that you can fly with map.fitBounds to the bounds, defining your favorite padding and easing function as you did in your code.

var coordinates = points;

var bounds = coordinates.reduce(function(bounds, coord) {
  return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));

map.fitBounds(bounds, {
  padding: { top: 50, bottom: 50, left: 50, right: 50 },
  easing(t) {
      return t * (2 - t);
  }
});

I have prepared this fiddle with the solution how to fit bounds to a list of coords with an array of 3 coords, but you can apply easily to yours.

And this is the result enter image description here

Then tap on Zoom to bounds enter image description here

Theran answered 23/7, 2020 at 15:40 Comment(0)
R
13

In my case, I was getting the same error when the padding value was high.

//this did not work
map.fitBounds(fitBounds, {padding: 150});
    
//this worked
map.fitBounds(fitBounds);
Regenerator answered 17/8, 2021 at 11:17 Comment(1)
Thank you! The issue for me was that the padding I was setting didn't fit the height of the map. E.g. If the map has height/width 200px, then padding should be less than 100px.Rectus
T
5

If you have more than a pair of coordinates, you should first reduce the array with coordinates.reduce, and then define the bounds through new mapboxgl.LngLatBounds. After that you can fly with map.fitBounds to the bounds, defining your favorite padding and easing function as you did in your code.

var coordinates = points;

var bounds = coordinates.reduce(function(bounds, coord) {
  return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));

map.fitBounds(bounds, {
  padding: { top: 50, bottom: 50, left: 50, right: 50 },
  easing(t) {
      return t * (2 - t);
  }
});

I have prepared this fiddle with the solution how to fit bounds to a list of coords with an array of 3 coords, but you can apply easily to yours.

And this is the result enter image description here

Then tap on Zoom to bounds enter image description here

Theran answered 23/7, 2020 at 15:40 Comment(0)
P
1

For the fitBounds() function you will need to pass your bounds as a LngLatBounds object, an array of LngLatLike objects in [South West, North East] order, or an array of numbers in [west, south, east, north] order. Mapbox has an example of this on their website here.

If you want to capture all of your markers you could calculate the most western, southern, eastern, and northern values of your coordinates and then pass them as an array. In your case: [-0.54664079, 51.38542169, -0.3735228, 51.45368209].

    mapboxgl.accessToken = 'pk.eyJ1IjoicGxtYXBib3giLCJhIjoiY2s3MHkzZ3VnMDFlbDNmbzNiajN5dm9lOCJ9.nbbtDF54HIXo0mCiekVxng';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40],
zoom: 9
});
 
document.getElementById('fit').addEventListener('click', function() {
map.fitBounds([-0.54664079, 51.38542169, -0.3735228, 51.45368209]);
});
    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }
#fit {
  display: block;
  position: relative;
  margin: 0px auto;
  width: 50%;
  height: 40px;
  padding: 10px;
  border: none;
  border-radius: 3px;
  font-size: 12px;
  text-align: center;
  color: #fff;
  background: #ee8a65;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fit a map to a bounding box</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />

</head>
<body>

<div id="map"></div>
<br />
<button id="fit">Fit to Box</button>

 
</body>
</html>
Patrol answered 23/7, 2020 at 15:36 Comment(0)
E
1

one option is to find the maximum lng and lat for north east and minimum lng and lat for south west like


function buildBounds(cords) {
    const allLats = [];
    const allLngs = [];
    cords.forEach((cord) => {
        allLats.push(cord.lat);
        allLngs.push(cord.lng);
    });
    const ne = [Math.max(...allLngs), Math.max(...allLats)];
    const sw = [Math.min(...allLngs), Math.min(...allLats)];
    console.log(ne, sw);
    return [sw, ne];
}



Elbow answered 9/2, 2023 at 17:48 Comment(0)
N
1

This answer gave the clue to the padding problem.

Here is a Typescript function that will try to fitBounds and then try again without the padding set with map.setPadding before finally giving up.

/**
 * Wraps `map.fitBounds` in an attempt to try a different padding
 * that might work when the screen is tiny, before finally giving up
 * in a way that doesn't crash.
 */
export function fitBounds(
  map: mapboxgl.Map,
  ...args: Parameters<mapboxgl.Map['fitBounds']>
): ReturnType<mapboxgl.Map['fitBounds']> | undefined {
  try {
    return map.fitBounds(...args)
  } catch (exc) {
    console.warn("Bounds didn't fit, trying without padding")
  }

  try {
    const [bounds, params, ...remainder] = args
    const padding = map.getPadding()

    return map.fitBounds(bounds, {
      ...params,
      // This is added to the existing padding you set with
      // map.setPadding
      padding: {
        left: -padding.left,
        top: -padding.top,
        bottom: -padding.bottom,
        right: -padding.right,
      },
      ...remainder,
    })
  } catch (exc) {
    console.warn("Bounds still didn't fit, giving up, need a bigger screen")
  }

  return undefined
}
Neddra answered 14/4, 2023 at 3:35 Comment(0)
M
0

I don't know this is relevant with your problem but when I get this error in mobile browsers on my map work, I solved problem with this code:

if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i.test(navigator.userAgent)) { 
$('#mapContainer').css({ 'width': (($(window).width())) + 'px' }); 
}

#mapContainer width was 100% on default.

Marielamariele answered 22/8, 2020 at 9:36 Comment(0)
L
0

SOLUTION The actual only valid solution I found is:

if(bounds._ne.distanceTo(bounds._sw) > 0)
    map.fitBounds(bounds, { padding: 50 });
Lobbyism answered 13/12, 2023 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.