Skip to content

Loading…

Rotate around arbitrary coordinate #1773

Closed
wants to merge 8 commits into from

3 participants

@elemoine
OpenLayers member

This PR makes it possible to rotate the view around any geographical position. This is useful for a navigation system where the current position (obtained through the geolocation API) is not displayed on the center of the map.

@elemoine
OpenLayers member

The build fails on all.combined.js. Checking now...

@twpayne

The code looks good, but in the animation example the "Rotate around Rome" button only works once. Maybe it should rotate by pi/4 each time it's clicked?

@elemoine
OpenLayers member

Build now passes.

Thanks @twpayne for the suggestion. I'll modify the example.

@elemoine
OpenLayers member

I've fixed the example. The example is available here: http://erilem.net/ol3/rotation-anchor/examples/animation.html.

@elemoine
OpenLayers member

Leaving this open for now. @pgiraud is going to test that in a real application.

@elemoine
OpenLayers member

Successfully tested by @pgiraud. And rebased onto the current master.

@twpayne

All looks good to me!

@fredj
OpenLayers member

+1 nice addition, thanks

@fredj
OpenLayers member

Is it ready to be merged?

@elemoine
OpenLayers member

I wanted to verify with @pgiraud that the patch works for him. I'll check with him before merging.

@fredj
OpenLayers member
@fredj
OpenLayers member

@elemoine , @pgiraud : I'm going to need this for a project soon; any objections to merge?

@elemoine
OpenLayers member

No, if it works for you then great.

@fredj
OpenLayers member

Thanks, see #1975

@fredj fredj closed this
@elemoine elemoine deleted the elemoine:rotation-anchor branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
1 examples/animation.html
@@ -32,6 +32,7 @@
<div class="span12">
<button id="rotate-left"><i class="icon-arrow-left"></i></button>
<button id="rotate-right"><i class="icon-arrow-right"></i></button>
+ <button id="rotate-around-rome">Rotate around Rome</button>
<button id="pan-to-london">Pan to London</button>
<button id="elastic-to-moscow">Elastic to Moscow</button>
<button id="bounce-to-istanbul">Bounce to Istanbul</button>
View
11 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() {
View
4 src/objectliterals.jsdoc
@@ -168,7 +168,9 @@
/**
* @typedef {Object} olx.animation.RotateOptions
- * @property {number} rotation The rotation to apply, in radians.
+ * @property {ol.Coordinate|undefined} anchor The rotation center/anchor. The map rotates around the center of the view
+ * if unspecified.
+ * @property {number|undefined} rotation The rotation value (in radians) to begin rotating from, typically `map.getView().getRotation()`. If `undefined` then `0` is assumed.
* @property {number|undefined} start The start time of the animation. Default is immediately.
* @property {number|undefined} duration The duration of the animation in milliseconds. Default is `1000`.
* @property {function(number):number|undefined} easing The easing function to use. Default is `ol.easing.inAndOut`
View
15 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 {
View
12 src/ol/coordinate.js
@@ -183,6 +183,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.
* @return {number} Squared distance between coord1 and coord2.
View
6 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);
}
};
View
1 src/ol/view2d.exports
@@ -5,4 +5,5 @@
@exportProperty ol.View2D.prototype.fitExtent
@exportProperty ol.View2D.prototype.getView2D
@exportProperty ol.View2D.prototype.getZoom
+@exportProperty ol.View2D.prototype.rotate
@exportProperty ol.View2D.prototype.setZoom
View
14 src/ol/view2d.js
@@ -440,6 +440,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.
* @todo stability experimental
Something went wrong with that request. Please try again.