diff --git a/externs/olx.js b/externs/olx.js index 0575ca6d4b..41eada26e2 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -7562,7 +7562,10 @@ olx.view; * constrainResolution: (boolean|undefined), * nearest: (boolean|undefined), * maxZoom: (number|undefined), - * minResolution: (number|undefined)}} + * minResolution: (number|undefined), + * duration: (number|undefined), + * easing: (undefined|function(number):number) + * }} */ olx.view.FitOptions; @@ -7609,6 +7612,26 @@ olx.view.FitOptions.prototype.minResolution; olx.view.FitOptions.prototype.maxZoom; +/** + * The duration of the animation in milliseconds. By default, there is no + * animations. + * @type {number|undefined} + * @api + */ +olx.view.FitOptions.prototype.duration; + + +/** + * The easing function used during the animation (defaults to {@link ol.easing.inAndOut}). + * The function will be called for each frame with a number representing a + * fraction of the animation's duration. The function should return a number + * between 0 and 1 representing the progress toward the destination state. + * @type {undefined|function(number):number} + * @api + */ +olx.view.FitOptions.prototype.easing; + + /* typedefs for object literals exposed by the library */ diff --git a/src/ol/view.js b/src/ol/view.js index 5b5ef4550f..c7c1a68df0 100644 --- a/src/ol/view.js +++ b/src/ol/view.js @@ -735,7 +735,6 @@ ol.View.prototype.fit = function(geometry, size, opt_options) { } resolution = constrainedResolution; } - this.setResolution(resolution); // calculate center sinAngle = -sinAngle; // go back to original rotation @@ -745,8 +744,19 @@ ol.View.prototype.fit = function(geometry, size, opt_options) { centerRotY += (padding[0] - padding[2]) / 2 * resolution; var centerX = centerRotX * cosAngle - centerRotY * sinAngle; var centerY = centerRotY * cosAngle + centerRotX * sinAngle; + var center = [centerX, centerY]; - this.setCenter([centerX, centerY]); + if (options.duration !== undefined) { + this.animate({ + resolution: resolution, + center: center, + duration: options.duration, + easing: options.easing + }); + } else { + this.setResolution(resolution); + this.setCenter(center); + } }; diff --git a/test/spec/ol/view.test.js b/test/spec/ol/view.test.js index 2301a7c124..fae8818623 100644 --- a/test/spec/ol/view.test.js +++ b/test/spec/ol/view.test.js @@ -813,10 +813,30 @@ describe('ol.View', function() { }); describe('fit', function() { + + var originalRequestAnimationFrame = window.requestAnimationFrame; + var originalCancelAnimationFrame = window.cancelAnimationFrame; + + beforeEach(function() { + window.requestAnimationFrame = function(callback) { + return setTimeout(callback, 1); + }; + window.cancelAnimationFrame = function(key) { + return clearTimeout(key); + }; + }); + + afterEach(function() { + window.requestAnimationFrame = originalRequestAnimationFrame; + window.cancelAnimationFrame = originalCancelAnimationFrame; + }); + var view; beforeEach(function() { view = new ol.View({ - resolutions: [200, 100, 50, 20, 10, 5, 2, 1] + center: [0, 0], + resolutions: [200, 100, 50, 20, 10, 5, 2, 1], + zoom: 5 }); }); it('fits correctly to the geometry', function() { @@ -886,6 +906,27 @@ describe('ol.View', function() { view.fit(ol.extent.createEmpty(), [200, 200]); }).to.throwException(); }); + it('animates when duration is defined', function(done) { + view.fit( + new ol.geom.LineString([[6000, 46000], [6000, 47100], [7000, 46000]]), + [200, 200], + { + padding: [100, 0, 0, 100], + constrainResolution: false, + duration: 25 + }); + + expect(view.getAnimating()).to.eql(true); + + setTimeout(function() { + expect(view.getResolution()).to.be(11); + expect(view.getCenter()[0]).to.be(5950); + expect(view.getCenter()[1]).to.be(47100); + expect(view.getAnimating()).to.eql(false); + done(); + }, 50); + + }); }); describe('centerOn', function() {