I'm using OpenLayers 5 for my project and wasn't able to find anything on here for that. In the past, OpenLayers has had restrictExtent
, but that seems to have disappeared. Is there a way to limit or restrict the user's ability to pan vertically so that they can't drag it off the screen?
I've tried using the maxExtent
on both the layer containing the map and the View, and I've been able to limit what's visible by doing so on the View. I haven't been able to limit the panning, however. Any help with this would be awesome.
map.js
componentDidMount() {
BASE_VIEW.setMinZoom(this.getMinZoom());
this.resize();
this.map = new Map({
controls: defaultControls().extend([MOUSE_POSITION_CONTROL]),
layers: [BASE_LAYER],
target: 'map',
view: BASE_VIEW
});
}
map-constants.js
const baseView = new View({
center: fromLonLat(conus, projection),
projection: projection,
zoom: 4,
extent: [Number.NEGATIVE_INFINITY, -43, Number.POSITIVE_INFINITY, 43]
});
The nearest equivalent to OpenLayers 2 restrictedExtent
in OL3/4/5 is the misleadingly named extent
option of ol.View
but that is a center constraint which restricts the map center, and depending on resolution and map size it is possible to pan the edges of the map considerably beyond that.
To replicate restrictedExtent
you would need to recalculate the center constraint and reset the view as the resolution changes (ignoring very small changes to avoid performance issues). Assuming you have opened the map at the required maximum extent (using .fit()
perhaps) you could then use this code
var extent = map.getView().calculateExtent(); // opening coverage
var resolution = 0;
function resChange() {
var newResolution = map.getView().getResolution();
if (resolution == 0 || Math.abs((newResolution-resolution)/resolution) > 0.01) {
resolution = newResolution;
var width = map.getSize()[0] * resolution;
var height = map.getSize()[1] * resolution;
var view = new ol.View({
projection: map.getView().getProjection(),
extent: [extent[0]+(width/2), extent[1]+(height/2), extent[2]-(width/2), extent[3]-(height/2)],
center: map.getView().getCenter(),
resolution: resolution,
maxZoom: map.getView().getMaxZoom(),
minZoom: map.getView().getMinZoom()
});
view.on('change:resolution', resChange);
map.setView(view);
}
}
resChange();
Here's a demo. For efficiency I'm only resetting the view at integer zoom levels (resulting in a stretch and snap back effect when zooming out close to the edges), and for the demo to work full page I reset the map when resized.
var view = new ol.View();
var map = new ol.Map({
layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ],
target: 'map'
});
function openMap() {
map.setView(view);
var extent = ol.proj.transformExtent([ -2, 50.5, 2, 53], 'EPSG:4326', 'EPSG:3857');
// fit the extent horizontally or vertically depending on screen size
// to determine the maximum resolution possible
var size = map.getSize();
var width = ol.extent.getWidth(extent);
var height = ol.extent.getHeight(extent);
if (size[0]/size[1] > width/height) {
view.fit([extent[0],(extent[1]+extent[3])/2,extent[2],(extent[1]+extent[3])/2], { constrainResolution: false });
} else {
view.fit([(extent[0]+extent[2])/2,extent[1],(extent[0]+extent[2])/2,extent[3]], { constrainResolution: false });
}
var maxResolution = view.getResolution();
var resolution = 0;
function resChange() {
var oldView = map.getView();
if (resolution == 0 || oldView.getZoom()%1 == 0) {
resolution = oldView.getResolution();
var width = map.getSize()[0] * resolution;
var height = map.getSize()[1] * resolution;
var newView = new ol.View({
projection: oldView.getProjection(),
extent: [extent[0]+(width/2), extent[1]+(height/2), extent[2]-(width/2), extent[3]-(height/2)],
resolution: resolution,
maxResolution: maxResolution,
rotation: oldView.getRotation()
});
newView.setCenter(newView.constrainCenter(oldView.getCenter()));
newView.on('change:resolution', resChange);
map.setView(newView);
}
}
resChange();
}
map.on('change:size', openMap);
openMap();
<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
UPDATE
In OpenLayers 6 the view extent
option does restrict the extent and not the center (useless constrainOnlyCenter
is also specified) so no workaround is needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With