View / add a method to compute a valid zoom level
The `getValidZoomLevel` apply the current resolution constraint to return a value that is guaranteed valid. This is used for interactions & controls which need a target value to work: the +/- buttons, the zoom clider, the dragbox zoom and the mouse wheel zoom.
This commit is contained in:
@@ -1217,6 +1217,23 @@ class View extends BaseObject {
|
|||||||
endInteraction() {
|
endInteraction() {
|
||||||
this.setHint(ViewHint.INTERACTING, -1);
|
this.setHint(ViewHint.INTERACTING, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a valid zoom level according to the current view constraints.
|
||||||
|
* @param {number|undefined} targetZoom Target resolution.
|
||||||
|
* @param {number=} opt_direction Direction. Default is `0`. Specify `-1` or `1` to return
|
||||||
|
* the available value respectively lower or greater than the target one. Leaving `0` will simply choose
|
||||||
|
* the nearest available value.
|
||||||
|
* @return {number|undefined} Valid zoom level.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getValidZoomLevel(targetZoom, opt_direction) {
|
||||||
|
const direction = opt_direction || 0;
|
||||||
|
const currentRes = this.getResolution();
|
||||||
|
const currentZoom = this.getZoom();
|
||||||
|
return this.getZoomForResolution(
|
||||||
|
this.constraints_.resolution(currentRes, targetZoom - currentZoom, direction));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -114,20 +114,20 @@ class Zoom extends Control {
|
|||||||
// upon it
|
// upon it
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const currentResolution = view.getResolution();
|
const currentZoom = view.getZoom();
|
||||||
if (currentResolution) {
|
if (currentZoom !== undefined) {
|
||||||
const newResolution = view.constrainResolution(currentResolution, delta);
|
const newZoom = view.getValidZoomLevel(currentZoom + delta);
|
||||||
if (this.duration_ > 0) {
|
if (this.duration_ > 0) {
|
||||||
if (view.getAnimating()) {
|
if (view.getAnimating()) {
|
||||||
view.cancelAnimations();
|
view.cancelAnimations();
|
||||||
}
|
}
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: newResolution,
|
zoom: newZoom,
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
view.setResolution(newResolution);
|
view.setZoom(newZoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,9 +218,10 @@ class ZoomSlider extends Control {
|
|||||||
event.offsetY - this.thumbSize_[1] / 2);
|
event.offsetY - this.thumbSize_[1] / 2);
|
||||||
|
|
||||||
const resolution = this.getResolutionForPosition_(relativePosition);
|
const resolution = this.getResolutionForPosition_(relativePosition);
|
||||||
|
const zoom = view.getValidZoomLevel(view.getZoomForResolution(resolution));
|
||||||
|
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: view.constrainResolution(resolution),
|
zoom: zoom,
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
@@ -281,8 +282,11 @@ class ZoomSlider extends Control {
|
|||||||
const view = this.getMap().getView();
|
const view = this.getMap().getView();
|
||||||
view.endInteraction();
|
view.endInteraction();
|
||||||
|
|
||||||
|
const zoom = view.getValidZoomLevel(
|
||||||
|
view.getZoomForResolution(this.currentResolution_));
|
||||||
|
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: view.constrainResolution(this.currentResolution_),
|
zoom: zoom,
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -80,14 +80,14 @@ function onBoxEnd() {
|
|||||||
extent = mapExtent;
|
extent = mapExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolution = view.constrainResolution(
|
const resolution = view.getResolutionForExtent(extent, size);
|
||||||
view.getResolutionForExtent(extent, size));
|
const zoom = view.getValidZoomLevel(view.getZoomForResolution(resolution));
|
||||||
|
|
||||||
let center = getCenter(extent);
|
let center = getCenter(extent);
|
||||||
center = view.constrainCenter(center);
|
center = view.constrainCenter(center);
|
||||||
|
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: resolution,
|
zoom: zoom,
|
||||||
center: center,
|
center: center,
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
|
|||||||
@@ -189,34 +189,49 @@ export function zoom(view, resolution, opt_anchor, opt_duration, opt_direction)
|
|||||||
* @param {number=} opt_duration Duration.
|
* @param {number=} opt_duration Duration.
|
||||||
*/
|
*/
|
||||||
export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
|
export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
|
||||||
|
const currentZoom = view.getZoom();
|
||||||
const currentResolution = view.getResolution();
|
const currentResolution = view.getResolution();
|
||||||
let resolution = view.constrainResolution(currentResolution, delta, 0);
|
|
||||||
|
|
||||||
if (resolution !== undefined) {
|
if (currentZoom === undefined) {
|
||||||
const resolutions = view.getResolutions();
|
return;
|
||||||
resolution = clamp(
|
|
||||||
resolution,
|
|
||||||
view.getMinResolution() || resolutions[resolutions.length - 1],
|
|
||||||
view.getMaxResolution() || resolutions[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newZoom = view.getValidZoomLevel(currentZoom + delta);
|
||||||
|
const newResolution = view.getResolutionForZoom(newZoom);
|
||||||
|
|
||||||
// If we have a constraint on center, we need to change the anchor so that the
|
// If we have a constraint on center, we need to change the anchor so that the
|
||||||
// new center is within the extent. We first calculate the new center, apply
|
// new center is within the extent. We first calculate the new center, apply
|
||||||
// the constraint to it, and then calculate back the anchor
|
// the constraint to it, and then calculate back the anchor
|
||||||
if (opt_anchor && resolution !== undefined && resolution !== currentResolution) {
|
if (opt_anchor) {
|
||||||
const currentCenter = view.getCenter();
|
const currentCenter = view.getCenter();
|
||||||
let center = view.calculateCenterZoom(resolution, opt_anchor);
|
let center = view.calculateCenterZoom(newResolution, opt_anchor);
|
||||||
center = view.constrainCenter(center);
|
center = view.constrainCenter(center);
|
||||||
|
|
||||||
opt_anchor = [
|
opt_anchor = [
|
||||||
(resolution * currentCenter[0] - currentResolution * center[0]) /
|
(newResolution * currentCenter[0] - currentResolution * center[0]) /
|
||||||
(resolution - currentResolution),
|
(newResolution - currentResolution),
|
||||||
(resolution * currentCenter[1] - currentResolution * center[1]) /
|
(newResolution * currentCenter[1] - currentResolution * center[1]) /
|
||||||
(resolution - currentResolution)
|
(newResolution - currentResolution)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration);
|
if (opt_duration > 0) {
|
||||||
|
if (view.getAnimating()) {
|
||||||
|
view.cancelAnimations();
|
||||||
|
}
|
||||||
|
view.animate({
|
||||||
|
resolution: newResolution,
|
||||||
|
anchor: opt_anchor,
|
||||||
|
duration: opt_duration,
|
||||||
|
easing: easeOut
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (opt_anchor) {
|
||||||
|
const center = view.calculateCenterZoom(newResolution, opt_anchor);
|
||||||
|
view.setCenter(center);
|
||||||
|
}
|
||||||
|
view.setResolution(newResolution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -239,8 +239,10 @@ class MouseWheelZoom extends Interaction {
|
|||||||
view.setResolution(resolution);
|
view.setResolution(resolution);
|
||||||
|
|
||||||
if (rebound === 0 && this.constrainResolution_) {
|
if (rebound === 0 && this.constrainResolution_) {
|
||||||
|
const zoomDelta = delta > 0 ? -1 : 1;
|
||||||
|
const newZoom = view.getValidZoomLevel(view.getZoom() + zoomDelta);
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: view.constrainResolution(resolution, delta > 0 ? -1 : 1),
|
resolution: view.getResolutionForZoom(newZoom),
|
||||||
easing: easeOut,
|
easing: easeOut,
|
||||||
anchor: this.lastAnchor_,
|
anchor: this.lastAnchor_,
|
||||||
duration: this.duration_
|
duration: this.duration_
|
||||||
|
|||||||
@@ -1439,6 +1439,35 @@ describe('ol.View', function() {
|
|||||||
expect(view.getHints()[1]).to.be(0);
|
expect(view.getHints()[1]).to.be(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#getValidZoomLevel()', function() {
|
||||||
|
let view;
|
||||||
|
|
||||||
|
it('works correctly without constraint', function() {
|
||||||
|
view = new View({
|
||||||
|
zoom: 0
|
||||||
|
});
|
||||||
|
expect(view.getValidZoomLevel(3)).to.be(3);
|
||||||
|
});
|
||||||
|
it('works correctly with resolution constraints', function() {
|
||||||
|
view = new View({
|
||||||
|
zoom: 4,
|
||||||
|
minZoom: 4,
|
||||||
|
maxZoom: 8
|
||||||
|
});
|
||||||
|
expect(view.getValidZoomLevel(3)).to.be(4);
|
||||||
|
expect(view.getValidZoomLevel(10)).to.be(8);
|
||||||
|
});
|
||||||
|
it('works correctly with a specific resolution set', function() {
|
||||||
|
view = new View({
|
||||||
|
zoom: 0,
|
||||||
|
resolutions: [512, 256, 128, 64, 32, 16, 8]
|
||||||
|
});
|
||||||
|
expect(view.getValidZoomLevel(0)).to.be(0);
|
||||||
|
expect(view.getValidZoomLevel(4)).to.be(4);
|
||||||
|
expect(view.getValidZoomLevel(8)).to.be(6);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ol.View.isNoopAnimation()', function() {
|
describe('ol.View.isNoopAnimation()', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user