View / add adjust* methods to manipulate the view more easily
API changes: * (breaking) the `rotate` method is gone * the `adjustRotation`, `adjustResolution` and `adjustZoom` methods are now available and allow using an anchor. This means interactions do not have to do the anchor computation themselves and this also fix anchor computation when constraints must be applied.
This commit is contained in:
@@ -635,10 +635,10 @@ class View extends BaseObject {
|
||||
*/
|
||||
calculateCenterRotate(rotation, anchor) {
|
||||
let center;
|
||||
const currentCenter = this.targetCenter_;
|
||||
const currentCenter = this.getCenter();
|
||||
if (currentCenter !== undefined) {
|
||||
center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];
|
||||
rotateCoordinate(center, rotation - this.targetRotation_);
|
||||
rotateCoordinate(center, rotation - this.getRotation());
|
||||
addCoordinate(center, anchor);
|
||||
}
|
||||
return center;
|
||||
@@ -651,8 +651,8 @@ class View extends BaseObject {
|
||||
*/
|
||||
calculateCenterZoom(resolution, anchor) {
|
||||
let center;
|
||||
const currentCenter = this.targetCenter_;
|
||||
const currentResolution = this.targetResolution_;
|
||||
const currentCenter = this.getCenter();
|
||||
const currentResolution = this.getResolution();
|
||||
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;
|
||||
@@ -1123,17 +1123,50 @@ class View extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the view around a given coordinate.
|
||||
* @param {number} rotation New rotation value for the view.
|
||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The rotation center.
|
||||
* Multiply the view resolution by a ratio, optionally using an anchor.
|
||||
* @param {number} ratio The ratio to apply on the view resolution.
|
||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
rotate(rotation, opt_anchor) {
|
||||
adjustResolution(ratio, opt_anchor) {
|
||||
const isMoving = this.getAnimating() || this.getInteracting();
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_ * ratio, 0, size, isMoving);
|
||||
|
||||
if (opt_anchor !== undefined) {
|
||||
const center = this.calculateCenterRotate(rotation, opt_anchor);
|
||||
this.setCenter(center);
|
||||
this.targetCenter_ = this.calculateCenterZoom(newResolution, opt_anchor);
|
||||
}
|
||||
this.setRotation(rotation);
|
||||
|
||||
this.targetResolution_ *= ratio;
|
||||
this.applyParameters_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the view zoom level, optionally using an anchor.
|
||||
* @param {number} delta Relative value to add to the zoom level.
|
||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
||||
* @api
|
||||
*/
|
||||
adjustZoom(delta, opt_anchor) {
|
||||
this.adjustResolution(Math.pow(this.zoomFactor_, -delta), opt_anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the view rotation, optionally using an anchor.
|
||||
* @param {number} delta Relative value to add to the zoom rotation, in radians.
|
||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The rotation center.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
adjustRotation(delta, opt_anchor) {
|
||||
const isMoving = this.getAnimating() || this.getInteracting();
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_ + delta, isMoving);
|
||||
if (opt_anchor !== undefined) {
|
||||
this.targetCenter_ = this.calculateCenterRotate(newRotation, opt_anchor);
|
||||
}
|
||||
this.targetRotation_ += delta;
|
||||
this.applyParameters_();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1206,9 +1239,15 @@ class View extends BaseObject {
|
||||
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);
|
||||
this.set(ViewProperty.CENTER, newCenter);
|
||||
if (this.get(ViewProperty.ROTATION) !== newRotation) {
|
||||
this.set(ViewProperty.ROTATION, newRotation);
|
||||
}
|
||||
if (this.get(ViewProperty.RESOLUTION) !== newResolution) {
|
||||
this.set(ViewProperty.RESOLUTION, newResolution);
|
||||
}
|
||||
if (!this.get(ViewProperty.CENTER) || !equals(this.get(ViewProperty.CENTER), newCenter)) {
|
||||
this.set(ViewProperty.CENTER, newCenter);
|
||||
}
|
||||
|
||||
if (this.getAnimating() && !opt_doNotCancelAnims) {
|
||||
this.cancelAnimations();
|
||||
|
||||
@@ -80,8 +80,7 @@ class DragRotate extends PointerInteraction {
|
||||
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
|
||||
if (this.lastAngle_ !== undefined) {
|
||||
const delta = theta - this.lastAngle_;
|
||||
const rotation = view.getRotation();
|
||||
rotate(view, rotation - delta);
|
||||
view.adjustRotation(-delta);
|
||||
}
|
||||
this.lastAngle_ = theta;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import {disable} from '../rotationconstraint.js';
|
||||
import ViewHint from '../ViewHint.js';
|
||||
import {shiftKeyOnly, mouseOnly} from '../events/condition.js';
|
||||
import {rotate, zoom} from './Interaction.js';
|
||||
import PointerInteraction from './Pointer.js';
|
||||
|
||||
|
||||
@@ -88,14 +87,13 @@ class DragRotateAndZoom extends PointerInteraction {
|
||||
const theta = Math.atan2(deltaY, deltaX);
|
||||
const magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
const view = map.getView();
|
||||
if (view.getConstraints().rotation !== disable && this.lastAngle_ !== undefined) {
|
||||
const angleDelta = theta - this.lastAngle_;
|
||||
rotate(view, view.getRotation() - angleDelta);
|
||||
if (this.lastAngle_ !== undefined) {
|
||||
const angleDelta = this.lastAngle_ - theta;
|
||||
view.adjustRotation(angleDelta);
|
||||
}
|
||||
this.lastAngle_ = theta;
|
||||
if (this.lastMagnitude_ !== undefined) {
|
||||
const resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);
|
||||
zoom(view, resolution);
|
||||
view.adjustResolution(this.lastMagnitude_ / magnitude);
|
||||
}
|
||||
if (this.lastMagnitude_ !== undefined) {
|
||||
this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
|
||||
|
||||
@@ -111,80 +111,14 @@ export function pan(view, delta, opt_duration) {
|
||||
const currentCenter = view.getCenter();
|
||||
if (currentCenter) {
|
||||
const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
|
||||
if (opt_duration) {
|
||||
view.animate({
|
||||
duration: opt_duration,
|
||||
easing: linear,
|
||||
center: center
|
||||
});
|
||||
} else {
|
||||
view.setCenter(center);
|
||||
}
|
||||
view.animate({
|
||||
duration: opt_duration !== undefined ? opt_duration : 250,
|
||||
easing: linear,
|
||||
center: center
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {import("../View.js").default} view View.
|
||||
* @param {number|undefined} rotation Rotation.
|
||||
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
export function rotate(view, rotation, opt_anchor, opt_duration) {
|
||||
if (rotation !== undefined) {
|
||||
const currentRotation = view.getRotation();
|
||||
const currentCenter = view.getCenter();
|
||||
if (currentRotation !== undefined && currentCenter && opt_duration > 0) {
|
||||
view.animate({
|
||||
rotation: rotation,
|
||||
anchor: opt_anchor,
|
||||
duration: opt_duration,
|
||||
easing: easeOut
|
||||
});
|
||||
} else {
|
||||
view.rotate(rotation, opt_anchor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {import("../View.js").default} view View.
|
||||
* @param {number|undefined} resolution Resolution to go to.
|
||||
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
* @param {number=} opt_direction Zooming direction; > 0 indicates
|
||||
* zooming out, in which case the constraints system will select
|
||||
* the largest nearest resolution; < 0 indicates zooming in, in
|
||||
* which case the constraints system will select the smallest
|
||||
* nearest resolution; == 0 indicates that the zooming direction
|
||||
* is unknown/not relevant, in which case the constraints system
|
||||
* will select the nearest resolution. If not defined 0 is
|
||||
* assumed.
|
||||
*/
|
||||
export function zoom(view, resolution, opt_anchor, opt_duration, opt_direction) {
|
||||
if (resolution) {
|
||||
const currentResolution = view.getResolution();
|
||||
const currentCenter = view.getCenter();
|
||||
if (currentResolution !== undefined && currentCenter &&
|
||||
resolution !== currentResolution && opt_duration) {
|
||||
view.animate({
|
||||
resolution: resolution,
|
||||
anchor: opt_anchor,
|
||||
duration: opt_duration,
|
||||
easing: easeOut
|
||||
});
|
||||
} else {
|
||||
if (opt_anchor) {
|
||||
const center = view.calculateCenterZoom(resolution, opt_anchor);
|
||||
view.setCenter(center);
|
||||
}
|
||||
view.setResolution(resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {import("../View.js").default} view View.
|
||||
* @param {number} delta Delta from previous zoom level.
|
||||
@@ -201,23 +135,15 @@ export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
|
||||
const newZoom = view.getValidZoomLevel(currentZoom + delta);
|
||||
const newResolution = view.getResolutionForZoom(newZoom);
|
||||
|
||||
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);
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
}
|
||||
view.animate({
|
||||
resolution: newResolution,
|
||||
anchor: opt_anchor,
|
||||
duration: opt_duration !== undefined ? opt_duration : 250,
|
||||
easing: easeOut
|
||||
});
|
||||
}
|
||||
|
||||
export default Interaction;
|
||||
|
||||
@@ -212,49 +212,7 @@ class MouseWheelZoom extends Interaction {
|
||||
view.beginInteraction();
|
||||
}
|
||||
this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);
|
||||
let resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
|
||||
const minResolution = view.getMinResolution();
|
||||
const maxResolution = view.getMaxResolution();
|
||||
let rebound = 0;
|
||||
if (resolution < minResolution) {
|
||||
resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
|
||||
rebound = 1;
|
||||
} else if (resolution > maxResolution) {
|
||||
resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
|
||||
rebound = -1;
|
||||
}
|
||||
if (this.lastAnchor_) {
|
||||
const center = view.calculateCenterZoom(resolution, this.lastAnchor_);
|
||||
view.setCenter(center);
|
||||
}
|
||||
view.setResolution(resolution);
|
||||
|
||||
if (rebound === 0) {
|
||||
const zoomDelta = delta > 0 ? -1 : 1;
|
||||
const newZoom = view.getValidZoomLevel(view.getZoom() + zoomDelta);
|
||||
view.animate({
|
||||
resolution: view.getResolutionForZoom(newZoom),
|
||||
easing: easeOut,
|
||||
anchor: this.lastAnchor_,
|
||||
duration: this.duration_
|
||||
});
|
||||
}
|
||||
|
||||
if (rebound > 0) {
|
||||
view.animate({
|
||||
resolution: minResolution,
|
||||
easing: easeOut,
|
||||
anchor: this.lastAnchor_,
|
||||
duration: 500
|
||||
});
|
||||
} else if (rebound < 0) {
|
||||
view.animate({
|
||||
resolution: maxResolution,
|
||||
easing: easeOut,
|
||||
anchor: this.lastAnchor_,
|
||||
duration: 500
|
||||
});
|
||||
}
|
||||
view.adjustZoom(-delta / this.trackpadDeltaPerZoom_, this.lastAnchor_);
|
||||
this.startTime_ = now;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -118,9 +118,8 @@ class PinchRotate extends PointerInteraction {
|
||||
|
||||
// rotate
|
||||
if (this.rotating_) {
|
||||
const rotation = view.getRotation();
|
||||
map.render();
|
||||
rotate(view, rotation + rotationDelta, this.anchor_);
|
||||
view.adjustRotation(rotationDelta, this.anchor_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,17 +83,6 @@ class PinchZoom extends PointerInteraction {
|
||||
|
||||
const map = mapBrowserEvent.map;
|
||||
const view = map.getView();
|
||||
const resolution = view.getResolution();
|
||||
const maxResolution = view.getMaxResolution();
|
||||
const minResolution = view.getMinResolution();
|
||||
let newResolution = resolution * scaleDelta;
|
||||
if (newResolution > maxResolution) {
|
||||
scaleDelta = maxResolution / resolution;
|
||||
newResolution = maxResolution;
|
||||
} else if (newResolution < minResolution) {
|
||||
scaleDelta = minResolution / resolution;
|
||||
newResolution = minResolution;
|
||||
}
|
||||
|
||||
if (scaleDelta != 1.0) {
|
||||
this.lastScaleDelta_ = scaleDelta;
|
||||
@@ -108,7 +97,7 @@ class PinchZoom extends PointerInteraction {
|
||||
|
||||
// scale, bypass the resolution constraint
|
||||
map.render();
|
||||
zoom(view, newResolution, this.anchor_);
|
||||
view.adjustResolution(scaleDelta, this.anchor_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +107,7 @@ class PinchZoom extends PointerInteraction {
|
||||
if (this.targetPointers.length < 2) {
|
||||
const map = mapBrowserEvent.map;
|
||||
const view = map.getView();
|
||||
const direction = this.lastScaleDelta_ - 1;
|
||||
const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
|
||||
view.endInteraction(this.duration_, direction);
|
||||
return false;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user