Accept resolution or zoom related options for constrained views

Any of minResolution, maxResolution, minZoom, or maxZoom can be used to constrain the view resolutions.  Resolution options are given precedence over zoom options.
This commit is contained in:
Tim Schaub
2014-05-15 16:43:27 -06:00
parent 3384ba07e3
commit 815f5b38c8
3 changed files with 269 additions and 28 deletions

View File

@@ -351,7 +351,9 @@ olx.ProjectionOptions.prototype.global;
* constrainRotation: (boolean|number|undefined),
* enableRotation: (boolean|undefined),
* extent: (ol.Extent|undefined),
* minResolution: (number|undefined),
* maxResolution: (number|undefined),
* minZoom: (number|undefined),
* maxZoom: (number|undefined),
* projection: ol.proj.ProjectionLike,
* resolution: (number|undefined),
@@ -400,23 +402,48 @@ olx.View2DOptions.prototype.extent;
/**
* The maximum resolution used to determine the resolution constraint. It is
* used together with `maxZoom` and `zoomFactor`. If unspecified it is
* calculated in such a way that the projection's validity extent fits in a
* 256x256 px tile. If the projection is Spherical Mercator (the default) then
* `maxResolution` defaults to `40075016.68557849 / 256 = 156543.03392804097`.
* used together with `minResolution` (or `maxZoom`) and `zoomFactor`. If
* unspecified it is calculated in such a way that the projection's validity
* extent fits in a 256x256 px tile. If the projection is Spherical Mercator
* (the default) then `maxResolution` defaults to `40075016.68557849 / 256 =
* 156543.03392804097`.
* @type {number|undefined}
*/
olx.View2DOptions.prototype.maxResolution;
/**
* The minimum resolution used to determine the resolution constraint. It is
* used together with `maxResolution` (or `minZoom`) and `zoomFactor`. If
* unspecified it is calculated assuming 29 zoom levels (with a factor of 2).
* If the projection is Spherical Mercator (the default) then `minResolution`
* defaults to `40075016.68557849 / 256 / Math.pow(2, 28) =
* 0.0005831682455839253`.
* @type {number|undefined}
*/
olx.View2DOptions.prototype.minResolution;
/**
* The maximum zoom level used to determine the resolution constraint. It is
* used together with `maxResolution` and `zoomFactor`. Default is `28`.
* used together with `minZoom` (or `maxResolution`) and `zoomFactor`. Default
* is `28`. Note that if `minResolution` is also provided, it is given
* precedence over `maxZoom`.
* @type {number|undefined}
*/
olx.View2DOptions.prototype.maxZoom;
/**
* The minimum zoom level used to determine the resolution constraint. It is
* used together with `maxZoom` (or `minResolution`) and `zoomFactor`. Default
* is `0`. Note that if `maxResolution` is also provided, it is given
* precedence over `minZoom`.
* @type {number|undefined}
*/
olx.View2DOptions.prototype.minZoom;
/**
* The projection. Default is `EPSG:3857` (Spherical Mercator).
* @type {ol.proj.ProjectionLike}
@@ -436,7 +463,8 @@ olx.View2DOptions.prototype.resolution;
/**
* Resolutions to determine the resolution constraint. If set the
* `maxResolution`, `maxZoom` and `zoomFactor` options are ignored.
* `maxResolution`, `minResolution`, `minZoom`, `maxZoom`, and `zoomFactor`
* options are ignored.
* @type {Array.<number>|undefined}
*/
olx.View2DOptions.prototype.resolutions;
@@ -460,8 +488,7 @@ olx.View2DOptions.prototype.zoom;
/**
* The zoom factor used to determine the resolution constraint. Used together
* with `maxResolution` and `maxZoom`. Default is `2`.
* The zoom factor used to determine the resolution constraint. Default is `2`.
* @type {number|undefined}
*/
olx.View2DOptions.prototype.zoomFactor;

View File

@@ -657,30 +657,65 @@ ol.View2D.createResolutionConstraint_ = function(options) {
resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions(
resolutions);
} else {
// TODO: move these to be ol constants
// see https://github.com/openlayers/ol3/issues/2076
var defaultMaxZoom = 28;
var defaultMinZoom = 0;
var defaultZoomFactor = 2;
// calculate the default min and max resolution
var projection = options.projection;
var extent = ol.proj.createProjection(projection, 'EPSG:3857').getExtent();
var size = goog.isNull(extent) ?
// use an extent that can fit the whole world if need be
360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
ol.proj.METERS_PER_UNIT[projection.getUnits()] :
Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent));
var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow(
defaultZoomFactor, defaultMinZoom);
var defaultMinResolution = defaultMaxResolution / Math.pow(
defaultZoomFactor, defaultMaxZoom - defaultMinZoom);
var minZoom = goog.isDef(options.minZoom) ?
options.minZoom : defaultMinZoom;
var maxZoom = goog.isDef(options.maxZoom) ?
options.maxZoom : defaultMaxZoom;
var zoomFactor = goog.isDef(options.zoomFactor) ?
options.zoomFactor : defaultZoomFactor;
// user provided maxResolution takes precedence
maxResolution = options.maxResolution;
if (!goog.isDef(maxResolution)) {
var projection = options.projection;
var projectionExtent = ol.proj.createProjection(projection, 'EPSG:3857')
.getExtent();
var size = goog.isNull(projectionExtent) ?
// use an extent that can fit the whole world if need be
360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
ol.proj.METERS_PER_UNIT[projection.getUnits()] :
Math.max(projectionExtent[2] - projectionExtent[0],
projectionExtent[3] - projectionExtent[1]);
maxResolution = size / ol.DEFAULT_TILE_SIZE;
if (goog.isDef(maxResolution)) {
minZoom = 0;
} else {
maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);
}
var maxZoom = options.maxZoom;
if (!goog.isDef(maxZoom)) {
maxZoom = 28;
// user provided minResolution takes precedence
minResolution = options.minResolution;
if (!goog.isDef(minResolution)) {
if (goog.isDef(options.maxZoom)) {
if (goog.isDef(options.maxResolution)) {
minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);
} else {
minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);
}
} else {
minResolution = defaultMinResolution;
}
}
var zoomFactor = options.zoomFactor;
if (!goog.isDef(zoomFactor)) {
zoomFactor = 2;
}
minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);
// given discrete zoom levels, minResolution may be different than provided
maxZoom = minZoom + Math.floor(
Math.log(maxResolution / minResolution) / Math.log(zoomFactor));
minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
resolutionConstraint = ol.ResolutionConstraint.createSnapToPower(
zoomFactor, maxResolution, maxZoom);
zoomFactor, maxResolution, maxZoom - minZoom);
}
return {constraint: resolutionConstraint, maxResolution: maxResolution,
minResolution: minResolution};

