Ограничить панорамирование вне области WMS в OpenLayers3
У меня есть прямоугольник WMS небольшой области и вы хотите ограничить панорамирование вне WMS extends, так что на карте нет видимой белой или черной области.
Добавление extent
в View
не работает для меня и в документации об этой опции написано
Степень, которая ограничивает центр, другими словами, центр не может быть установленным вне этой степени.
Но поскольку я понимаю это, если центр находится в области протяженности, но в самом углу он покажет белую область вне этой степени, но я не хочу видеть белую область вообще.
Можно ли добиться этого с помощью OL3?
Ответы
Ответ 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);
Здесь ожидаются переменные map
, view
(с очевидными значениями) и 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);
Ответ 3
Это расширение для ответа @tremby, но для комментария.
Прежде всего, его решение работает очень хорошо для меня, но его часто называют способом. Поэтому я завернул его в функцию debounce
.
So
view.on('change:resolution', constrainPan);
view.on('change:center', constrainPan);
становится
view.on('change:resolution', constrainPan);
view.on('change:center', constrainPan);
Это приведет к небольшому мерцанию, когда вы перемещаетесь за пределы ограничивающего прямоугольника, масштабирование/перемещение бота без задержки.
Все еще не идеальное, но полезное улучшение с моей точки зрения.
Код ошибки:
// 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