From e52fab636c13c8da6937abb4fcb7814da890d0b9 Mon Sep 17 00:00:00 2001 From: jahow Date: Sat, 12 Jan 2019 23:47:02 +0100 Subject: [PATCH] View / apply constraints automatically based on hints All constraints can now function differently if they are applied during interaction or animation. --- src/ol/View.js | 51 +++++++++++++++++++--------------- src/ol/centerconstraint.js | 2 +- src/ol/resolutionconstraint.js | 16 +++++++++-- src/ol/rotationconstraint.js | 12 ++++++-- test/spec/ol/view.test.js | 1 + 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/ol/View.js b/src/ol/View.js index d697dc66bc..ee0cbb1eb4 100644 --- a/src/ol/View.js +++ b/src/ol/View.js @@ -449,9 +449,9 @@ class View extends BaseObject { return; } let start = Date.now(); - let center = this.getCenter().slice(); - let resolution = this.getResolution(); - let rotation = this.getRotation(); + let center = this.targetCenter_.slice(); + let resolution = this.targetResolution_; + let rotation = this.targetRotation_; const series = []; for (let i = 0; i < animationCount; ++i) { const options = /** @type {AnimationOptions} */ (arguments[i]); @@ -573,28 +573,27 @@ class View extends BaseObject { const y1 = animation.targetCenter[1]; const x = x0 + progress * (x1 - x0); const y = y0 + progress * (y1 - y0); - this.set(ViewProperty.CENTER, [x, y]); + this.targetCenter_ = [x, y]; } if (animation.sourceResolution && animation.targetResolution) { const resolution = progress === 1 ? animation.targetResolution : animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution); if (animation.anchor) { - this.set(ViewProperty.CENTER, - this.calculateCenterZoom(resolution, animation.anchor)); + this.targetCenter_ = this.calculateCenterZoom(resolution, animation.anchor); } - this.set(ViewProperty.RESOLUTION, resolution); + this.targetResolution_ = resolution; } if (animation.sourceRotation !== undefined && animation.targetRotation !== undefined) { const rotation = progress === 1 ? modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI : animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation); if (animation.anchor) { - this.set(ViewProperty.CENTER, - this.calculateCenterRotate(rotation, animation.anchor)); + this.targetCenter_ = this.calculateCenterRotate(rotation, animation.anchor); } - this.set(ViewProperty.ROTATION, rotation); + this.targetRotation_ = rotation; } + this.applyParameters_(true); more = true; if (!animation.complete) { break; @@ -623,10 +622,10 @@ class View extends BaseObject { */ calculateCenterRotate(rotation, anchor) { let center; - const currentCenter = this.getCenter(); + const currentCenter = this.targetCenter_; if (currentCenter !== undefined) { center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; - rotateCoordinate(center, rotation - this.getRotation()); + rotateCoordinate(center, rotation - this.targetRotation_); addCoordinate(center, anchor); } return center; @@ -639,8 +638,8 @@ class View extends BaseObject { */ calculateCenterZoom(resolution, anchor) { let center; - const currentCenter = this.getCenter(); - const currentResolution = this.getResolution(); + const currentCenter = this.targetCenter_; + const currentResolution = this.targetResolution_; if (currentCenter !== undefined && currentResolution !== undefined) { const x = anchor[0] - resolution * (anchor[0] - currentCenter[0]) / currentResolution; const y = anchor[1] - resolution * (anchor[1] - currentCenter[1]) / currentResolution; @@ -917,7 +916,7 @@ class View extends BaseObject { */ getZoom() { let zoom; - const resolution = this.getResolution(); + const resolution = this.targetResolution_; if (resolution !== undefined) { zoom = this.getZoomForResolution(resolution); } @@ -1059,8 +1058,9 @@ class View extends BaseObject { easing: options.easing }, callback); } else { - this.setResolution(resolution); - this.setCenter(center); + this.targetResolution_ = resolution; + this.targetCenter_ = center; + this.applyParameters_(false, true); animationCallback(callback, true); } } @@ -1167,14 +1167,21 @@ class View extends BaseObject { /** * Recompute rotation/resolution/center based on target values. + * @param {boolean=} opt_doNotCancelAnims Do not cancel animations. + * @param {boolean=} opt_forceMoving Apply constraints as if the view is moving. * @private */ - applyParameters_() { - this.set(ViewProperty.ROTATION, this.targetRotation_); - this.set(ViewProperty.RESOLUTION, this.targetResolution_); - this.set(ViewProperty.CENTER, this.targetCenter_); + applyParameters_(opt_doNotCancelAnims, opt_forceMoving) { + const isMoving = this.getAnimating() || this.getInteracting() || opt_forceMoving; + const newRotation = this.constraints_.rotation(this.targetRotation_, 0, isMoving); + const newResolution = this.constraints_.resolution(this.targetResolution_, 0, 0, isMoving); + const newCenter = this.constraints_.center(this.targetCenter_, isMoving); - if (this.getAnimating()) { + this.set(ViewProperty.ROTATION, newRotation); + this.set(ViewProperty.RESOLUTION, newResolution); + this.set(ViewProperty.CENTER, newCenter); + + if (this.getAnimating() && !opt_doNotCancelAnims) { this.cancelAnimations(); } } diff --git a/src/ol/centerconstraint.js b/src/ol/centerconstraint.js index 3d24463c8b..4c4fcfe23f 100644 --- a/src/ol/centerconstraint.js +++ b/src/ol/centerconstraint.js @@ -19,7 +19,7 @@ export function createExtent(extent) { * @param {import("./coordinate.js").Coordinate=} center Center. * @return {import("./coordinate.js").Coordinate|undefined} Center. */ - function(center) { + function(center, opt_isMoving) { if (center) { return [ clamp(center[0], extent[0], extent[2]), diff --git a/src/ol/resolutionconstraint.js b/src/ol/resolutionconstraint.js index 8e85618832..9a7d713888 100644 --- a/src/ol/resolutionconstraint.js +++ b/src/ol/resolutionconstraint.js @@ -22,8 +22,14 @@ export function createSnapToResolutions(resolutions) { * @param {number} direction Direction. * @return {number|undefined} Resolution. */ - function(resolution, delta, direction) { + function(resolution, delta, direction, opt_isMoving) { if (resolution !== undefined) { + // during interacting or animating, allow intermediary values + if (opt_isMoving) { + // TODO: actually take delta and direction into account + return resolution; + } + let z = linearFindNearest(resolutions, resolution, direction); z = clamp(z + delta, 0, resolutions.length - 1); const index = Math.floor(z); @@ -55,8 +61,14 @@ export function createSnapToPower(power, maxResolution, opt_maxLevel) { * @param {number} direction Direction. * @return {number|undefined} Resolution. */ - function(resolution, delta, direction) { + function(resolution, delta, direction, opt_isMoving) { if (resolution !== undefined) { + // during interacting or animating, allow intermediary values + if (opt_isMoving) { + // TODO: actually take delta and direction into account + return resolution; + } + const offset = -direction / 2 + 0.5; const oldLevel = Math.floor( Math.log(maxResolution / resolution) / Math.log(power) + offset); diff --git a/src/ol/rotationconstraint.js b/src/ol/rotationconstraint.js index 6abc294e42..5183f28572 100644 --- a/src/ol/rotationconstraint.js +++ b/src/ol/rotationconstraint.js @@ -49,7 +49,11 @@ export function createSnapToN(n) { * @param {number} delta Delta. * @return {number|undefined} Rotation. */ - function(rotation, delta) { + function(rotation, delta, opt_isMoving) { + if (opt_isMoving) { + return rotation; + } + if (rotation !== undefined) { rotation = Math.floor((rotation + delta) / theta + 0.5) * theta; return rotation; @@ -72,7 +76,11 @@ export function createSnapToZero(opt_tolerance) { * @param {number} delta Delta. * @return {number|undefined} Rotation. */ - function(rotation, delta) { + function(rotation, delta, opt_isMoving) { + if (opt_isMoving) { + return rotation; + } + if (rotation !== undefined) { if (Math.abs(rotation + delta) <= tolerance) { return 0; diff --git a/test/spec/ol/view.test.js b/test/spec/ol/view.test.js index 926748e6fa..453ca5d623 100644 --- a/test/spec/ol/view.test.js +++ b/test/spec/ol/view.test.js @@ -365,6 +365,7 @@ describe('ol.View', function() { it('applies the current resolution if resolution was originally supplied', function() { const view = new View({ center: [0, 0], + maxResolution: 2000, resolution: 1000 }); view.setResolution(500);