在OpenLayers3中限制在WMS范围之外的Pan

时间:2014-11-29 07:43:20

标签: openlayers-3

我有一个小面积的矩形WMS,并希望限制WMS扩展外的平移,因此地图外部没有可见的白色或黑色区域。 将extent添加到View对我不起作用,并且有关此选项的文档已编写

  

限制中心的程度,换句话说,中心不能   超出这个范围。

但是据我所知,如果中心位于范围区域,但是在角落处,它会在这个范围之外显示白色区域,但我不想看到白色区域。

是否可以通过OL3实现这一目标?

3 个答案:

答案 0 :(得分:12)

这是我的解决方案。我刚刚写了它,因此没有经过广泛的测试。例如,如果你开始旋转地图,它可能会破裂,如果缩小太远,它可能会出现故障。

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

这要求变量mapview(具有明显的含义)和extent(您希望可见的xmin,ymin,xmax,ymax)可用。

答案 1 :(得分:2)

这是一个更强大的实现,在任何情况下都应该可以正常工作。它是用ES6编写的,需要isEqual方法(来自lodash或其他任何东西......)

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

答案 2 :(得分:1)

这是对@tremby回答的扩展,但是很想发表评论。

首先,他的解决方案对我来说效果很好,但它经常被称为方式。因此,我将其包装在debounce函数中。

所以

view.on('change:resolution', constrainPan);
view.on('change:center', constrainPan);

变为

var dConstrainPan = debounce(constrainPan);
view.on('change:resolution', dConstrainPan);
view.on('change:center', dConstrainPan);

这将导致轻微的闪烁,当移动到边界框外时,机器人缩放/移动工作没有延迟。

仍然不完美,但从我的观点来看是一个有用的改进。

去抖代码:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Soruce:https://davidwalsh.name/javascript-debounce-function,in underscore.js