Limit Panning OpenLayers 5

旧时模样 提交于 2019-12-10 14:27:57

问题


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]
});

回答1:


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.



来源:https://stackoverflow.com/questions/54562038/limit-panning-openlayers-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!