48

Is there a way to limit panning out of the world's edge? On this picture, brown is the world, grey is emptiness. I want to make it impossible to pan like this.

out of this world

approxiblue
  • 6,982
  • 16
  • 51
  • 59
Terion
  • 2,396
  • 3
  • 28
  • 42
  • This is possible, check out this thread: http://stackoverflow.com/questions/17187161/bounding-view-of-a-leaflet-js-image-map-to-a-landscape-viewport – chrki Mar 04 '14 at 10:13
  • 1
    Thank you! But is it possible to make it not to go back after panning over limits, but to make it block panning when reaching limits? – Terion Mar 04 '14 at 13:45

3 Answers3

62

Leaflet allows you to control how much the map resists being dragged out of bounds with the maxBoundsViscosity option (value: 0 to 1). Setting it to maximum disables dragging out of bounds entirely.

var map = new L.Map('map', {
  center: bounds.getCenter(),
  zoom: 5,
  layers: [osm],
  maxBounds: bounds,
  maxBoundsViscosity: 1.0
});

This feature is available in 1.0.0. The relevant pull request includes a working example:

var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
  osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
  osm1 = L.tileLayer(osmUrl, {
    maxZoom: 18,
    attribution: osmAttrib
  }),
  osm2 = L.tileLayer(osmUrl, {
    maxZoom: 18,
    attribution: osmAttrib
  }),
  bounds = new L.LatLngBounds(new L.LatLng(49.5, -11.3), new L.LatLng(61.2, 2.5));

var map1 = new L.Map('map1', {
  center: bounds.getCenter(),
  zoom: 5,
  layers: [osm1],
  maxBounds: bounds,
  maxBoundsViscosity: 0.75
});

var map2 = new L.Map('map2', {
  center: bounds.getCenter(),
  zoom: 5,
  layers: [osm2],
  maxBounds: bounds,
  maxBoundsViscosity: 1.0
});

var latlngs = L.rectangle(bounds).getLatLngs();
L.polyline(latlngs[0].concat(latlngs[0][0])).addTo(map1);
L.polyline(latlngs[0].concat(latlngs[0][0])).addTo(map2);
html,
body,
#map {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.0.0/dist/leaflet.js"></script>

<h1>Left: Bouncy maxBounds. Right: Not bouncy.</h1>

<div id="map1" style="float: left; width:45%; height: 80%;"></div>
<div id="map2" style="float: left; width:45%; height: 80%;"></div>
approxiblue
  • 6,982
  • 16
  • 51
  • 59
  • Is this option still working ? I am not able to do something similar with mapbox – gsuresh92 Jul 29 '16 at 12:37
  • @gsuresh92 Not for mapbox. At this point [mapbox is using leaflet 0.7.7](https://github.com/mapbox/mapbox.js/blob/34e4610dcca34152188b1a57cb4d3dab0db00a96/package.json), but this feature is in 1.0-beta1 and later. – approxiblue Jul 29 '16 at 14:29
  • I didn't downvote, but this doesn't seem to work in rc3. – catbadger Sep 20 '16 at 20:06
  • @catbadger Thanks. Looks like they refactored and [moved that option](https://github.com/Leaflet/Leaflet/pull/4449). The [debug example](https://github.com/Leaflet/Leaflet/blob/3a2106b2cc16b4a1f722e92c93c19552a6c4de57/debug/map/max-bounds-bouncy.html) for that option no longer works though; I'll check to see if it's a regression or not. – approxiblue Sep 20 '16 at 20:28
  • @catbadger I was mistaken, looks like the [debug example for rc3](https://github.com/Leaflet/Leaflet/blob/v1.0.0-rc.3/debug/map/max-bounds-bouncy.html) still works. Is this what you expect? – approxiblue Sep 22 '16 at 02:06
33

This is how I resolved it for the world map

var map = L.map('map').setView([51.505, -0.09], 3);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map);

var southWest = L.latLng(-89.98155760646617, -180),
northEast = L.latLng(89.99346179538875, 180);
var bounds = L.latLngBounds(southWest, northEast);

map.setMaxBounds(bounds);
map.on('drag', function() {
    map.panInsideBounds(bounds, { animate: false });
});

See working example both for version .7.0.7 http://jsfiddle.net/exqar2w4/18/ and for version 1.0.3 http://jsfiddle.net/exqar2w4/20/

rob.m
  • 9,843
  • 19
  • 73
  • 162
14

I use react-leaflet so syntax slightly different to above, but thought it would be helpful to show some sensible bounds to use (none of the answers above do that).

import Leaflet from 'leaflet'
import { Map as LeafletMap} from 'react-leaflet'

// Set map bounds.
// Allow scroll over the international date line, so users can comfortably zoom into locations near the date line.
const corner1 = Leaflet.latLng(-90, -200)
const corner2 = Leaflet.latLng(90, 200)
const bounds = Leaflet.latLngBounds(corner1, corner2)

Which is then rendered as...

<LeafletMap
  maxBoundsViscosity={1.0}
  maxBounds={bounds}
  {...otherProps}
>
thclark
  • 4,784
  • 3
  • 39
  • 65