At last, added ability to set max geographical bounds within which users can pan/zoom! Closed #93

This commit is contained in:
mourner 2011-12-02 19:04:19 +02:00
parent 0e81d29168
commit 43d87dacde
6 changed files with 130 additions and 28 deletions

View File

@ -9,6 +9,7 @@ Leaflet Changelog
* Added **Canvas backend** for vector layers (polylines, polygons, circles). This enables vector support on Android < 3, and it can also be optionally preferred over SVG for a performance gain in some cases. Thanks to [@florianf](https://github.com/florianf) for a big part of this work.
* Added **layers control** (`Control.Layers`) for convenient layer switching.
* Added ability to set max geographical bounds within which users can pan/zoom. [#93](https://github.com/CloudMade/Leaflet/issues/93)
### Improvements
@ -24,6 +25,7 @@ Leaflet Changelog
* Improved `LatLng` constructor to be more tolerant (and throw descriptive error if latitude or longitude can't be interpreted as a number). [#136](https://github.com/CloudMade/Leaflet/issues/136)
* Added `urlParams` third optional argument to `TileLayer` constructor for convenience: an object with properties that will be evaluated in the URL template.
* Added `L.Util.template` method for simple string template evaluation.
* Added second argument `inside` to `map` `getBoundsZoom` method that allows you to get appropriate zoom for the view to fit *inside* the given bounds.
* Improved `map` `locate` method, added ability to watch location continuously and more options. [#212](https://github.com/CloudMade/Leaflet/issues/212)
* Added ability to add a tile layer below all others (`map.addLayer(layer, true)`) (useful for switching base tile layers).
* Added `hasLayer` method to `Map`.

36
debug/map/max-bounds.html Normal file
View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet debug page</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="../../dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../../dist/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="../css/mobile.css" />
<script src="../leaflet-include.js"></script>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade',
cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution}),
bounds = new L.LatLngBounds(new L.LatLng(49.41097, -11.29395), new L.LatLng(62.85515, 2.50488));
var map = new L.Map('map', {
center: bounds.getCenter(),
zoom: 7,
layers: [cloudmade],
maxBounds: bounds
});
</script>
</body>
</html>

39
dist/leaflet.js vendored
View File

@ -40,22 +40,24 @@ L.LatLng.prototype={equals:function(a){if(!(a instanceof L.LatLng))return!1;retu
getCenter:function(){return new L.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new L.LatLng(this._northEast.lat,this._southWest.lng)},getSouthEast:function(){return new L.LatLng(this._southWest.lat,this._northEast.lng)},contains:function(a){var b=this._southWest,c=this._northEast,d;a instanceof L.LatLngBounds?(d=a.getSouthWest(),
a=a.getNorthEast()):d=a;return d.lat>=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng},toBBoxString:function(){var a=this._southWest,b=this._northEast;return[a.lng,a.lat,b.lng,b.lat].join(",")}});L.Projection={};L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}};L.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.3142,R_MAJOR:6378137,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=this.R_MAJOR,e=a.lng*b*d,a=Math.max(Math.min(c,a.lat),-c)*b,b=this.R_MINOR/d,b=Math.sqrt(1-b*b),c=b*Math.sin(a),c=Math.pow((1-c)/(1+c),b*0.5),a=-d*Math.log(Math.tan(0.5*(Math.PI*0.5-a))/c);return new L.Point(e,a)},unproject:function(a,b){for(var c=L.LatLng.RAD_TO_DEG,d=this.R_MAJOR,e=a.x*c/d,f=this.R_MINOR/d,f=Math.sqrt(1-f*f),d=Math.exp(-a.y/d),
g=Math.PI/2-2*Math.atan(d),h=15,j=0.1;Math.abs(j)>1.0E-7&&--h>0;)j=f*Math.sin(g),j=Math.PI/2-2*Math.atan(d*Math.pow((1-j)/(1+j),0.5*f))-g,g+=j;return new L.LatLng(g*c,e,b)}};L.CRS={latLngToPoint:function(a,b){return this.transformation._transform(this.projection.project(a),b)},pointToLatLng:function(a,b,c){return this.projection.unproject(this.transformation.untransform(a,b),c)},project:function(a){return this.projection.project(a)}};L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(0.5/Math.PI,0.5,-0.5/Math.PI,0.5),project:function(a){return this.projection.project(a).multiplyBy(6378137)}});L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"});L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,0.5,-1/360,0.5)});L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator;return new L.Transformation(0.5/(Math.PI*a.R_MAJOR),0.5,-0.5/(Math.PI*a.R_MINOR),0.5)}()});L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*Math.pow(2,a)},center:null,zoom:null,layers:[],dragging:!0,touchZoom:L.Browser.touch&&!L.Browser.android,scrollWheelZoom:!L.Browser.touch,doubleClickZoom:!0,shiftDragZoom:!0,zoomControl:!0,attributionControl:!0,fadeAnimation:L.DomUtil.TRANSITION&&!L.Browser.android,zoomAnimation:L.DomUtil.TRANSITION&&!L.Browser.android&&!L.Browser.mobileOpera,trackResize:!0,closePopupOnClick:!0,worldCopyJump:!0},
initialize:function(a,b){L.Util.setOptions(this,b);this._container=L.DomUtil.get(a);if(this._container._leaflet)throw Error("Map container is already initialized.");this._container._leaflet=!0;this._initLayout();L.DomEvent&&(this._initEvents(),L.Handler&&this._initInteraction(),L.Control&&this._initControls());var c=this.options.center,d=this.options.zoom;c!==null&&d!==null&&this.setView(c,d,!0);c=this.options.layers;c=c instanceof Array?c:[c];this._tileLayersNum=0;this._initLayers(c)},setView:function(a,
b){this._resetView(a,this._limitZoom(b));return this},setZoom:function(a){return this.setView(this.getCenter(),a)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(a){var b=this.getBoundsZoom(a);return this.setView(a.getCenter(),b)},fitWorld:function(){var a=new L.LatLng(-60,-170),b=new L.LatLng(85,179);return this.fitBounds(new L.LatLngBounds(a,b))},panTo:function(a){return this.setView(a,this._zoom)},panBy:function(a){this.fire("movestart");
this._rawPanBy(a);this.fire("move");this.fire("moveend");return this},addLayer:function(a,b){var c=L.Util.stamp(a);if(this._layers[c])return this;this._layers[c]=a;if(a.options&&!isNaN(a.options.maxZoom))this._layersMaxZoom=Math.max(this._layersMaxZoom||0,a.options.maxZoom);if(a.options&&!isNaN(a.options.minZoom))this._layersMinZoom=Math.min(this._layersMinZoom||Infinity,a.options.minZoom);this.options.zoomAnimation&&L.TileLayer&&a instanceof L.TileLayer&&(this._tileLayersNum++,a.on("load",this._onTileLayerLoad,
this));this.attributionControl&&a.getAttribution&&this.attributionControl.addAttribution(a.getAttribution());c=function(){a.onAdd(this,b);this.fire("layeradd",{layer:a})};if(this._loaded)c.call(this);else this.on("load",c,this);return this},removeLayer:function(a){var b=L.Util.stamp(a);this._layers[b]&&(a.onRemove(this),delete this._layers[b],this.options.zoomAnimation&&L.TileLayer&&a instanceof L.TileLayer&&(this._tileLayersNum--,a.off("load",this._onTileLayerLoad,this)),this.attributionControl&&
a.getAttribution&&this.attributionControl.removeAttribution(a.getAttribution()),this.fire("layerremove",{layer:a}));return this},hasLayer:function(a){return this._layers.hasOwnProperty(L.Util.stamp(a))},invalidateSize:function(){if(!this._loaded)return this;var a=this.getSize();this._sizeChanged=!0;this._rawPanBy(a.subtract(this.getSize()).divideBy(2));this.fire("move");clearTimeout(this._sizeTimer);this._sizeTimer=setTimeout(L.Util.bind(function(){this.fire("moveend")},this),200);return this},getCenter:function(a){var b=
this.getSize().divideBy(2);return this.unproject(this._getTopLeftPoint().add(b),this._zoom,a)},getZoom:function(){return this._zoom},getBounds:function(){var a=this.getPixelBounds(),b=this.unproject(new L.Point(a.min.x,a.max.y)),a=this.unproject(new L.Point(a.max.x,a.min.y));return new L.LatLngBounds(b,a)},getMinZoom:function(){return isNaN(this.options.minZoom)?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return isNaN(this.options.maxZoom)?this._layersMaxZoom||Infinity:this.options.maxZoom},
getBoundsZoom:function(a){var b=this.getSize(),c=this.getMinZoom(),d=this.getMaxZoom(),e=a.getNorthEast(),a=a.getSouthWest(),f,g;do c++,f=this.project(e,c),g=this.project(a,c),f=new L.Point(f.x-g.x,g.y-f.y);while(f.x<=b.x&&f.y<=b.y&&c<=d);return c-1},getSize:function(){if(!this._size||this._sizeChanged)this._size=new L.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1;return this._size},getPixelBounds:function(){var a=this._getTopLeftPoint(),b=this.getSize();return new L.Bounds(a,
a.add(b))},getPixelOrigin:function(){return this._initialTopLeftPoint},getPanes:function(){return this._panes},mouseEventToContainerPoint:function(a){return L.DomEvent.getMousePosition(a,this._container)},mouseEventToLayerPoint:function(a){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(a))},mouseEventToLatLng:function(a){return this.layerPointToLatLng(this.mouseEventToLayerPoint(a))},containerPointToLayerPoint:function(a){return a.subtract(L.DomUtil.getPosition(this._mapPane))},
layerPointToContainerPoint:function(a){return a.add(L.DomUtil.getPosition(this._mapPane))},layerPointToLatLng:function(a){return this.unproject(a.add(this._initialTopLeftPoint))},latLngToLayerPoint:function(a){return this.project(a)._round()._subtract(this._initialTopLeftPoint)},project:function(a,b){b=typeof b==="undefined"?this._zoom:b;return this.options.crs.latLngToPoint(a,this.options.scale(b))},unproject:function(a,b,c){b=typeof b==="undefined"?this._zoom:b;return this.options.crs.pointToLatLng(a,
this.options.scale(b),c)},_initLayout:function(){var a=this._container;a.innerHTML="";a.className+=" leaflet-container";this.options.fadeAnimation&&(a.className+=" leaflet-fade-anim");var b=L.DomUtil.getStyle(a,"position");if(b!=="absolute"&&b!=="relative")a.style.position="relative";this._initPanes();this._initControlPos&&this._initControlPos()},_initPanes:function(){var a=this._panes={};this._mapPane=a.mapPane=this._createPane("leaflet-map-pane",this._container);this._tilePane=a.tilePane=this._createPane("leaflet-tile-pane",
this._mapPane);this._objectsPane=a.objectsPane=this._createPane("leaflet-objects-pane",this._mapPane);a.shadowPane=this._createPane("leaflet-shadow-pane");a.overlayPane=this._createPane("leaflet-overlay-pane");a.markerPane=this._createPane("leaflet-marker-pane");a.popupPane=this._createPane("leaflet-popup-pane")},_createPane:function(a,b){return L.DomUtil.create("div",a,b||this._objectsPane)},_resetView:function(a,b,c){var d=this._zoom!==b;this.fire("movestart");this._zoom=b;this._initialTopLeftPoint=
this._getNewTopLeftPoint(a);c?this._initialTopLeftPoint._add(L.DomUtil.getPosition(this._mapPane)):L.DomUtil.setPosition(this._mapPane,new L.Point(0,0));this._tileLayersToLoad=this._tileLayersNum;this.fire("viewreset",{hard:!c});this.fire("move");d&&this.fire("zoomend");this.fire("moveend");if(!this._loaded)this._loaded=!0,this.fire("load")},_initLayers:function(a){this._layers={};var b,c;b=0;for(c=a.length;b<c;b++)this.addLayer(a[b])},_initControls:function(){this.options.zoomControl&&this.addControl(new L.Control.Zoom);
if(this.options.attributionControl)this.attributionControl=new L.Control.Attribution,this.addControl(this.attributionControl)},_rawPanBy:function(a){var b=L.DomUtil.getPosition(this._mapPane);L.DomUtil.setPosition(this._mapPane,b.subtract(a))},_initEvents:function(){L.DomEvent.addListener(this._container,"click",this._onMouseClick,this);var a=["dblclick","mousedown","mouseenter","mouseleave","mousemove"],b,c;b=0;for(c=a.length;b<c;b++)L.DomEvent.addListener(this._container,a[b],this._fireMouseEvent,
this);this.options.trackResize&&L.DomEvent.addListener(window,"resize",this._onResize,this)},_onResize:function(){L.Util.requestAnimFrame(this.invalidateSize,this,!1,this._container)},_onMouseClick:function(a){if(this._loaded&&(!this.dragging||!this.dragging.moved()))this.fire("pre"+a.type),this._fireMouseEvent(a)},_fireMouseEvent:function(a){if(this._loaded){var b=a.type,b=b==="mouseenter"?"mouseover":b==="mouseleave"?"mouseout":b;this.hasEventListeners(b)&&this.fire(b,{latlng:this.mouseEventToLatLng(a),
layerPoint:this.mouseEventToLayerPoint(a)})}},_initInteraction:function(){var a={dragging:L.Handler.MapDrag,touchZoom:L.Handler.TouchZoom,doubleClickZoom:L.Handler.DoubleClickZoom,scrollWheelZoom:L.Handler.ScrollWheelZoom,shiftDragZoom:L.Handler.ShiftDragZoom},b;for(b in a)a.hasOwnProperty(b)&&a[b]&&(this[b]=new a[b](this),this.options[b]&&this[b].enable())},_onTileLayerLoad:function(){this._tileLayersToLoad--;if(this._tileLayersNum&&!this._tileLayersToLoad&&this._tileBg)clearTimeout(this._clearTileBgTimer),
this._clearTileBgTimer=setTimeout(L.Util.bind(this._clearTileBg,this),500)},_getTopLeftPoint:function(){if(!this._loaded)throw Error("Set map center and zoom first.");return this._initialTopLeftPoint.subtract(L.DomUtil.getPosition(this._mapPane))},_getNewTopLeftPoint:function(a){var b=this.getSize().divideBy(2);return this.project(a).subtract(b).round()},_limitZoom:function(a){var b=this.getMinZoom(),c=this.getMaxZoom();return Math.max(b,Math.min(c,a))}});L.Map.include({locate:function(a){this._locationOptions=a=L.Util.extend({watch:!1,setView:!1,maxZoom:Infinity,timeout:1E4,maximumAge:0,enableHighAccuracy:!1},a);if(!navigator.geolocation)return this.fire("locationerror",{code:0,message:"Geolocation not supported."});var b=L.Util.bind(this._handleGeolocationResponse,this),c=L.Util.bind(this._handleGeolocationError,this);a.watch?this._locationWatchId=navigator.geolocation.watchPosition(b,c,a):navigator.geolocation.getCurrentPosition(b,c,a);return this},
initialize:function(a,b){L.Util.setOptions(this,b);this._container=L.DomUtil.get(a);if(this._container._leaflet)throw Error("Map container is already initialized.");this._container._leaflet=!0;this._initLayout();L.DomEvent&&(this._initEvents(),L.Handler&&this._initInteraction(),L.Control&&this._initControls());this.options.maxBounds&&this.setMaxBounds(this.options.maxBounds);var c=this.options.center,d=this.options.zoom;c!==null&&d!==null&&this.setView(c,d,!0);c=this.options.layers;c=c instanceof
Array?c:[c];this._tileLayersNum=0;this._initLayers(c)},setView:function(a,b){this._resetView(a,this._limitZoom(b));return this},setZoom:function(a){return this.setView(this.getCenter(),a)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(a){var b=this.getBoundsZoom(a);return this.setView(a.getCenter(),b)},fitWorld:function(){var a=new L.LatLng(-60,-170),b=new L.LatLng(85,179);return this.fitBounds(new L.LatLngBounds(a,b))},
panTo:function(a){return this.setView(a,this._zoom)},panBy:function(a){this.fire("movestart");this._rawPanBy(a);this.fire("move");this.fire("moveend");return this},setMaxBounds:function(a){this.options.maxBounds=a;var b=this.getBoundsZoom(a,!0);this.options.minZoom=b;this._loaded&&(this._zoom<b?this.setView(a.getCenter(),b):this.panInsideBounds(a));return this},panInsideBounds:function(a){var b=this.getBounds(),c=this.project(b.getSouthWest()),b=this.project(b.getNorthEast()),d=this.project(a.getSouthWest()),
a=this.project(a.getNorthEast()),e=0,f=0;b.y<a.y&&(f=a.y-b.y);b.x>a.x&&(e=a.x-b.x);c.y>d.y&&(f=d.y-c.y);c.x<d.x&&(e=d.x-c.x);return this.panBy(new L.Point(e,f,!0))},addLayer:function(a,b){var c=L.Util.stamp(a);if(this._layers[c])return this;this._layers[c]=a;if(a.options&&!isNaN(a.options.maxZoom))this._layersMaxZoom=Math.max(this._layersMaxZoom||0,a.options.maxZoom);if(a.options&&!isNaN(a.options.minZoom))this._layersMinZoom=Math.min(this._layersMinZoom||Infinity,a.options.minZoom);this.options.zoomAnimation&&
L.TileLayer&&a instanceof L.TileLayer&&(this._tileLayersNum++,a.on("load",this._onTileLayerLoad,this));this.attributionControl&&a.getAttribution&&this.attributionControl.addAttribution(a.getAttribution());c=function(){a.onAdd(this,b);this.fire("layeradd",{layer:a})};if(this._loaded)c.call(this);else this.on("load",c,this);return this},removeLayer:function(a){var b=L.Util.stamp(a);this._layers[b]&&(a.onRemove(this),delete this._layers[b],this.options.zoomAnimation&&L.TileLayer&&a instanceof L.TileLayer&&
(this._tileLayersNum--,a.off("load",this._onTileLayerLoad,this)),this.attributionControl&&a.getAttribution&&this.attributionControl.removeAttribution(a.getAttribution()),this.fire("layerremove",{layer:a}));return this},hasLayer:function(a){return this._layers.hasOwnProperty(L.Util.stamp(a))},invalidateSize:function(){if(!this._loaded)return this;var a=this.getSize();this._sizeChanged=!0;this._rawPanBy(a.subtract(this.getSize()).divideBy(2));this.fire("move");clearTimeout(this._sizeTimer);this._sizeTimer=
setTimeout(L.Util.bind(function(){this.fire("moveend")},this),200);return this},getCenter:function(a){var b=this.getSize().divideBy(2);return this.unproject(this._getTopLeftPoint().add(b),this._zoom,a)},getZoom:function(){return this._zoom},getBounds:function(){var a=this.getPixelBounds(),b=this.unproject(new L.Point(a.min.x,a.max.y)),a=this.unproject(new L.Point(a.max.x,a.min.y));return new L.LatLngBounds(b,a)},getMinZoom:function(){return isNaN(this.options.minZoom)?this._layersMinZoom||0:this.options.minZoom},
getMaxZoom:function(){return isNaN(this.options.maxZoom)?this._layersMaxZoom||Infinity:this.options.maxZoom},getBoundsZoom:function(a,b){var c=this.getSize(),d=this.getMinZoom(),e=this.getMaxZoom(),f=a.getNorthEast(),g=a.getSouthWest(),h,j;h=!0;do d++,h=this.project(f,d),j=this.project(g,d),h=new L.Point(h.x-j.x,j.y-h.y),h=b?h.x<c.x||h.y<c.y:h.x<=c.x&&h.y<=c.y;while(h&&d<=e);return b?d:d-1},getSize:function(){if(!this._size||this._sizeChanged)this._size=new L.Point(this._container.clientWidth,this._container.clientHeight),
this._sizeChanged=!1;return this._size},getPixelBounds:function(){var a=this._getTopLeftPoint(),b=this.getSize();return new L.Bounds(a,a.add(b))},getPixelOrigin:function(){return this._initialTopLeftPoint},getPanes:function(){return this._panes},mouseEventToContainerPoint:function(a){return L.DomEvent.getMousePosition(a,this._container)},mouseEventToLayerPoint:function(a){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(a))},mouseEventToLatLng:function(a){return this.layerPointToLatLng(this.mouseEventToLayerPoint(a))},
containerPointToLayerPoint:function(a){return a.subtract(L.DomUtil.getPosition(this._mapPane))},layerPointToContainerPoint:function(a){return a.add(L.DomUtil.getPosition(this._mapPane))},layerPointToLatLng:function(a){return this.unproject(a.add(this._initialTopLeftPoint))},latLngToLayerPoint:function(a){return this.project(a)._round()._subtract(this._initialTopLeftPoint)},project:function(a,b){b=typeof b==="undefined"?this._zoom:b;return this.options.crs.latLngToPoint(a,this.options.scale(b))},unproject:function(a,
b,c){b=typeof b==="undefined"?this._zoom:b;return this.options.crs.pointToLatLng(a,this.options.scale(b),c)},_initLayout:function(){var a=this._container;a.innerHTML="";a.className+=" leaflet-container";this.options.fadeAnimation&&(a.className+=" leaflet-fade-anim");var b=L.DomUtil.getStyle(a,"position");if(b!=="absolute"&&b!=="relative")a.style.position="relative";this._initPanes();this._initControlPos&&this._initControlPos()},_initPanes:function(){var a=this._panes={};this._mapPane=a.mapPane=this._createPane("leaflet-map-pane",
this._container);this._tilePane=a.tilePane=this._createPane("leaflet-tile-pane",this._mapPane);this._objectsPane=a.objectsPane=this._createPane("leaflet-objects-pane",this._mapPane);a.shadowPane=this._createPane("leaflet-shadow-pane");a.overlayPane=this._createPane("leaflet-overlay-pane");a.markerPane=this._createPane("leaflet-marker-pane");a.popupPane=this._createPane("leaflet-popup-pane")},_createPane:function(a,b){return L.DomUtil.create("div",a,b||this._objectsPane)},_resetView:function(a,b,c){var d=
this._zoom!==b;this.fire("movestart");this._zoom=b;this._initialTopLeftPoint=this._getNewTopLeftPoint(a);c?this._initialTopLeftPoint._add(L.DomUtil.getPosition(this._mapPane)):L.DomUtil.setPosition(this._mapPane,new L.Point(0,0));this._tileLayersToLoad=this._tileLayersNum;this.fire("viewreset",{hard:!c});this.fire("move");d&&this.fire("zoomend");this.fire("moveend");if(!this._loaded)this._loaded=!0,this.fire("load")},_initLayers:function(a){this._layers={};var b,c;b=0;for(c=a.length;b<c;b++)this.addLayer(a[b])},
_initControls:function(){this.options.zoomControl&&this.addControl(new L.Control.Zoom);if(this.options.attributionControl)this.attributionControl=new L.Control.Attribution,this.addControl(this.attributionControl)},_rawPanBy:function(a){var b=L.DomUtil.getPosition(this._mapPane);L.DomUtil.setPosition(this._mapPane,b.subtract(a))},_initEvents:function(){L.DomEvent.addListener(this._container,"click",this._onMouseClick,this);var a=["dblclick","mousedown","mouseenter","mouseleave","mousemove"],b,c;b=
0;for(c=a.length;b<c;b++)L.DomEvent.addListener(this._container,a[b],this._fireMouseEvent,this);this.options.trackResize&&L.DomEvent.addListener(window,"resize",this._onResize,this)},_onResize:function(){L.Util.requestAnimFrame(this.invalidateSize,this,!1,this._container)},_onMouseClick:function(a){if(this._loaded&&(!this.dragging||!this.dragging.moved()))this.fire("pre"+a.type),this._fireMouseEvent(a)},_fireMouseEvent:function(a){if(this._loaded){var b=a.type,b=b==="mouseenter"?"mouseover":b==="mouseleave"?
"mouseout":b;this.hasEventListeners(b)&&this.fire(b,{latlng:this.mouseEventToLatLng(a),layerPoint:this.mouseEventToLayerPoint(a)})}},_initInteraction:function(){var a={dragging:L.Handler.MapDrag,touchZoom:L.Handler.TouchZoom,doubleClickZoom:L.Handler.DoubleClickZoom,scrollWheelZoom:L.Handler.ScrollWheelZoom,shiftDragZoom:L.Handler.ShiftDragZoom},b;for(b in a)a.hasOwnProperty(b)&&a[b]&&(this[b]=new a[b](this),this.options[b]&&this[b].enable())},_onTileLayerLoad:function(){this._tileLayersToLoad--;
if(this._tileLayersNum&&!this._tileLayersToLoad&&this._tileBg)clearTimeout(this._clearTileBgTimer),this._clearTileBgTimer=setTimeout(L.Util.bind(this._clearTileBg,this),500)},_getTopLeftPoint:function(){if(!this._loaded)throw Error("Set map center and zoom first.");return this._initialTopLeftPoint.subtract(L.DomUtil.getPosition(this._mapPane))},_getNewTopLeftPoint:function(a){var b=this.getSize().divideBy(2);return this.project(a).subtract(b).round()},_limitZoom:function(a){var b=this.getMinZoom(),
c=this.getMaxZoom();return Math.max(b,Math.min(c,a))}});L.Map.include({locate:function(a){this._locationOptions=a=L.Util.extend({watch:!1,setView:!1,maxZoom:Infinity,timeout:1E4,maximumAge:0,enableHighAccuracy:!1},a);if(!navigator.geolocation)return this.fire("locationerror",{code:0,message:"Geolocation not supported."});var b=L.Util.bind(this._handleGeolocationResponse,this),c=L.Util.bind(this._handleGeolocationError,this);a.watch?this._locationWatchId=navigator.geolocation.watchPosition(b,c,a):navigator.geolocation.getCurrentPosition(b,c,a);return this},
stopLocate:function(){navigator.geolocation&&navigator.geolocation.clearWatch(this._locationWatchId)},locateAndSetView:function(a,b){b=L.Util.extend({maxZoom:a||Infinity,setView:!0});return this.locate(b)},_handleGeolocationError:function(a){var a=a.code,b=a==1?"permission denied":a==2?"position unavailable":"timeout";this._locationOptions.setView&&!this._loaded&&this.fitWorld();this.fire("locationerror",{code:a,message:"Geolocation error: "+b+"."})},_handleGeolocationResponse:function(a){var b=180*
a.coords.accuracy/4E7,c=b*2,d=a.coords.latitude,e=a.coords.longitude,f=new L.LatLng(d,e),g=new L.LatLng(d-b,e-c),b=new L.LatLng(d+b,e+c),g=new L.LatLngBounds(g,b);this._locationOptions.setView&&(b=Math.min(this.getBoundsZoom(g),this._locationOptions.maxZoom),this.setView(f,b));this.fire("locationfound",{latlng:f,bounds:g,accuracy:a.coords.accuracy})}});L.Map.include({openPopup:function(a){this.closePopup();this._popup=a;return this.addLayer(a)},closePopup:function(){this._popup&&this.removeLayer(this._popup);return this}});L.Map.include(!L.Transition||!L.Transition.implemented()?{}:{setView:function(a,b,c){var b=this._limitZoom(b),d=this._zoom!=b;if(this._loaded&&!c&&this._layers&&(c=this._getNewTopLeftPoint(a).subtract(this._getTopLeftPoint()),a=new L.LatLng(a.lat,a.lng),d?this._zoomToIfCenterInView&&this._zoomToIfCenterInView(a,b,c):this._panByIfClose(c)))return this;this._resetView(a,b);return this},panBy:function(a){if(!a.x&&!a.y)return this;if(!this._panTransition)this._panTransition=new L.Transition(this._mapPane,
{duration:0.3}),this._panTransition.on("step",this._onPanTransitionStep,this),this._panTransition.on("end",this._onPanTransitionEnd,this);this.fire("movestart");this._panTransition.run({position:L.DomUtil.getPosition(this._mapPane).subtract(a)});return this},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){this.fire("moveend")},_panByIfClose:function(a){if(this._offsetIsWithinView(a))return this.panBy(a),!0;return!1},_offsetIsWithinView:function(a,b){var c=b||1,d=
@ -114,12 +116,11 @@ L.Util.extend(L.GeoJSON,{geometryToLayer:function(a,b){var c=a.coordinates,d,e,f
case "MultiPolygon":return c=this.coordsToLatLngs(c,2),new L.MultiPolygon(c);case "GeometryCollection":e=0;for(f=a.geometries.length;e<f;e++)d=this.geometryToLayer(a.geometries[e]),g.push(d);return new L.FeatureGroup(g);default:throw Error("Invalid GeoJSON object.");}},coordsToLatLng:function(a,b){var c=parseFloat(a[b?0:1]),d=parseFloat(a[b?1:0]);return new L.LatLng(c,d)},coordsToLatLngs:function(a,b,c){var d,e=[],f,g=a.length;for(f=0;f<g;f++)d=b?this.coordsToLatLngs(a[f],b-1,c):this.coordsToLatLng(a[f],
c),e.push(d);return e}});L.Handler=L.Class.extend({initialize:function(a){this._map=a},enabled:function(){return!!this._enabled}});L.Handler.MapDrag=L.Handler.extend({enable:function(){if(!this._enabled){if(!this._draggable){this._draggable=new L.Draggable(this._map._mapPane,this._map._container);this._draggable.on("dragstart",this._onDragStart,this);this._draggable.on("drag",this._onDrag,this);this._draggable.on("dragend",this._onDragEnd,this);var a=this._map.options;a.worldCopyJump&&!a.continuousWorld&&(this._draggable.on("predrag",this._onPreDrag,this),this._map.on("viewreset",this._onViewReset,this))}this._draggable.enable();
this._enabled=!0}},disable:function(){if(this._enabled)this._draggable.disable(),this._enabled=!1},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){this._map.fire("movestart");this._map.fire("dragstart")},_onDrag:function(){this._map.fire("move");this._map.fire("drag")},_onViewReset:function(){var a=this._map.getSize().divideBy(2);this._initialWorldOffset=this._map.latLngToLayerPoint(new L.LatLng(0,0)).subtract(a)},_onPreDrag:function(){var a=this._map,b=a.options.scale(a.getZoom()),
c=Math.round(b/2),a=this._initialWorldOffset.x,d=this._draggable._newPos.x,e=(d-c+a)%b+c-a,b=(d+c+a)%b-c-a;this._draggable._newPos.x=Math.abs(e+a)<Math.abs(b+a)?e:b},_onDragEnd:function(){this._map.fire("moveend");this._map.fire("dragend")}});L.Handler.TouchZoom=L.Handler.extend({enable:function(){if(L.Browser.touch&&!this._enabled)L.DomEvent.addListener(this._map._container,"touchstart",this._onTouchStart,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"touchstart",this._onTouchStart,this),this._enabled=!1},_onTouchStart:function(a){if(a.touches&&!(a.touches.length!=2||this._map._animatingZoom)){var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]),
c=Math.round(b/2),a=this._initialWorldOffset.x,d=this._draggable._newPos.x,e=(d-c+a)%b+c-a,b=(d+c+a)%b-c-a;this._draggable._newPos.x=Math.abs(e+a)<Math.abs(b+a)?e:b},_onDragEnd:function(){var a=this._map;a.fire("moveend");a.fire("dragend");this._map.options.maxBounds&&L.Util.requestAnimFrame(this._panInsideMaxBounds,a,!0,a._container)},_panInsideMaxBounds:function(){this.panInsideBounds(this.options.maxBounds)}});L.Handler.TouchZoom=L.Handler.extend({enable:function(){if(L.Browser.touch&&!this._enabled)L.DomEvent.addListener(this._map._container,"touchstart",this._onTouchStart,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"touchstart",this._onTouchStart,this),this._enabled=!1},_onTouchStart:function(a){if(a.touches&&!(a.touches.length!=2||this._map._animatingZoom)){var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]),
d=this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2));this._startCenter=b.add(c).divideBy(2,!0);this._startDist=b.distanceTo(c);this._moved=!1;this._zooming=!0;this._centerOffset=d.subtract(this._startCenter);L.DomEvent.addListener(document,"touchmove",this._onTouchMove,this);L.DomEvent.addListener(document,"touchend",this._onTouchEnd,this);L.DomEvent.preventDefault(a)}},_onTouchMove:function(a){if(a.touches&&a.touches.length==2){if(!this._moved)this._map._mapPane.className+=" leaflet-zoom-anim",
this._map._prepareTileBg(),this._moved=!0;var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]);this._scale=b.distanceTo(c)/this._startDist;this._delta=b.add(c).divideBy(2,!0).subtract(this._startCenter);this._map._tileBg.style.webkitTransform=[L.DomUtil.getTranslateString(this._delta),L.DomUtil.getScaleString(this._scale,this._startCenter)].join(" ");L.DomEvent.preventDefault(a)}},_onTouchEnd:function(){if(this._moved&&this._zooming){this._zooming=
!1;var a=this._map.getZoom(),b=Math.log(this._scale)/Math.LN2,b=this._map._limitZoom(a+(b>0?Math.ceil(b):Math.floor(b))),a=b-a,c=this._centerOffset.subtract(this._delta).divideBy(this._scale),d=this._map.unproject(this._map.getPixelOrigin().add(this._startCenter).add(c));L.DomEvent.removeListener(document,"touchmove",this._onTouchMove);L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);this._map._runAnimation(d,b,Math.pow(2,a)/this._scale,this._startCenter.add(c))}}});L.Handler.ScrollWheelZoom=L.Handler.extend({enable:function(){if(!this._enabled)L.DomEvent.addListener(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0,this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"mousewheel",this._onWheelScroll),this._enabled=!1},_onWheelScroll:function(a){this._delta+=L.DomEvent.getWheelDelta(a);this._lastMousePos=this._map.mouseEventToContainerPoint(a);clearTimeout(this._timer);this._timer=setTimeout(L.Util.bind(this._performZoom,
this),50);L.DomEvent.preventDefault(a)},_performZoom:function(){var a=Math.round(this._delta),a=Math.max(Math.min(a,4),-4);this._delta=0;if(a){var b=this._getCenterForScrollWheelZoom(this._lastMousePos,a),a=this._map.getZoom()+a;this._map._limitZoom(a)!=this._map._zoom&&this._map.setView(b,a)}},_getCenterForScrollWheelZoom:function(a,b){var c=this._map.getPixelBounds().getCenter(),d=this._map.getSize().divideBy(2),d=a.subtract(d).multiplyBy(1-Math.pow(2,-b));return this._map.unproject(c.add(d),this._map._zoom,
!0)}});L.Handler.DoubleClickZoom=L.Handler.extend({enable:function(){if(!this._enabled)this._map.on("dblclick",this._onDoubleClick,this._map),this._enabled=!0},disable:function(){if(this._enabled)this._map.off("dblclick",this._onDoubleClick,this._map),this._enabled=!1},_onDoubleClick:function(a){this.setView(a.latlng,this._zoom+1)}});L.Handler.ShiftDragZoom=L.Handler.extend({initialize:function(a){this._map=a;this._container=a._container;this._pane=a._panes.overlayPane},enable:function(){if(!this._enabled)L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown),this._enabled=!1},_onMouseDown:function(a){if(!a.shiftKey||a.which!=1&&a.button!=1)return!1;L.DomUtil.disableTextSelection();
this),50);L.DomEvent.preventDefault(a)},_performZoom:function(){var a=Math.round(this._delta),b=this._map.getZoom(),a=Math.max(Math.min(a,4),-4),a=this._map._limitZoom(b+a)-b;this._delta=0;a&&this._map.setView(this._getCenterForScrollWheelZoom(this._lastMousePos,a),b+a)},_getCenterForScrollWheelZoom:function(a,b){var c=this._map.getPixelBounds().getCenter(),d=this._map.getSize().divideBy(2),d=a.subtract(d).multiplyBy(1-Math.pow(2,-b));return this._map.unproject(c.add(d),this._map._zoom,!0)}});L.Handler.DoubleClickZoom=L.Handler.extend({enable:function(){if(!this._enabled)this._map.on("dblclick",this._onDoubleClick,this._map),this._enabled=!0},disable:function(){if(this._enabled)this._map.off("dblclick",this._onDoubleClick,this._map),this._enabled=!1},_onDoubleClick:function(a){this.setView(a.latlng,this._zoom+1)}});L.Handler.ShiftDragZoom=L.Handler.extend({initialize:function(a){this._map=a;this._container=a._container;this._pane=a._panes.overlayPane},enable:function(){if(!this._enabled)L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown),this._enabled=!1},_onMouseDown:function(a){if(!a.shiftKey||a.which!=1&&a.button!=1)return!1;L.DomUtil.disableTextSelection();
this._startLayerPoint=this._map.mouseEventToLayerPoint(a);this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane);L.DomUtil.setPosition(this._box,this._startLayerPoint);this._container.style.cursor="crosshair";L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this);L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this);L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),a=b.x-this._startLayerPoint.x,c=b.y-this._startLayerPoint.y,
b=new L.Point(Math.min(b.x,this._startLayerPoint.x),Math.min(b.y,this._startLayerPoint.y));L.DomUtil.setPosition(this._box,b);this._box.style.width=Math.abs(a)-4+"px";this._box.style.height=Math.abs(c)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box);this._container.style.cursor="";L.DomUtil.enableTextSelection();L.DomEvent.removeListener(document,"mousemove",this._onMouseMove);L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);a=this._map.mouseEventToLayerPoint(a);this._map.fitBounds(new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint),
this._map.layerPointToLatLng(a)))}});L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},enable:function(){if(!this._enabled){if(!this._draggable)this._draggable=new L.Draggable(this._marker._icon,this._marker._icon),this._draggable.on("dragstart",this._onDragStart,this),this._draggable.on("drag",this._onDrag,this),this._draggable.on("dragend",this._onDragEnd,this);this._draggable.enable();this._enabled=!0}},disable:function(){if(this._enabled)this._draggable.disable(),this._enabled=!1},moved:function(){return this._draggable&&

View File

@ -65,7 +65,18 @@ L.Handler.MapDrag = L.Handler.extend({
},
_onDragEnd: function() {
this._map.fire('moveend');
this._map.fire('dragend');
var map = this._map;
map.fire('moveend');
map.fire('dragend');
if (this._map.options.maxBounds) {
// TODO predrag validation instead of animation
L.Util.requestAnimFrame(this._panInsideMaxBounds, map, true, map._container);
}
},
_panInsideMaxBounds: function () {
this.panInsideBounds(this.options.maxBounds);
}
});

