View / add a resolveConstraints method to end interactions
This will help making sure that the view will come back to a "rested" state once the interactions are over. Interactions no longer need to handle the animation back to a rested state, they simply call `endInteraction` with the desired duration and direction.
This commit is contained in:
+54
-21
@@ -21,6 +21,8 @@ import {clamp, modulo} from './math.js';
|
|||||||
import {assign} from './obj.js';
|
import {assign} from './obj.js';
|
||||||
import {createProjection, METERS_PER_UNIT} from './proj.js';
|
import {createProjection, METERS_PER_UNIT} from './proj.js';
|
||||||
import Units from './proj/Units.js';
|
import Units from './proj/Units.js';
|
||||||
|
import {equals} from './coordinate';
|
||||||
|
import {easeOut} from './easing';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -651,9 +653,10 @@ class View extends BaseObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {number|undefined} opt_rotation
|
||||||
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
||||||
*/
|
*/
|
||||||
getSizeFromViewport_() {
|
getSizeFromViewport_(opt_rotation) {
|
||||||
const size = [100, 100];
|
const size = [100, 100];
|
||||||
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
||||||
const element = document.querySelector(selector);
|
const element = document.querySelector(selector);
|
||||||
@@ -662,6 +665,10 @@ class View extends BaseObject {
|
|||||||
size[0] = parseInt(metrics.width, 10);
|
size[0] = parseInt(metrics.width, 10);
|
||||||
size[1] = parseInt(metrics.height, 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;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1164,18 +1171,10 @@ class View extends BaseObject {
|
|||||||
const isMoving = this.getAnimating() || this.getInteracting() || opt_forceMoving;
|
const isMoving = this.getAnimating() || this.getInteracting() || opt_forceMoving;
|
||||||
|
|
||||||
// compute rotation
|
// compute rotation
|
||||||
const newRotation = this.constraints_.rotation(this.targetRotation_, 0, isMoving);
|
const newRotation = this.constraints_.rotation(this.targetRotation_, isMoving);
|
||||||
|
const size = this.getSizeFromViewport_(newRotation);
|
||||||
// compute viewport size with rotation
|
const newResolution = this.constraints_.resolution(this.targetResolution_, 0, size, isMoving);
|
||||||
const size = this.getSizeFromViewport_();
|
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size, isMoving);
|
||||||
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);
|
|
||||||
|
|
||||||
this.set(ViewProperty.ROTATION, newRotation);
|
this.set(ViewProperty.ROTATION, newRotation);
|
||||||
this.set(ViewProperty.RESOLUTION, newResolution);
|
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.
|
* Notify the View that an interaction has started.
|
||||||
* @api
|
* @api
|
||||||
@@ -1196,10 +1230,14 @@ class View extends BaseObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the View that an interaction has ended.
|
* 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
|
* @api
|
||||||
*/
|
*/
|
||||||
endInteraction() {
|
endInteraction(opt_duration, opt_resolutionDirection) {
|
||||||
this.setHint(ViewHint.INTERACTING, -1);
|
this.setHint(ViewHint.INTERACTING, -1);
|
||||||
|
|
||||||
|
this.resolveConstraints_(opt_duration, opt_resolutionDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1227,14 +1265,9 @@ class View extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
getValidResolution(targetResolution, opt_direction) {
|
getValidResolution(targetResolution, opt_direction) {
|
||||||
const direction = opt_direction || 0;
|
const direction = opt_direction || 0;
|
||||||
const size = this.getSizeFromViewport_();
|
const size = this.getSizeFromViewport_(this.getRotation());
|
||||||
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))
|
|
||||||
];
|
|
||||||
|
|
||||||
return(this.constraints_.resolution(targetResolution, direction, rotatedSize));
|
return(this.constraints_.resolution(targetResolution, direction, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,10 +74,6 @@ class DragPan extends PointerInteraction {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
handleDragEvent(mapBrowserEvent) {
|
handleDragEvent(mapBrowserEvent) {
|
||||||
if (!this.panning_) {
|
|
||||||
this.panning_ = true;
|
|
||||||
this.getMap().getView().beginInteraction();
|
|
||||||
}
|
|
||||||
const targetPointers = this.targetPointers;
|
const targetPointers = this.targetPointers;
|
||||||
const centroid = centroidFromPointers(targetPointers);
|
const centroid = centroidFromPointers(targetPointers);
|
||||||
if (targetPointers.length == this.lastPointersCount_) {
|
if (targetPointers.length == this.lastPointersCount_) {
|
||||||
@@ -152,7 +148,11 @@ class DragPan extends PointerInteraction {
|
|||||||
this.lastCentroid = null;
|
this.lastCentroid = null;
|
||||||
// stop any current animation
|
// stop any current animation
|
||||||
if (view.getAnimating()) {
|
if (view.getAnimating()) {
|
||||||
view.setCenter(mapBrowserEvent.frameState.viewState.center);
|
view.cancelAnimations();
|
||||||
|
}
|
||||||
|
if (!this.panning_) {
|
||||||
|
this.panning_ = true;
|
||||||
|
this.getMap().getView().beginInteraction();
|
||||||
}
|
}
|
||||||
if (this.kinetic_) {
|
if (this.kinetic_) {
|
||||||
this.kinetic_.begin();
|
this.kinetic_.begin();
|
||||||
|
|||||||
@@ -97,9 +97,7 @@ class DragRotate extends PointerInteraction {
|
|||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction();
|
view.endInteraction(this.duration_);
|
||||||
const rotation = view.getRotation();
|
|
||||||
rotate(view, rotation, undefined, this.duration_);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,10 +113,8 @@ class DragRotateAndZoom extends PointerInteraction {
|
|||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction();
|
|
||||||
const direction = this.lastScaleDelta_ - 1;
|
const direction = this.lastScaleDelta_ - 1;
|
||||||
rotate(view, view.getRotation());
|
view.endInteraction(this.duration_, direction);
|
||||||
zoom(view, view.getResolution(), undefined, this.duration_, direction);
|
|
||||||
this.lastScaleDelta_ = 0;
|
this.lastScaleDelta_ = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,11 +131,7 @@ class PinchRotate extends PointerInteraction {
|
|||||||
if (this.targetPointers.length < 2) {
|
if (this.targetPointers.length < 2) {
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction();
|
view.endInteraction(this.duration_);
|
||||||
if (this.rotating_) {
|
|
||||||
const rotation = view.getRotation();
|
|
||||||
rotate(view, rotation, this.anchor_, this.duration_);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -126,17 +126,8 @@ class PinchZoom extends PointerInteraction {
|
|||||||
if (this.targetPointers.length < 2) {
|
if (this.targetPointers.length < 2) {
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction();
|
const direction = this.lastScaleDelta_ - 1;
|
||||||
const resolution = view.getResolution();
|
view.endInteraction(this.duration_, direction);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -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|undefined} rotation Rotation.
|
||||||
* @param {number} delta Delta.
|
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
export function disable(rotation, delta) {
|
export function disable(rotation) {
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -25,12 +24,11 @@ export function disable(rotation, delta) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
* @param {number} delta Delta.
|
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
export function none(rotation, delta) {
|
export function none(rotation) {
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
return rotation + delta;
|
return rotation;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -46,17 +44,16 @@ export function createSnapToN(n) {
|
|||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
* @param {number} delta Delta.
|
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
function(rotation, delta, opt_isMoving) {
|
function(rotation, opt_isMoving) {
|
||||||
if (opt_isMoving) {
|
if (opt_isMoving) {
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;
|
rotation = Math.floor(rotation / theta + 0.5) * theta;
|
||||||
return rotation;
|
return rotation;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -77,16 +74,16 @@ export function createSnapToZero(opt_tolerance) {
|
|||||||
* @param {number} delta Delta.
|
* @param {number} delta Delta.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
function(rotation, delta, opt_isMoving) {
|
function(rotation, opt_isMoving) {
|
||||||
if (opt_isMoving) {
|
if (opt_isMoving) {
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
if (Math.abs(rotation + delta) <= tolerance) {
|
if (Math.abs(rotation) <= tolerance) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return rotation + delta;
|
return rotation;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -8,27 +8,15 @@ describe('ol.rotationconstraint', function() {
|
|||||||
it('returns expected rotation value', function() {
|
it('returns expected rotation value', function() {
|
||||||
const rotationConstraint = createSnapToZero(0.3);
|
const rotationConstraint = createSnapToZero(0.3);
|
||||||
|
|
||||||
expect(rotationConstraint(0.1, 0)).to.eql(0);
|
expect(rotationConstraint(0.1)).to.eql(0);
|
||||||
expect(rotationConstraint(0.2, 0)).to.eql(0);
|
expect(rotationConstraint(0.2)).to.eql(0);
|
||||||
expect(rotationConstraint(0.3, 0)).to.eql(0);
|
expect(rotationConstraint(0.3)).to.eql(0);
|
||||||
expect(rotationConstraint(0.4, 0)).to.eql(0.4);
|
expect(rotationConstraint(0.4)).to.eql(0.4);
|
||||||
|
|
||||||
expect(rotationConstraint(-0.1, 0)).to.eql(0);
|
expect(rotationConstraint(-0.1)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.2, 0)).to.eql(0);
|
expect(rotationConstraint(-0.2)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.3, 0)).to.eql(0);
|
expect(rotationConstraint(-0.3)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.4, 0)).to.eql(-0.4);
|
expect(rotationConstraint(-0.4)).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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user