diff --git a/src/ol/View.js b/src/ol/View.js index b3abc05f89..0ba9115d5b 100644 --- a/src/ol/View.js +++ b/src/ol/View.js @@ -198,7 +198,7 @@ const DEFAULT_MIN_ZOOM = 0; * * ### The view states * - * An View is determined by three states: `center`, `resolution`, + * A View is determined by three states: `center`, `resolution`, * and `rotation`. Each state has a corresponding getter and setter, e.g. * `getCenter` and `setCenter` for the `center` state. * @@ -1555,6 +1555,15 @@ export function createResolutionConstraint(options) { const smooth = options.smoothResolutionConstraint !== undefined ? options.smoothResolutionConstraint : true; + const projection = createProjection(options.projection, 'EPSG:3857'); + const projExtent = projection.getExtent(); + let constrainOnlyCenter = options.constrainOnlyCenter; + let extent = options.extent; + if (!multiWorld && !extent && projection.isGlobal()) { + constrainOnlyCenter = false; + extent = projExtent; + } + if (options.resolutions !== undefined) { const resolutions = options.resolutions; maxResolution = resolutions[minZoom]; @@ -1563,20 +1572,18 @@ export function createResolutionConstraint(options) { if (options.constrainResolution) { resolutionConstraint = createSnapToResolutions(resolutions, smooth, - !options.constrainOnlyCenter && options.extent); + !constrainOnlyCenter && extent); } else { resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth, - !options.constrainOnlyCenter && options.extent); + !constrainOnlyCenter && extent); } } else { // calculate the default min and max resolution - const projection = createProjection(options.projection, 'EPSG:3857'); - const extent = projection.getExtent(); - const size = !extent ? + const size = !projExtent ? // use an extent that can fit the whole world if need be 360 * METERS_PER_UNIT[Units.DEGREES] / projection.getMetersPerUnit() : - Math.max(getWidth(extent), getHeight(extent)); + Math.max(getWidth(projExtent), getHeight(projExtent)); const defaultMaxResolution = size / DEFAULT_TILE_SIZE / Math.pow( defaultZoomFactor, DEFAULT_MIN_ZOOM); @@ -1614,14 +1621,8 @@ export function createResolutionConstraint(options) { if (options.constrainResolution) { resolutionConstraint = createSnapToPower( zoomFactor, maxResolution, minResolution, smooth, - !options.constrainOnlyCenter && options.extent); + !constrainOnlyCenter && extent); } else { - let constrainOnlyCenter = options.constrainOnlyCenter; - let extent = options.extent; - if (!multiWorld && !extent && projection.isGlobal()) { - constrainOnlyCenter = false; - extent = projection.getExtent(); - } resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth, !constrainOnlyCenter && extent); } diff --git a/src/ol/resolutionconstraint.js b/src/ol/resolutionconstraint.js index b0c36d5b6d..72594e9730 100644 --- a/src/ol/resolutionconstraint.js +++ b/src/ol/resolutionconstraint.js @@ -82,6 +82,9 @@ export function createSnapToResolutions(resolutions, opt_smooth, opt_maxExtent) const capped = Math.min(cappedMaxRes, resolution); const z = Math.floor(linearFindNearest(resolutions, capped, direction)); + if (resolutions[z] > cappedMaxRes && z < resolutions.length - 1) { + return resolutions[z + 1]; + } return resolutions[z]; } else { return undefined; diff --git a/test/spec/ol/view.test.js b/test/spec/ol/view.test.js index d4bf59b078..96b7d84830 100644 --- a/test/spec/ol/view.test.js +++ b/test/spec/ol/view.test.js @@ -430,6 +430,8 @@ describe('ol.View', function() { const defaultMaxRes = 156543.03392804097; const size = [512, 512]; + const maxResolution = 160000; + const resolutions = [160000, 80000, 40000, 20000, 10000, 5000]; function getConstraint(options) { return createResolutionConstraint(options).constraint; } @@ -439,12 +441,61 @@ describe('ol.View', function() { expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes / 2); }); - it('can be enabled by setting multiWorld to truet', function() { + it('can be enabled by setting multiWorld to true', function() { const fn = getConstraint({ multiWorld: true }); expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes); }); + + it('disabled, with constrainResolution', function() { + const fn = getConstraint({ + maxResolution: maxResolution, + constrainResolution: true + }); + expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes / 2); + }); + + it('enabled, with constrainResolution', function() { + const fn = getConstraint({ + maxResolution: maxResolution, + constrainResolution: true, + multiWorld: true + }); + expect(fn(defaultMaxRes, 0, size)).to.be(maxResolution); + }); + + it('disabled, with resolutions array', function() { + const fn = getConstraint({ + resolutions: resolutions + }); + expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes / 2); + }); + + it('enabled, with resolutions array', function() { + const fn = getConstraint({ + resolutions: resolutions, + multiWorld: true + }); + expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes); + }); + + it('disabled, with resolutions array and constrainResolution', function() { + const fn = getConstraint({ + resolutions: resolutions, + constrainResolution: true + }); + expect(fn(defaultMaxRes, 0, size)).to.be(resolutions[2]); + }); + + it('enabled, with resolutions array and constrainResolution', function() { + const fn = getConstraint({ + resolutions: resolutions, + constrainResolution: true, + multiWorld: true + }); + expect(fn(defaultMaxRes, 0, size)).to.be(resolutions[0]); + }); }); });