Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restrict Pan outside WMS extent in OpenLayers3

Tags:

openlayers-3

I have rectangle WMS of small area and want to restrict panning outside WMS extends, so there aren't white or black area outside the map visible at all. Adding extent to View does not work for me and in documentation about this option is written

The extent that constrains the center, in other words, center cannot be set outside this extent.

But as I understand this if center is in the area of extent, but on the very corner, it will show white area outside this extent, but I don't want to see white area at all.

Is it possible to achieve this with OL3?

like image 831
Anuket Avatar asked Nov 29 '14 07:11

Anuket


2 Answers

Here's my solution. I wrote it just now, and so it is not extensively tested. It would probably break if you start rotating the map, for example, and it may be glitchy if you zoom out too far.

var constrainPan = function() {
    var visible = view.calculateExtent(map.getSize());
    var centre = view.getCenter();
    var delta;
    var adjust = false;
    if ((delta = extent[0] - visible[0]) > 0) {
        adjust = true;
        centre[0] += delta;
    } else if ((delta = extent[2] - visible[2]) < 0) {
        adjust = true;
        centre[0] += delta;
    }
    if ((delta = extent[1] - visible[1]) > 0) {
        adjust = true;
        centre[1] += delta;
    } else if ((delta = extent[3] - visible[3]) < 0) {
        adjust = true;
        centre[1] += delta;
    }
    if (adjust) {
        view.setCenter(centre);
    }
};
view.on('change:resolution', constrainPan);
view.on('change:center', constrainPan);

This expects the variables map, view (with obvious meanings) and extent (the xmin, ymin, xmax, ymax you want to be visible) to be available.

like image 60
tremby Avatar answered Nov 11 '22 16:11

tremby


Here's a more robust implementation that should work really well in any case. It's written in ES6, and requires isEqual method (from lodash or anything else ...)

const extent = [-357823.2365, 6037008.6939, 1313632.3628, 7230727.3772];
const view = this.olMap.getView();

const modifyValues = {};

// Trick to forbid panning outside extent
let constrainPan = (e) => {
  const type = e.type;
  const newValue = e.target.get(e.key);
  const oldValue = e.oldValue;

  if (isEqual(oldValue, newValue)) {
    // Do nothing when event doesn't change the value
    return;
  }

  if (isEqual(modifyValues[type], newValue)) {
    // Break possible infinite loop
    delete modifyValues[type];
    return;
  }

  if (type === 'change:resolution' && newValue < oldValue) {
    // Always allow zoom-in.
    return;
  }

  const visibleExtent = view.calculateExtent(this.olMap.getSize());
  const intersection = ol.extent.getIntersection(visibleExtent, extent);
  const modify = !isEqual(intersection, visibleExtent);

  if (modify) {
    if (type === 'change:center') {
      const newCenter = newValue.slice(0);

      if (ol.extent.getWidth(visibleExtent) !== ol.extent.getWidth(intersection)) {
        newCenter[0] = oldValue[0];
      }

      if (ol.extent.getHeight(visibleExtent) !== ol.extent.getHeight(intersection)) {
        newCenter[1] = oldValue[1];
      }

      modifyValues[type] = newCenter;
      view.setCenter(newCenter);
    } else if (type === 'change:resolution') {
      modifyValues[type] = oldValue;
      view.setResolution(oldValue);
    }
  }
};
view.on('change:resolution', constrainPan);
view.on('change:center', constrainPan);
like image 40
Toilal Avatar answered Nov 11 '22 14:11

Toilal