View File

@ -57,6 +57,10 @@ L.Map = L.Class.extend({
if (L.Control) { this._initControls(); }
}
if (this.options.maxBounds) {
this.setMaxBounds(this.options.maxBounds);
}
var center = this.options.center,
zoom = this.options.zoom;
@ -119,6 +123,48 @@ L.Map = L.Class.extend({
return this;
},
setMaxBounds: function (bounds) {
this.options.maxBounds = bounds;
var minZoom = this.getBoundsZoom(bounds, true);
this.options.minZoom = minZoom;
if (this._loaded) {
if (this._zoom < minZoom) {
this.setView(bounds.getCenter(), minZoom);
} else {
this.panInsideBounds(bounds);
}
}
return this;
},
panInsideBounds: function (bounds) {
var viewBounds = this.getBounds(),
viewSw = this.project(viewBounds.getSouthWest()),
viewNe = this.project(viewBounds.getNorthEast()),
sw = this.project(bounds.getSouthWest()),
ne = this.project(bounds.getNorthEast()),
dx = 0,
dy = 0;
if (viewNe.y < ne.y) { // north
dy = ne.y - viewNe.y;
}
if (viewNe.x > ne.x) { // east
dx = ne.x - viewNe.x;
}
if (viewSw.y > sw.y) { // south
dy = sw.y - viewSw.y;
}
if (viewSw.x < sw.x) { // west
dx = sw.x - viewSw.x;
}
return this.panBy(new L.Point(dx, dy, true));
},
addLayer: function (layer, insertAtTheTop) {
var id = L.Util.stamp(layer);
@ -226,7 +272,7 @@ L.Map = L.Class.extend({
return isNaN(this.options.maxZoom) ? this._layersMaxZoom || Infinity : this.options.maxZoom;
},
getBoundsZoom: function (bounds) { // (LatLngBounds)
getBoundsZoom: function (bounds, inside) { // (LatLngBounds)
var size = this.getSize(),
zoom = this.getMinZoom(),
maxZoom = this.getMaxZoom(),
@ -234,17 +280,23 @@ L.Map = L.Class.extend({
sw = bounds.getSouthWest(),
boundsSize,
nePoint,
swPoint;
swPoint,
zoomNotFound = true;
do {
zoom++;
nePoint = this.project(ne, zoom);
swPoint = this.project(sw, zoom);
boundsSize = new L.Point(nePoint.x - swPoint.x, swPoint.y - nePoint.y);
} while ((boundsSize.x <= size.x) &&
(boundsSize.y <= size.y) && (zoom <= maxZoom));
return zoom - 1;
if (!inside) {
zoomNotFound = (boundsSize.x <= size.x) && (boundsSize.y <= size.y);
} else {
zoomNotFound = (boundsSize.x < size.x) || (boundsSize.y < size.y);
}
} while (zoomNotFound && (zoom <= maxZoom));
return inside ? zoom : zoom - 1;
},
getSize: function () {

View File

@ -33,11 +33,11 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
this._panTransition.on('end', this._onPanTransitionEnd, this);
}
this.fire('movestart');
this._panTransition.run({
position: L.DomUtil.getPosition(this._mapPane).subtract(offset)
});
return this;
},