View File

@@ -58,6 +58,185 @@ describe('ol.View2D', function() {
});
});
describe('with zoom related options', function() {
var defaultMaxRes = 156543.03392804097;
function getConstraint(options) {
return ol.View2D.createResolutionConstraint_(options).constraint;
}
it('works with only maxZoom', function() {
var maxZoom = 10;
var constraint = getConstraint({
maxZoom: maxZoom
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes, 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, maxZoom), 1e-9);
});
it('works with only minZoom', function() {
var minZoom = 5;
var constraint = getConstraint({
minZoom: minZoom
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, 28), 1e-9);
});
it('works with maxZoom and minZoom', function() {
var minZoom = 2;
var maxZoom = 11;
var constraint = getConstraint({
minZoom: minZoom,
maxZoom: maxZoom
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, maxZoom), 1e-9);
});
it('works with maxZoom, minZoom, and zoomFactor', function() {
var minZoom = 4;
var maxZoom = 8;
var zoomFactor = 3;
var constraint = getConstraint({
minZoom: minZoom,
maxZoom: maxZoom,
zoomFactor: zoomFactor
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(zoomFactor, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual(
defaultMaxRes / Math.pow(zoomFactor, maxZoom), 1e-9);
});
});
describe('with resolution related options', function() {
var defaultMaxRes = 156543.03392804097;
function getConstraint(options) {
return ol.View2D.createResolutionConstraint_(options).constraint;
}
it('works with only maxResolution', function() {
var maxResolution = 10e6;
var constraint = getConstraint({
maxResolution: maxResolution
});
expect(constraint(maxResolution * 3, 0, 0)).to.roughlyEqual(
maxResolution, 1e-9);
var minResolution = constraint(0, 0, 0);
var defaultMinRes = defaultMaxRes / Math.pow(2, 28);
expect(minResolution).to.be.greaterThan(defaultMinRes);
expect(minResolution / defaultMinRes).to.be.lessThan(2);
});
it('works with only minResolution', function() {
var minResolution = 100;
var constraint = getConstraint({
minResolution: minResolution
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes, 1e-9);
var constrainedMinRes = constraint(0, 0, 0);
expect(constrainedMinRes).to.be.greaterThan(minResolution);
expect(constrainedMinRes / minResolution).to.be.lessThan(2);
});
it('works with minResolution and maxResolution', function() {
var constraint = getConstraint({
maxResolution: 500,
minResolution: 100
});
expect(constraint(600, 0, 0)).to.be(500);
expect(constraint(500, 0, 0)).to.be(500);
expect(constraint(400, 0, 0)).to.be(500);
expect(constraint(300, 0, 0)).to.be(250);
expect(constraint(200, 0, 0)).to.be(250);
expect(constraint(100, 0, 0)).to.be(125);
expect(constraint(0, 0, 0)).to.be(125);
});
it('accepts minResolution, maxResolution, and zoomFactor', function() {
var constraint = getConstraint({
maxResolution: 500,
minResolution: 1,
zoomFactor: 10
});
expect(constraint(1000, 0, 0)).to.be(500);
expect(constraint(500, 0, 0)).to.be(500);
expect(constraint(100, 0, 0)).to.be(50);
expect(constraint(50, 0, 0)).to.be(50);
expect(constraint(10, 0, 0)).to.be(5);
expect(constraint(1, 0, 0)).to.be(5);
});
});
describe('overspecified options (prefers resolution)', function() {
var defaultMaxRes = 156543.03392804097;
function getConstraint(options) {
return ol.View2D.createResolutionConstraint_(options).constraint;
}
it('respects maxResolution over minZoom', function() {
var maxResolution = 10e6;
var minZoom = 8;
var constraint = getConstraint({
maxResolution: maxResolution,
minZoom: minZoom
});
expect(constraint(maxResolution * 3, 0, 0)).to.roughlyEqual(
maxResolution, 1e-9);
var minResolution = constraint(0, 0, 0);
var defaultMinRes = defaultMaxRes / Math.pow(2, 28);
expect(minResolution).to.be.greaterThan(defaultMinRes);
expect(minResolution / defaultMinRes).to.be.lessThan(2);
});
it('respects minResolution over maxZoom', function() {
var minResolution = 100;
var maxZoom = 50;
var constraint = getConstraint({
minResolution: minResolution,
maxZoom: maxZoom
});
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual(
defaultMaxRes, 1e-9);
var constrainedMinRes = constraint(0, 0, 0);
expect(constrainedMinRes).to.be.greaterThan(minResolution);
expect(constrainedMinRes / minResolution).to.be.lessThan(2);
});
});
});
describe('create rotation constraint', function() {