diff --git a/examples/animation.html b/examples/animation.html
index 3eae57f489..dbe6d34ff3 100644
--- a/examples/animation.html
+++ b/examples/animation.html
@@ -32,6 +32,7 @@
+
diff --git a/examples/animation.js b/examples/animation.js
index a14ea27954..de211bde63 100644
--- a/examples/animation.js
+++ b/examples/animation.js
@@ -49,6 +49,17 @@ rotateRight.addEventListener('click', function() {
map.beforeRender(rotateRight);
}, false);
+var rotateAroundRome = document.getElementById('rotate-around-rome');
+rotateAroundRome.addEventListener('click', function() {
+ var currentRotation = view.getRotation();
+ var rotateAroundRome = ol.animation.rotate({
+ anchor: rome,
+ duration: 1000,
+ rotation: currentRotation
+ });
+ map.beforeRender(rotateAroundRome);
+ view.rotate(currentRotation + (Math.PI / 2), rome);
+}, false);
var panToLondon = document.getElementById('pan-to-london');
panToLondon.addEventListener('click', function() {
diff --git a/externs/olx.js b/externs/olx.js
index b9d52c6358..87b9d20619 100644
--- a/externs/olx.js
+++ b/externs/olx.js
@@ -544,7 +544,8 @@ olx.animation.PanOptions.prototype.easing;
/**
- * @typedef {{rotation: number,
+ * @typedef {{rotation: (number|undefined),
+ * anchor: (ol.Coordinate|undefined),
* start: (number|undefined),
* duration: (number|undefined),
* easing: (function(number):number|undefined)}}
@@ -554,12 +555,21 @@ olx.animation.RotateOptions;
/**
- * The rotation to apply, in radians.
- * @type {number}
+ * The rotation value (in radians) to begin rotating from, typically
+ * `map.getView().getRotation()`. If `undefined` then `0` is assumed.
+ * @type {number|undefined}
*/
olx.animation.RotateOptions.prototype.rotation;
+/**
+ * The rotation center/anchor. The map rotates around the center of the view
+ * if unspecified.
+ * @type {ol.Coordinate|undefined}
+ */
+olx.animation.RotateOptions.prototype.anchor;
+
+
/**
* The start time of the animation. Default is immediately.
* @type {number|undefined}
diff --git a/src/ol/animation.js b/src/ol/animation.js
index 938f838db9..50c69921d5 100644
--- a/src/ol/animation.js
+++ b/src/ol/animation.js
@@ -4,6 +4,7 @@ goog.provide('ol.animation');
goog.require('ol.PreRenderFunction');
goog.require('ol.ViewHint');
+goog.require('ol.coordinate');
goog.require('ol.easing');
@@ -87,11 +88,13 @@ ol.animation.pan = function(options) {
* @todo stability experimental
*/
ol.animation.rotate = function(options) {
- var sourceRotation = options.rotation;
+ var sourceRotation = goog.isDef(options.rotation) ? options.rotation : 0;
var start = goog.isDef(options.start) ? options.start : goog.now();
var duration = goog.isDef(options.duration) ? options.duration : 1000;
var easing = goog.isDef(options.easing) ?
options.easing : ol.easing.inAndOut;
+ var anchor = goog.isDef(options.anchor) ?
+ options.anchor : null;
return (
/**
@@ -106,9 +109,15 @@ ol.animation.rotate = function(options) {
} else if (frameState.time < start + duration) {
var delta = 1 - easing((frameState.time - start) / duration);
var deltaRotation =
- sourceRotation - frameState.view2DState.rotation;
+ (sourceRotation - frameState.view2DState.rotation) * delta;
frameState.animate = true;
- frameState.view2DState.rotation += delta * deltaRotation;
+ frameState.view2DState.rotation += deltaRotation;
+ if (!goog.isNull(anchor)) {
+ var center = frameState.view2DState.center;
+ ol.coordinate.sub(center, anchor);
+ ol.coordinate.rotate(center, deltaRotation);
+ ol.coordinate.add(center, anchor);
+ }
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else {
diff --git a/src/ol/coordinate.js b/src/ol/coordinate.js
index 81838416aa..c34247c41f 100644
--- a/src/ol/coordinate.js
+++ b/src/ol/coordinate.js
@@ -182,6 +182,18 @@ ol.coordinate.scale = function(coordinate, s) {
};
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Coordinate} delta Delta.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.coordinate.sub = function(coordinate, delta) {
+ coordinate[0] -= delta[0];
+ coordinate[1] -= delta[1];
+ return coordinate;
+};
+
+
/**
* @param {ol.Coordinate} coord1 First coordinate.
* @param {ol.Coordinate} coord2 Second coordinate.
diff --git a/src/ol/interaction/interaction.js b/src/ol/interaction/interaction.js
index dbc57deee1..307b6e07d3 100644
--- a/src/ol/interaction/interaction.js
+++ b/src/ol/interaction/interaction.js
@@ -128,11 +128,7 @@ ol.interaction.Interaction.rotateWithoutConstraints =
}
}
goog.asserts.assertInstanceof(view, ol.View2D);
- if (goog.isDefAndNotNull(opt_anchor)) {
- var center = view.calculateCenterRotate(rotation, opt_anchor);
- view.setCenter(center);
- }
- view.setRotation(rotation);
+ view.rotate(rotation, opt_anchor);
}
};
diff --git a/src/ol/view2d.exports b/src/ol/view2d.exports
index 01d44dd7b5..e665804784 100644
--- a/src/ol/view2d.exports
+++ b/src/ol/view2d.exports
@@ -7,4 +7,5 @@
@exportProperty ol.View2D.prototype.centerOn
@exportProperty ol.View2D.prototype.getView2D
@exportProperty ol.View2D.prototype.getZoom
+@exportProperty ol.View2D.prototype.rotate
@exportProperty ol.View2D.prototype.setZoom
diff --git a/src/ol/view2d.js b/src/ol/view2d.js
index b87e6dfe58..e8df7039b1 100644
--- a/src/ol/view2d.js
+++ b/src/ol/view2d.js
@@ -534,6 +534,20 @@ ol.View2D.prototype.isDef = function() {
};
+/**
+ * Rotate the view around a given coordinate.
+ * @param {number} rotation New rotation value for the view.
+ * @param {ol.Coordinate=} opt_anchor The rotation center.
+ */
+ol.View2D.prototype.rotate = function(rotation, opt_anchor) {
+ if (goog.isDef(opt_anchor)) {
+ var center = this.calculateCenterRotate(rotation, opt_anchor);
+ this.setCenter(center);
+ }
+ this.setRotation(rotation);
+};
+
+
/**
* Set the center of the current view.
* @param {ol.Coordinate|undefined} center Center.