Martin J
Martin J

Reputation: 2159

Maximum latitude map panning with leaflet

I am new to leaflet and I want the restrict the panning of a world map horizontally and not vertically (longitude but not latitude) because this map will display pictures when I click on them and I cant see well the image when i restrict the panning horizontally AND vertically. The map by itself it not a picture, it's a real world map. But when I click on certain location, a small picture will appear on the map.

I try to play with maxBounds and setMaxbounds. The normal maxBounds (to view the world map) is :

maxBounds: [[-85, -180.0],[85, 180.0]],

When i try to put the latitude to

[[-150, -180.0],[150, 180.0]]

, the vertical panning is still restricted. Can somebody help please? Thank you.

Upvotes: 0

Views: 3422

Answers (1)

IvanSanchez
IvanSanchez

Reputation: 19069

This sounds similar to a (quite obscure) issue in the Leaflet issue tracker a while back: see https://github.com/Leaflet/Leaflet/issues/3081

However, that issue was dealing with infinite horizontal bounds, not vertical bounds in a CRS that already has some preset limits.

If you set the map's maxBounds to a value larger than 85 (the value for MAX_LATITUDE of L.Projection.Spherical) and run a debugger, the call stack goes through the map's _panInsideMapBounds(), then panInsideBounds(), then _limitCenter(), then _getBoundsOffset, then project(), then through the map CRS's latLngToPoint, then untimately L.Projection.Spherical's project(). L.Projection.Spherical.project() projects the bounds' limits into pixel coordinates, and clamps the projected point to be inside the projection's limits.

There are a lot of reasons behind this, one of them being to prevent users from putting markers outside the area covered with tiles:

screenshot clamping markers

(This is particularly important when a user confuses lat-lng with lng-lat and tries to use a value outside the [-90,90] range for latitude, and the projection code starts returning Infinity values everywhere)

How to get around this? Well, we can always specify the map's CRS, and we can create a CRS with a hacked projection which enforces a different limit. Please be aware that this changes how the pixelOrigin works internally (as explained in the Leaflet tutorial about extending layers), so stuff (particularly plugins) might break.

So something like:

var hackedSphericalMercator = L.Util.extend(L.Projection.SphericalMercator, {
  MAX_LATITUDE: 89.999
});

var hackedEPSG3857 = L.Util.extend(L.CRS.EPSG3857, {
  projection: hackedSphericalMercator
});

var map = new L.Map('mapcontainer', {
    crs: hackedEPSG3857,
});

Of course, then you can set up your own maxBounds:

var map = new L.Map('mapcontainer', {
    crs: hackedEPSG3857,
    maxBounds: [[-Infinity, -10], [Infinity, 10]]
});

In this case, the bounds' limits would still be clamped to hackedSphericalMercator.MAX_LATITUDE, but you should have enough wiggle room for your application.


As a side note: A radically different approach to this problem would be to use a different map projection. We're used to a spherical cylindrical projection, but that's not the only way to flatten the earth.

In particular, a Transverse Mercator projection (or pretty much any other transverse cylindrical projection, for that matter) works pretty much in the same way, but wraps vertically instead of horizontally, and it's the projected longitudes, not latitudes, the ones which approach infinity asymptotically when approaching the [-180, 180] range. Let me borrow an image from its wikipedia article:

transverse spherical projection diagram

This implies a different set of challenges (namely finding some raster tiles appropriate for your application, including which prime meridian to use, and making proj4leaflet play nice), but it's definitely doable.

Upvotes: 4

Related Questions