diff --git a/src/ol/View.js b/src/ol/View.js index c3645663d1..561af1cb39 100644 --- a/src/ol/View.js +++ b/src/ol/View.js @@ -21,6 +21,8 @@ import {clamp, modulo} from './math.js'; import {assign} from './obj.js'; import {createProjection, METERS_PER_UNIT} from './proj.js'; import Units from './proj/Units.js'; +import {equals} from './coordinate'; +import {easeOut} from './easing'; /** @@ -651,9 +653,10 @@ class View extends BaseObject { /** * @private + * @param {number|undefined} opt_rotation * @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found. */ - getSizeFromViewport_() { + getSizeFromViewport_(opt_rotation) { const size = [100, 100]; const selector = '.ol-viewport[data-view="' + getUid(this) + '"]'; const element = document.querySelector(selector); @@ -662,6 +665,10 @@ class View extends BaseObject { size[0] = parseInt(metrics.width, 10); size[1] = parseInt(metrics.height, 10); } + if (opt_rotation) { + size[0] = Math.abs(size[0] * Math.cos(opt_rotation)) + Math.abs(size[1] * Math.sin(opt_rotation)); + size[1] = Math.abs(size[0] * Math.sin(opt_rotation)) + Math.abs(size[1] * Math.cos(opt_rotation)); + } return size; } @@ -1164,18 +1171,10 @@ class View extends BaseObject { const isMoving = this.getAnimating() || this.getInteracting() || opt_forceMoving; // compute rotation - const newRotation = this.constraints_.rotation(this.targetRotation_, 0, isMoving); - - // compute viewport size with rotation - const size = this.getSizeFromViewport_(); - const rotation = this.getRotation() || 0; - const rotatedSize = [ - Math.abs(size[0] * Math.cos(rotation)) + Math.abs(size[1] * Math.sin(rotation)), - Math.abs(size[0] * Math.sin(rotation)) + Math.abs(size[1] * Math.cos(rotation)) - ]; - - const newResolution = this.constraints_.resolution(this.targetResolution_, 0, rotatedSize, isMoving); - const newCenter = this.constraints_.center(this.targetCenter_, newResolution, rotatedSize, isMoving); + const newRotation = this.constraints_.rotation(this.targetRotation_, isMoving); + const size = this.getSizeFromViewport_(newRotation); + const newResolution = this.constraints_.resolution(this.targetResolution_, 0, size, isMoving); + const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size, isMoving); this.set(ViewProperty.ROTATION, newRotation); this.set(ViewProperty.RESOLUTION, newResolution); @@ -1186,6 +1185,41 @@ class View extends BaseObject { } } + /** + * If any constraints need to be applied, an animation will be triggered. + * This is typically done on interaction end. + * @param {number=} opt_duration The animation duration in ms. + * @param {number=} opt_resolutionDirection Which direction to zoom. + * @observable + * @private + */ + resolveConstraints_(opt_duration, opt_resolutionDirection) { + const duration = opt_duration || 250; + const direction = opt_resolutionDirection || 0; + + const newRotation = this.constraints_.rotation(this.targetRotation_); + const size = this.getSizeFromViewport_(newRotation); + const newResolution = this.constraints_.resolution(this.targetResolution_, direction, size); + const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size); + + if (this.getResolution() !== newResolution || + this.getRotation() !== newRotation || + !equals(this.getCenter(), newCenter)) { + + if (this.getAnimating()) { + this.cancelAnimations(); + } + + this.animate({ + rotation: newRotation, + center: newCenter, + resolution: newResolution, + duration: duration, + easing: easeOut + }); + } + } + /** * Notify the View that an interaction has started. * @api @@ -1196,10 +1230,14 @@ class View extends BaseObject { /** * Notify the View that an interaction has ended. + * @param {number=} opt_duration Animation duration in ms. + * @param {number=} opt_resolutionDirection Which direction to zoom. * @api */ - endInteraction() { + endInteraction(opt_duration, opt_resolutionDirection) { this.setHint(ViewHint.INTERACTING, -1); + + this.resolveConstraints_(opt_duration, opt_resolutionDirection); } /** @@ -1227,14 +1265,9 @@ class View extends BaseObject { */ getValidResolution(targetResolution, opt_direction) { const direction = opt_direction || 0; - const size = this.getSizeFromViewport_(); - const rotation = this.getRotation() || 0; - const rotatedSize = [ - Math.abs(size[0] * Math.cos(rotation)) + Math.abs(size[1] * Math.sin(rotation)), - Math.abs(size[0] * Math.sin(rotation)) + Math.abs(size[1] * Math.cos(rotation)) - ]; + const size = this.getSizeFromViewport_(this.getRotation()); - return(this.constraints_.resolution(targetResolution, direction, rotatedSize)); + return(this.constraints_.resolution(targetResolution, direction, size)); } } diff --git a/src/ol/interaction/DragPan.js b/src/ol/interaction/DragPan.js index 020eb509ef..6f18683a40 100644 --- a/src/ol/interaction/DragPan.js +++ b/src/ol/interaction/DragPan.js @@ -74,10 +74,6 @@ class DragPan extends PointerInteraction { * @inheritDoc */ handleDragEvent(mapBrowserEvent) { - if (!this.panning_) { - this.panning_ = true; - this.getMap().getView().beginInteraction(); - } const targetPointers = this.targetPointers; const centroid = centroidFromPointers(targetPointers); if (targetPointers.length == this.lastPointersCount_) { @@ -152,7 +148,11 @@ class DragPan extends PointerInteraction { this.lastCentroid = null; // stop any current animation if (view.getAnimating()) { - view.setCenter(mapBrowserEvent.frameState.viewState.center); + view.cancelAnimations(); + } + if (!this.panning_) { + this.panning_ = true; + this.getMap().getView().beginInteraction(); } if (this.kinetic_) { this.kinetic_.begin(); diff --git a/src/ol/interaction/DragRotate.js b/src/ol/interaction/DragRotate.js index 09143c0d79..7d4d9a4be2 100644 --- a/src/ol/interaction/DragRotate.js +++ b/src/ol/interaction/DragRotate.js @@ -97,9 +97,7 @@ class DragRotate extends PointerInteraction { const map = mapBrowserEvent.map; const view = map.getView(); - view.endInteraction(); - const rotation = view.getRotation(); - rotate(view, rotation, undefined, this.duration_); + view.endInteraction(this.duration_); return false; } diff --git a/src/ol/interaction/DragRotateAndZoom.js b/src/ol/interaction/DragRotateAndZoom.js index 0bd024ed67..3f3d4d62c3 100644 --- a/src/ol/interaction/DragRotateAndZoom.js +++ b/src/ol/interaction/DragRotateAndZoom.js @@ -113,10 +113,8 @@ class DragRotateAndZoom extends PointerInteraction { const map = mapBrowserEvent.map; const view = map.getView(); - view.endInteraction(); const direction = this.lastScaleDelta_ - 1; - rotate(view, view.getRotation()); - zoom(view, view.getResolution(), undefined, this.duration_, direction); + view.endInteraction(this.duration_, direction); this.lastScaleDelta_ = 0; return false; } diff --git a/src/ol/interaction/PinchRotate.js b/src/ol/interaction/PinchRotate.js index fc40d7f851..fba8c0ff96 100644 --- a/src/ol/interaction/PinchRotate.js +++ b/src/ol/interaction/PinchRotate.js @@ -131,11 +131,7 @@ class PinchRotate extends PointerInteraction { if (this.targetPointers.length < 2) { const map = mapBrowserEvent.map; const view = map.getView(); - view.endInteraction(); - if (this.rotating_) { - const rotation = view.getRotation(); - rotate(view, rotation, this.anchor_, this.duration_); - } + view.endInteraction(this.duration_); return false; } else { return true; diff --git a/src/ol/interaction/PinchZoom.js b/src/ol/interaction/PinchZoom.js index 885e69b492..282d543138 100644 --- a/src/ol/interaction/PinchZoom.js +++ b/src/ol/interaction/PinchZoom.js @@ -126,17 +126,8 @@ class PinchZoom extends PointerInteraction { if (this.targetPointers.length < 2) { const map = mapBrowserEvent.map; const view = map.getView(); - view.endInteraction(); - const resolution = view.getResolution(); - if (this.constrainResolution_ || - resolution < view.getMinResolution() || - resolution > view.getMaxResolution()) { - // Zoom to final resolution, with an animation, and provide a - // direction not to zoom out/in if user was pinching in/out. - // Direction is > 0 if pinching out, and < 0 if pinching in. - const direction = this.lastScaleDelta_ - 1; - zoom(view, resolution, this.anchor_, this.duration_, direction); - } + const direction = this.lastScaleDelta_ - 1; + view.endInteraction(this.duration_, direction); return false; } else { return true; diff --git a/src/ol/rotationconstraint.js b/src/ol/rotationconstraint.js index 1efcc7f734..67c5183869 100644 --- a/src/ol/rotationconstraint.js +++ b/src/ol/rotationconstraint.js @@ -5,16 +5,15 @@ import {toRadians} from './math.js'; /** - * @typedef {function((number|undefined), number, boolean=): (number|undefined)} Type + * @typedef {function((number|undefined), boolean=): (number|undefined)} Type */ /** * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. * @return {number|undefined} Rotation. */ -export function disable(rotation, delta) { +export function disable(rotation) { if (rotation !== undefined) { return 0; } else { @@ -25,12 +24,11 @@ export function disable(rotation, delta) { /** * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. * @return {number|undefined} Rotation. */ -export function none(rotation, delta) { +export function none(rotation) { if (rotation !== undefined) { - return rotation + delta; + return rotation; } else { return undefined; } @@ -46,17 +44,16 @@ export function createSnapToN(n) { return ( /** * @param {number|undefined} rotation Rotation. - * @param {number} delta Delta. * @param {boolean=} opt_isMoving True if an interaction or animation is in progress. * @return {number|undefined} Rotation. */ - function(rotation, delta, opt_isMoving) { + function(rotation, opt_isMoving) { if (opt_isMoving) { return rotation; } if (rotation !== undefined) { - rotation = Math.floor((rotation + delta) / theta + 0.5) * theta; + rotation = Math.floor(rotation / theta + 0.5) * theta; return rotation; } else { return undefined; @@ -77,16 +74,16 @@ export function createSnapToZero(opt_tolerance) { * @param {number} delta Delta. * @return {number|undefined} Rotation. */ - function(rotation, delta, opt_isMoving) { + function(rotation, opt_isMoving) { if (opt_isMoving) { return rotation; } if (rotation !== undefined) { - if (Math.abs(rotation + delta) <= tolerance) { + if (Math.abs(rotation) <= tolerance) { return 0; } else { - return rotation + delta; + return rotation; } } else { return undefined; diff --git a/test/spec/ol/rotationconstraint.test.js b/test/spec/ol/rotationconstraint.test.js index f3e19a6119..c042ad4307 100644 --- a/test/spec/ol/rotationconstraint.test.js +++ b/test/spec/ol/rotationconstraint.test.js @@ -8,27 +8,15 @@ describe('ol.rotationconstraint', function() { it('returns expected rotation value', function() { const rotationConstraint = createSnapToZero(0.3); - expect(rotationConstraint(0.1, 0)).to.eql(0); - expect(rotationConstraint(0.2, 0)).to.eql(0); - expect(rotationConstraint(0.3, 0)).to.eql(0); - expect(rotationConstraint(0.4, 0)).to.eql(0.4); + expect(rotationConstraint(0.1)).to.eql(0); + expect(rotationConstraint(0.2)).to.eql(0); + expect(rotationConstraint(0.3)).to.eql(0); + expect(rotationConstraint(0.4)).to.eql(0.4); - expect(rotationConstraint(-0.1, 0)).to.eql(0); - expect(rotationConstraint(-0.2, 0)).to.eql(0); - expect(rotationConstraint(-0.3, 0)).to.eql(0); - expect(rotationConstraint(-0.4, 0)).to.eql(-0.4); - - expect(rotationConstraint(1, -0.9)).to.eql(0); - expect(rotationConstraint(1, -0.8)).to.eql(0); - // floating-point arithmetic - expect(rotationConstraint(1, -0.7)).not.to.eql(0); - expect(rotationConstraint(1, -0.6)).to.eql(0.4); - - expect(rotationConstraint(-1, 0.9)).to.eql(0); - expect(rotationConstraint(-1, 0.8)).to.eql(0); - // floating-point arithmetic - expect(rotationConstraint(-1, 0.7)).not.to.eql(0); - expect(rotationConstraint(-1, 0.6)).to.eql(-0.4); + expect(rotationConstraint(-0.1)).to.eql(0); + expect(rotationConstraint(-0.2)).to.eql(0); + expect(rotationConstraint(-0.3)).to.eql(0); + expect(rotationConstraint(-0.4)).to.eql(-0.4); }); });