Show only one world

This commit is contained in:
ahocevar
2019-03-22 21:55:54 +01:00
parent a95481a8fe
commit 3940b5ec88
6 changed files with 97 additions and 46 deletions

View File

@@ -22,6 +22,10 @@ Previously, this options only constrained the view *center*. This behaviour can
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input. As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
##### Zoom is constrained so only one world is visible
Previously, maps showed multiple worlds at low zoom levels. Now, the view is restricted to show only one world. To get the previous behavior, configure the `ol/View` with `multiWorld: true`.
##### Removal of deprecated methods ##### Removal of deprecated methods
The `inherits` function that was used to inherit the prototype methods from one constructor into another has been removed. The `inherits` function that was used to inherit the prototype methods from one constructor into another has been removed.

View File

@@ -20,7 +20,8 @@ const map = new Map({
view: new View({ view: new View({
projection: 'EPSG:4326', projection: 'EPSG:4326',
center: [0, 0], center: [0, 0],
resolution: 1 resolution: 1,
multiWorld: true
}) })
}); });
map.getView().setCenter([10, 10]); map.getView().setCenter([10, 10]);

View File

@@ -120,6 +120,7 @@ import {createMinMaxResolution} from './resolutionconstraint';
* resolution constraint. It is used together with `maxZoom` (or * resolution constraint. It is used together with `maxZoom` (or
* `minResolution`) and `zoomFactor`. Note that if `maxResolution` is also * `minResolution`) and `zoomFactor`. Note that if `maxResolution` is also
* provided, it is given precedence over `minZoom`. * provided, it is given precedence over `minZoom`.
* @property {boolean} [multiWorld=false] No more than one world is visible.
* @property {boolean} [constrainResolution=false] If true, the view will always * @property {boolean} [constrainResolution=false] If true, the view will always
* animate to the closest zoom level after an interaction; false means * animate to the closest zoom level after an interaction; false means
* intermediary zoom levels are allowed. * intermediary zoom levels are allowed.
@@ -1435,6 +1436,9 @@ export function createResolutionConstraint(options) {
const zoomFactor = options.zoomFactor !== undefined ? const zoomFactor = options.zoomFactor !== undefined ?
options.zoomFactor : defaultZoomFactor; options.zoomFactor : defaultZoomFactor;
const multiWorld = options.multiWorld !== undefined ?
options.multiWorld : false;
const smooth = const smooth =
options.smoothResolutionConstraint !== undefined ? options.smoothResolutionConstraint : true; options.smoothResolutionConstraint !== undefined ? options.smoothResolutionConstraint : true;
@@ -1499,8 +1503,14 @@ export function createResolutionConstraint(options) {
zoomFactor, maxResolution, minResolution, smooth, zoomFactor, maxResolution, minResolution, smooth,
!options.constrainOnlyCenter && options.extent); !options.constrainOnlyCenter && options.extent);
} else { } else {
let constrainOnlyCenter = options.constrainOnlyCenter;
let extent = options.extent;
if (!multiWorld && !extent && projection.isGlobal()) {
constrainOnlyCenter = false;
extent = projection.getExtent();
}
resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth, resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth,
!options.constrainOnlyCenter && options.extent); !constrainOnlyCenter && extent);
} }
} }
return {constraint: resolutionConstraint, maxResolution: maxResolution, return {constraint: resolutionConstraint, maxResolution: maxResolution,

View File

@@ -146,6 +146,7 @@ describe('ol.control.ScaleLine', function() {
ctrl.setMap(map); ctrl.setMap(map);
map.setView(new View({ map.setView(new View({
center: [0, 0], center: [0, 0],
multiWorld: true,
zoom: 0 zoom: 0
})); }));
map.renderSync(); map.renderSync();
@@ -176,6 +177,7 @@ describe('ol.control.ScaleLine', function() {
const ctrl = new ScaleLine(); const ctrl = new ScaleLine();
map.setView(new View({ map.setView(new View({
center: [0, 0], center: [0, 0],
multiWorld: true,
zoom: 0 zoom: 0
})); }));
ctrl.setMap(map); ctrl.setMap(map);
@@ -277,6 +279,7 @@ describe('ol.control.ScaleLine', function() {
expect(ctrl.element.innerText).to.be('2000 km'); expect(ctrl.element.innerText).to.be('2000 km');
map.setView(new View({ map.setView(new View({
center: [7, 52], center: [7, 52],
multiWorld: true,
zoom: 2, zoom: 2,
projection: 'EPSG:4326' projection: 'EPSG:4326'
})); }));
@@ -380,6 +383,7 @@ describe('ol.control.ScaleLine', function() {
ctrl.setMap(map); ctrl.setMap(map);
map.setView(new View({ map.setView(new View({
center: [0, 0], center: [0, 0],
multiWorld: true,
zoom: 0, /* min zoom */ zoom: 0, /* min zoom */
projection: 'EPSG:4326' projection: 'EPSG:4326'
})); }));
@@ -417,7 +421,8 @@ describe('ol.control.ScaleLine', function() {
map.setView(new View({ map.setView(new View({
center: [7, 0], center: [7, 0],
zoom: 2, zoom: 2,
projection: 'EPSG:4326' projection: 'EPSG:4326',
multiWorld: true
})); }));
map.renderSync(); map.renderSync();
const innerHtml0 = ctrl.element.innerHTML; const innerHtml0 = ctrl.element.innerHTML;
@@ -467,7 +472,8 @@ describe('ol.control.ScaleLine', function() {
map.setView(new View({ map.setView(new View({
center: [0, 0], center: [0, 0],
zoom: currentZoom, zoom: currentZoom,
maxZoom: currentZoom maxZoom: currentZoom,
multiWorld: true
})); }));
mapView = map.getView(); mapView = map.getView();
map.renderSync(); map.renderSync();

View File

@@ -100,6 +100,7 @@ describe('ol.renderer.Layer', function() {
view = new View({ view = new View({
center: [0, 0], center: [0, 0],
multiWorld: true,
zoom: 0 zoom: 0
}); });

View File

@@ -145,18 +145,20 @@ describe('ol.View', function() {
describe('create resolution constraint', function() { describe('create resolution constraint', function() {
describe('with no options', function() { describe('with no options', function() {
const size = [200, 200];
it('gives a correct resolution constraint function', function() { it('gives a correct resolution constraint function', function() {
const options = {}; const options = {};
const fn = createResolutionConstraint(options).constraint; const fn = createResolutionConstraint(options).constraint;
expect(fn(156543.03392804097, 0, 0)) expect(fn(156543.03392804097, 0, size))
.to.roughlyEqual(156543.03392804097, 1e-9); .to.roughlyEqual(156543.03392804097, 1e-9);
expect(fn(78271.51696402048, 0, 0)) expect(fn(78271.51696402048, 0, size))
.to.roughlyEqual(78271.51696402048, 1e-10); .to.roughlyEqual(78271.51696402048, 1e-10);
}); });
}); });
describe('with maxResolution, maxZoom, and zoomFactor options', describe('with maxResolution, maxZoom, and zoomFactor options',
function() { function() {
const size = [200, 200];
it('gives a correct resolution constraint function', function() { it('gives a correct resolution constraint function', function() {
const options = { const options = {
maxResolution: 81, maxResolution: 81,
@@ -169,16 +171,17 @@ describe('ol.View', function() {
const minResolution = info.minResolution; const minResolution = info.minResolution;
expect(minResolution).to.eql(3); expect(minResolution).to.eql(3);
const fn = info.constraint; const fn = info.constraint;
expect(fn(82, 0, 0)).to.eql(81); expect(fn(82, 0, size)).to.eql(81);
expect(fn(81, 0, 0)).to.eql(81); expect(fn(81, 0, size)).to.eql(81);
expect(fn(27, 0, 0)).to.eql(27); expect(fn(27, 0, size)).to.eql(27);
expect(fn(9, 0, 0)).to.eql(9); expect(fn(9, 0, size)).to.eql(9);
expect(fn(3, 0, 0)).to.eql(3); expect(fn(3, 0, size)).to.eql(3);
expect(fn(2, 0, 0)).to.eql(3); expect(fn(2, 0, size)).to.eql(3);
}); });
}); });
describe('with resolutions', function() { describe('with resolutions', function() {
const size = [200, 200];
it('gives a correct resolution constraint function', function() { it('gives a correct resolution constraint function', function() {
const options = { const options = {
resolutions: [97, 76, 65, 54, 0.45] resolutions: [97, 76, 65, 54, 0.45]
@@ -189,17 +192,18 @@ describe('ol.View', function() {
const minResolution = info.minResolution; const minResolution = info.minResolution;
expect(minResolution).to.eql(0.45); expect(minResolution).to.eql(0.45);
const fn = info.constraint; const fn = info.constraint;
expect(fn(97, 0, 0)).to.eql(97); expect(fn(97, 0, size)).to.eql(97);
expect(fn(76, 0, 0)).to.eql(76); expect(fn(76, 0, size)).to.eql(76);
expect(fn(65, 0, 0)).to.eql(65); expect(fn(65, 0, size)).to.eql(65);
expect(fn(54, 0, 0)).to.eql(54); expect(fn(54, 0, size)).to.eql(54);
expect(fn(0.45, 0, 0)).to.eql(0.45); expect(fn(0.45, 0, size)).to.eql(0.45);
}); });
}); });
describe('with zoom related options', function() { describe('with zoom related options', function() {
const defaultMaxRes = 156543.03392804097; const defaultMaxRes = 156543.03392804097;
const size = [200, 200];
function getConstraint(options) { function getConstraint(options) {
return createResolutionConstraint(options).constraint; return createResolutionConstraint(options).constraint;
} }
@@ -210,10 +214,10 @@ describe('ol.View', function() {
maxZoom: maxZoom maxZoom: maxZoom
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes, 1e-9); defaultMaxRes, 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual( expect(constraint(0, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, maxZoom), 1e-9); defaultMaxRes / Math.pow(2, maxZoom), 1e-9);
}); });
@@ -223,10 +227,10 @@ describe('ol.View', function() {
minZoom: minZoom minZoom: minZoom
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, minZoom), 1e-9); defaultMaxRes / Math.pow(2, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual( expect(constraint(0, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, 28), 1e-9); defaultMaxRes / Math.pow(2, 28), 1e-9);
}); });
@@ -238,10 +242,10 @@ describe('ol.View', function() {
maxZoom: maxZoom maxZoom: maxZoom
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, minZoom), 1e-9); defaultMaxRes / Math.pow(2, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual( expect(constraint(0, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(2, maxZoom), 1e-9); defaultMaxRes / Math.pow(2, maxZoom), 1e-9);
}); });
@@ -255,10 +259,10 @@ describe('ol.View', function() {
zoomFactor: zoomFactor zoomFactor: zoomFactor
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(zoomFactor, minZoom), 1e-9); defaultMaxRes / Math.pow(zoomFactor, minZoom), 1e-9);
expect(constraint(0, 0, 0)).to.roughlyEqual( expect(constraint(0, 0, size)).to.roughlyEqual(
defaultMaxRes / Math.pow(zoomFactor, maxZoom), 1e-9); defaultMaxRes / Math.pow(zoomFactor, maxZoom), 1e-9);
}); });
@@ -267,6 +271,7 @@ describe('ol.View', function() {
describe('with resolution related options', function() { describe('with resolution related options', function() {
const defaultMaxRes = 156543.03392804097; const defaultMaxRes = 156543.03392804097;
const size = [200, 200];
function getConstraint(options) { function getConstraint(options) {
return createResolutionConstraint(options).constraint; return createResolutionConstraint(options).constraint;
} }
@@ -274,13 +279,14 @@ describe('ol.View', function() {
it('works with only maxResolution', function() { it('works with only maxResolution', function() {
const maxResolution = 10e6; const maxResolution = 10e6;
const constraint = getConstraint({ const constraint = getConstraint({
multiWorld: true,
maxResolution: maxResolution maxResolution: maxResolution
}); });
expect(constraint(maxResolution * 3, 0, 0)).to.roughlyEqual( expect(constraint(maxResolution * 3, 0, size)).to.roughlyEqual(
maxResolution, 1e-9); maxResolution, 1e-9);
const minResolution = constraint(0, 0, 0); const minResolution = constraint(0, 0, size);
const defaultMinRes = defaultMaxRes / Math.pow(2, 28); const defaultMinRes = defaultMaxRes / Math.pow(2, 28);
expect(minResolution).to.be.greaterThan(defaultMinRes); expect(minResolution).to.be.greaterThan(defaultMinRes);
@@ -293,10 +299,10 @@ describe('ol.View', function() {
minResolution: minResolution minResolution: minResolution
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes, 1e-9); defaultMaxRes, 1e-9);
const constrainedMinRes = constraint(0, 0, 0); const constrainedMinRes = constraint(0, 0, size);
expect(constrainedMinRes).to.be.greaterThan(minResolution); expect(constrainedMinRes).to.be.greaterThan(minResolution);
expect(constrainedMinRes / minResolution).to.be.lessThan(2); expect(constrainedMinRes / minResolution).to.be.lessThan(2);
}); });
@@ -308,13 +314,13 @@ describe('ol.View', function() {
constrainResolution: true constrainResolution: true
}); });
expect(constraint(600, 0, 0)).to.be(500); expect(constraint(600, 0, size)).to.be(500);
expect(constraint(500, 0, 0)).to.be(500); expect(constraint(500, 0, size)).to.be(500);
expect(constraint(400, 0, 0)).to.be(500); expect(constraint(400, 0, size)).to.be(500);
expect(constraint(300, 0, 0)).to.be(250); expect(constraint(300, 0, size)).to.be(250);
expect(constraint(200, 0, 0)).to.be(250); expect(constraint(200, 0, size)).to.be(250);
expect(constraint(100, 0, 0)).to.be(125); expect(constraint(100, 0, size)).to.be(125);
expect(constraint(0, 0, 0)).to.be(125); expect(constraint(0, 0, size)).to.be(125);
}); });
it('accepts minResolution, maxResolution, and zoomFactor', function() { it('accepts minResolution, maxResolution, and zoomFactor', function() {
@@ -325,12 +331,12 @@ describe('ol.View', function() {
constrainResolution: true constrainResolution: true
}); });
expect(constraint(1000, 0, 0)).to.be(500); expect(constraint(1000, 0, size)).to.be(500);
expect(constraint(500, 0, 0)).to.be(500); expect(constraint(500, 0, size)).to.be(500);
expect(constraint(100, 0, 0)).to.be(50); expect(constraint(100, 0, size)).to.be(50);
expect(constraint(50, 0, 0)).to.be(50); expect(constraint(50, 0, size)).to.be(50);
expect(constraint(10, 0, 0)).to.be(5); expect(constraint(10, 0, size)).to.be(5);
expect(constraint(1, 0, 0)).to.be(5); expect(constraint(1, 0, size)).to.be(5);
}); });
}); });
@@ -338,6 +344,7 @@ describe('ol.View', function() {
describe('overspecified options (prefers resolution)', function() { describe('overspecified options (prefers resolution)', function() {
const defaultMaxRes = 156543.03392804097; const defaultMaxRes = 156543.03392804097;
const size = [200, 200];
function getConstraint(options) { function getConstraint(options) {
return createResolutionConstraint(options).constraint; return createResolutionConstraint(options).constraint;
} }
@@ -346,14 +353,15 @@ describe('ol.View', function() {
const maxResolution = 10e6; const maxResolution = 10e6;
const minZoom = 8; const minZoom = 8;
const constraint = getConstraint({ const constraint = getConstraint({
multiWorld: true,
maxResolution: maxResolution, maxResolution: maxResolution,
minZoom: minZoom minZoom: minZoom
}); });
expect(constraint(maxResolution * 3, 0, 0)).to.roughlyEqual( expect(constraint(maxResolution * 3, 0, size)).to.roughlyEqual(
maxResolution, 1e-9); maxResolution, 1e-9);
const minResolution = constraint(0, 0, 0); const minResolution = constraint(0, 0, size);
const defaultMinRes = defaultMaxRes / Math.pow(2, 28); const defaultMinRes = defaultMaxRes / Math.pow(2, 28);
expect(minResolution).to.be.greaterThan(defaultMinRes); expect(minResolution).to.be.greaterThan(defaultMinRes);
@@ -368,16 +376,37 @@ describe('ol.View', function() {
maxZoom: maxZoom maxZoom: maxZoom
}); });
expect(constraint(defaultMaxRes, 0, 0)).to.roughlyEqual( expect(constraint(defaultMaxRes, 0, size)).to.roughlyEqual(
defaultMaxRes, 1e-9); defaultMaxRes, 1e-9);
const constrainedMinRes = constraint(0, 0, 0); const constrainedMinRes = constraint(0, 0, size);
expect(constrainedMinRes).to.be.greaterThan(minResolution); expect(constrainedMinRes).to.be.greaterThan(minResolution);
expect(constrainedMinRes / minResolution).to.be.lessThan(2); expect(constrainedMinRes / minResolution).to.be.lessThan(2);
}); });
}); });
describe('Map views that show more than one world', function() {
const defaultMaxRes = 156543.03392804097;
const size = [512, 512];
function getConstraint(options) {
return createResolutionConstraint(options).constraint;
}
it('are disabled by default', function() {
const fn = getConstraint({});
expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes / 2);
});
it('can be enabled by setting multiWorld to truet', function() {
const fn = getConstraint({
multiWorld: true
});
expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes);
});
});
}); });
describe('create rotation constraint', function() { describe('create rotation constraint', function() {