diff --git a/src/ol/resolutionconstraint.js b/src/ol/resolutionconstraint.js index 98b1fd8b61..023bd61da5 100644 --- a/src/ol/resolutionconstraint.js +++ b/src/ol/resolutionconstraint.js @@ -21,7 +21,13 @@ ol.ResolutionConstraint.createSnapToResolutions = function(resolutions) { var z = ol.array.linearFindNearest(resolutions, resolution, direction); z = ol.math.clamp(z + delta, 0, resolutions.length - 1); - return resolutions[z]; + var index = Math.floor(z); + if (z != index && index < resolutions.length - 1) { + var power = resolutions[index] / resolutions[index + 1]; + return resolutions[index] / Math.pow(power, z - index); + } else { + return resolutions[index]; + } } else { return undefined; } @@ -45,14 +51,7 @@ ol.ResolutionConstraint.createSnapToPower = function(power, maxResolution, opt_m */ function(resolution, delta, direction) { if (resolution !== undefined) { - var offset; - if (direction > 0) { - offset = 0; - } else if (direction < 0) { - offset = 1; - } else { - offset = 0.5; - } + var offset = -direction / 2 + 0.5; var oldLevel = Math.floor( Math.log(maxResolution / resolution) / Math.log(power) + offset); var newLevel = Math.max(oldLevel + delta, 0); diff --git a/src/ol/view.js b/src/ol/view.js index b0ce90cfc5..07678fe31d 100644 --- a/src/ol/view.js +++ b/src/ol/view.js @@ -134,6 +134,12 @@ ol.View = function(opt_options) { */ this.minResolution_ = resolutionConstraintInfo.minResolution; + /** + * @private + * @type {number} + */ + this.zoomFactor_ = resolutionConstraintInfo.zoomFactor; + /** * @private * @type {Array.|undefined} @@ -453,27 +459,32 @@ ol.View.prototype.getState = function() { /** * Get the current zoom level. Return undefined if the current - * resolution is undefined or not a "constrained resolution". + * resolution is undefined or not within the "resolution constraints". * @return {number|undefined} Zoom. * @api stable */ ol.View.prototype.getZoom = function() { - var offset; + var zoom; var resolution = this.getResolution(); - - if (resolution !== undefined) { - var res, z = 0; - do { - res = this.constrainResolution(this.maxResolution_, z); - if (res == resolution) { - offset = z; - break; + if (resolution !== undefined && + resolution >= this.minResolution_ && resolution <= this.maxResolution_) { + var offset = this.minZoom_ || 0; + var max, zoomFactor; + if (this.resolutions_) { + var nearest = ol.array.linearFindNearest(this.resolutions_, resolution, 1); + offset += nearest; + if (nearest == this.resolutions_.length - 1) { + return offset; } - ++z; - } while (res > this.minResolution_); + max = this.resolutions_[nearest]; + zoomFactor = max / this.resolutions_[nearest + 1]; + } else { + max = this.maxResolution_; + zoomFactor = this.zoomFactor_; + } + zoom = offset + Math.log(max / resolution) / Math.log(zoomFactor); } - - return offset !== undefined ? this.minZoom_ + offset : offset; + return zoom; }; @@ -689,7 +700,7 @@ ol.View.createCenterConstraint_ = function(options) { * @private * @param {olx.ViewOptions} options View options. * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number, - * minResolution: number}} The constraint. + * minResolution: number, zoomFactor: number}} The constraint. */ ol.View.createResolutionConstraint_ = function(options) { var resolutionConstraint; @@ -763,7 +774,7 @@ ol.View.createResolutionConstraint_ = function(options) { zoomFactor, maxResolution, maxZoom - minZoom); } return {constraint: resolutionConstraint, maxResolution: maxResolution, - minResolution: minResolution, minZoom: minZoom}; + minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor}; }; diff --git a/test/spec/ol/view.test.js b/test/spec/ol/view.test.js index b7bfbe1158..212bf445aa 100644 --- a/test/spec/ol/view.test.js +++ b/test/spec/ol/view.test.js @@ -323,17 +323,20 @@ describe('ol.View', function() { view.setResolution(undefined); expect(view.getZoom()).to.be(undefined); - view.setResolution(511); + view.setResolution(513); expect(view.getZoom()).to.be(undefined); view.setResolution(512); expect(view.getZoom()).to.be(0); - view.setResolution(64); - expect(view.getZoom()).to.be(3); + view.setResolution(100); + expect(view.getZoom()).to.roughlyEqual(2.35614, 1e-5); view.setResolution(65); - expect(view.getZoom()).to.be(undefined); + expect(view.getZoom()).to.roughlyEqual(2.97763, 1e-5); + + view.setResolution(64); + expect(view.getZoom()).to.be(3); view.setResolution(16); expect(view.getZoom()).to.be(5); @@ -341,6 +344,28 @@ describe('ol.View', function() { view.setResolution(15); expect(view.getZoom()).to.be(undefined); }); + + it('works for resolution arrays with variable zoom factors', function() { + var view = new ol.View({ + resolutions: [10, 5, 2, 1] + }); + + view.setZoom(1); + expect(view.getZoom()).to.be(1); + + view.setZoom(1.3); + expect(view.getZoom()).to.be(1.3); + + view.setZoom(2); + expect(view.getZoom()).to.be(2); + + view.setZoom(2.7); + expect(view.getZoom()).to.be(2.7); + + view.setZoom(3); + expect(view.getZoom()).to.be(3); + + }); }); describe('#getZoom() - constrained', function() { @@ -359,6 +384,9 @@ describe('ol.View', function() { view.setZoom(15); expect(view.getZoom()).to.be(15); + view.setZoom(15.3); + expect(view.getZoom()).to.be(15.3); + view.setZoom(20); expect(view.getZoom()).to.be(20);