diff --git a/examples/restricted-extent.html b/examples/restricted-extent.html new file mode 100644 index 0000000000..2f8dc0d6ef --- /dev/null +++ b/examples/restricted-extent.html @@ -0,0 +1,70 @@ + + + + + + + + +

OpenLayers Restricted Extent Example

+
+

+ Map navigation is limited by a combination of map and layer properties. + The base layer resolutions array controls the resolutions (or zoom + levels) available. The resolutions can be limited by setting a + maxResolution property or by explicitly specifying a resolutions + array. +

+

+ Navigation limited by the maxExtent property. A map cannot be panned + so that the center of the viewport is outside of the bounds specified + in maxExtent. If you wish to further restrict panning, use the + restrictedExtent property. With restrictedExtent set, the map cannot + be panned beyond the given bounds. If the maxResolution allows the + map to be zoomed to a resolution that displays an area bigger than + the restrictedExtent, the viewport will remain centered on the + restrictedExtent. +

+

+ + + + + diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index 996b6c630e..29b2965111 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -206,6 +206,17 @@ OpenLayers.Map = OpenLayers.Class({ */ minExtent: null, + /** + * APIProperty: restrictedExtent + * {} Limit map navigation to this extent where possible. + * If a non-null restrictedExtent is set, panning will be restricted + * to the given bounds. In addition, zooming to a resolution that + * displays more than the restricted extent will center the map + * on the restricted extent. If you wish to limit the zoom level + * or resolution, use maxResolution. + */ + restrictedExtent: null, + /** * APIProperty: numZoomLevels * {Integer} Number of zoom levels for the map. Defaults to 16. Set a @@ -1036,10 +1047,47 @@ OpenLayers.Map = OpenLayers.Class({ * TBD: reconsider forceZoomChange in 3.0 */ setCenter: function (lonlat, zoom, dragging, forceZoomChange) { - + if (!this.center && !this.isValidLonLat(lonlat)) { lonlat = this.maxExtent.getCenterLonLat(); } + + if(this.restrictedExtent != null) { + // In 3.0, decide if we want to change interpretation of maxExtent. + if(lonlat == null) { + lonlat = this.getCenter(); + } + if(zoom == null) { + zoom = this.getZoom(); + } + var resolution = null; + if(this.baseLayer != null) { + resolution = this.baseLayer.resolutions[zoom]; + } + var extent = this.calculateBounds(lonlat, resolution); + if(!this.restrictedExtent.containsBounds(extent)) { + var maxCenter = this.restrictedExtent.getCenterLonLat(); + if(extent.getWidth() > this.restrictedExtent.getWidth()) { + lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); + } else if(extent.left < this.restrictedExtent.left) { + lonlat = lonlat.add(this.restrictedExtent.left - + extent.left, 0); + } else if(extent.right > this.restrictedExtent.right) { + lonlat = lonlat.add(this.restrictedExtent.right - + extent.right, 0); + } + if(extent.getHeight() > this.restrictedExtent.getHeight()) { + lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); + } else if(extent.bottom < this.restrictedExtent.bottom) { + lonlat = lonlat.add(0, this.restrictedExtent.bottom - + extent.bottom); + } + else if(extent.top > this.restrictedExtent.top) { + lonlat = lonlat.add(0, this.restrictedExtent.top - + extent.top); + } + } + } var zoomChanged = forceZoomChange || ( (this.isValidZoomLevel(zoom)) && diff --git a/tests/test_Map.html b/tests/test_Map.html index 9e1d6c05c6..13370edc87 100644 --- a/tests/test_Map.html +++ b/tests/test_Map.html @@ -472,6 +472,102 @@ t.ok( newNumControls == oldNumControls, "removing bad controlid doesnt crash or decrease control count") } + function test_Map_restrictedExtent(t) { + t.plan(24); + var extent = new OpenLayers.Bounds(-180, -90, 180, 90); + var options = { + maxResolution: "auto" + }; + var map = new OpenLayers.Map("map", options); + var layer = new OpenLayers.Layer.WMS( + "test", + "http://octo.metacarta.com/cgi-bin/mapserv?", + {map: "/mapdata/vmap_wms.map", layers: "basic"} + ); + map.addLayer(layer); + map.zoomToMaxExtent(); + var nw = new OpenLayers.LonLat(extent.left, extent.top); + var ne = new OpenLayers.LonLat(extent.right, extent.top); + var sw = new OpenLayers.LonLat(extent.left, extent.bottom); + var se = new OpenLayers.LonLat(extent.right, extent.bottom); + + // try panning to northwest corner + map.setOptions({restrictedExtent: extent}); + map.setCenter(nw, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + extent.getCenterLonLat().toString(), + "map extent properly restricted to northwest at zoom 0"); + t.eq(map.zoom, 0, "zoom not restricted for nw, 0"); + map.setCenter(nw, 5); + t.eq(map.getExtent().top, extent.top, + "map extent top properly restricted to northwest at zoom 5"); + t.eq(map.getExtent().left, extent.left, + "map extent left properly restricted to northwest at zoom 5"); + t.eq(map.zoom, 5, "zoom not restricted for nw, 5"); + map.setOptions({restrictedExtent: null}); + map.setCenter(nw, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + nw.toString(), + "map extent not restricted with null restrictedExtent for nw"); + + // try panning to northeast corner + map.setOptions({restrictedExtent: extent}); + map.setCenter(ne, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + extent.getCenterLonLat().toString(), + "map extent properly restricted to northeast at zoom 0"); + t.eq(map.zoom, 0, "zoom not restricted for ne, 0"); + map.setCenter(ne, 5); + t.eq(map.getExtent().top, extent.top, + "map extent top properly restricted to northeast at zoom 5"); + t.eq(map.getExtent().right, extent.right, + "map extent right properly restricted to northeast at zoom 5"); + t.eq(map.zoom, 5, "zoom not restricted for ne, 5"); + map.setOptions({restrictedExtent: null}); + map.setCenter(ne, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + ne.toString(), + "map extent not restricted with null restrictedExtent for ne"); + + // try panning to southwest corner + map.setOptions({restrictedExtent: extent}); + map.setCenter(sw, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + extent.getCenterLonLat().toString(), + "map extent properly restricted to southwest at zoom 0"); + t.eq(map.zoom, 0, "zoom not restricted for sw, 0"); + map.setCenter(sw, 5); + t.eq(map.getExtent().bottom, extent.bottom, + "map extent bottom properly restricted to southwest at zoom 5"); + t.eq(map.getExtent().left, extent.left, + "map extent left properly restricted to southwest at zoom 5"); + t.eq(map.zoom, 5, "zoom not restricted for sw, 5"); + map.setOptions({restrictedExtent: null}); + map.setCenter(sw, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + sw.toString(), + "map extent not restricted with null restrictedExtent for sw"); + + // try panning to southeast corner + map.setOptions({restrictedExtent: extent}); + map.setCenter(se, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + extent.getCenterLonLat().toString(), + "map extent properly restricted to southeast at zoom 0"); + t.eq(map.zoom, 0, "zoom not restricted for se, 0"); + map.setCenter(se, 5); + t.eq(map.getExtent().bottom, extent.bottom, + "map extent bottom properly restricted to southeast at zoom 5"); + t.eq(map.getExtent().right, extent.right, + "map extent right properly restricted to southeast at zoom 5"); + t.eq(map.zoom, 5, "zoom not restricted for se, 5"); + map.setOptions({restrictedExtent: null}); + map.setCenter(se, 0); + t.eq(map.getExtent().getCenterLonLat().toString(), + se.toString(), + "map extent not restricted with null restrictedExtent for se"); + } + function test_99_Map_destroy (t) { t.plan( 3 ); map = new OpenLayers.Map('map'); @@ -484,6 +580,6 @@ -

+