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.