【问题标题】:Restrict Pan outside WMS extent in OpenLayers3在 OpenLayers3 中限制平移超出 WMS 范围
【发布时间】:2014-11-29 07:43:20
【问题描述】:

我有一个小区域的矩形 WMS,并且想限制 WMS 扩展之外的平移,因此地图之外根本看不到白色或黑色区域。 将extent 添加到View 对我不起作用,并且在有关此选项的文档中写入了

限制中心的范围,换句话说,中心不能 设置在这个范围之外。

但据我了解,如果中心位于范围区域内,但在最角落,它将显示此范围之外的白色区域,但我根本不想看到白色区域。

OL3可以做到吗?

【问题讨论】:

  • 这是个好问题。你想要的还不支持。不久前,我开始研究一个可以涵盖您的用例的补丁,但这个补丁尚未合并。请参阅 github.com/openlayers/ol3/pull/2777>。我会再次尝试解决这个问题。
  • 哦,那很糟糕。这个白色区域是我看到的大多数在线地图真正不喜欢的地方。现在等待OL3支持。
  • Erilem 的补丁有效,您可以轻松地自己添加它。 erilem.net/ol3/constrain-center/examples/restricted-extent.js
  • 指向 erilem 的拉取请求的链接末尾有一个隐秘的额外 > 并给出 404。工作链接:github.com/openlayers/ol3/pull/2777
  • 我不喜欢无法看到范围之外的白色区域。这意味着我永远不能集中在可用区域内的区域上。这会导致进一步的问题。

标签: openlayers-3


【解决方案1】:

这是我的解决方案。我刚刚写了它,所以它没有经过广泛的测试。例如,如果您开始旋转地图,它可能会损坏,如果您缩小得太远,它可能会出现故障。

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)可用。

【讨论】:

  • 效果很好,但在全屏模式下会导致缩放和拖动停止工作
  • 是的,我提到如果缩小得太远,它可能会损坏。当您进入全屏时,可能会出现相同的情况。很高兴它同样有帮助。如果您有特别建议使其更可靠,请提出修改建议。
  • 我收到“递归过多”错误,无法更快地平移,我的图层正在消失...仅供记录
  • 是的;对于一般情况,它绝对不是生产就绪的代码(尽管它对我的用例来说效果很好)。欢迎任何改进。
【解决方案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);

【讨论】:

  • ES6 lodash 导入注意:确保您使用import { isEqual } from 'lodash'。如果您忘记了花括号,它不会抛出错误,但 isEqual() 将始终为数组返回 true。
【解决方案3】:

这是@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);
    };
};

来源:https://davidwalsh.name/javascript-debounce-function,在 underscore.js 中

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多