Compare commits
1 Commits
v6.0.0-bet
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ca396f727 |
@@ -4,24 +4,6 @@
|
|||||||
|
|
||||||
#### Backwards incompatible changes
|
#### Backwards incompatible changes
|
||||||
|
|
||||||
##### The `setCenter`, `setZoom`, `setResolution` and `setRotation` methods on `ol/View` do not bypass constraints anymore
|
|
||||||
|
|
||||||
Previously, these methods allowed setting values that were inconsistent with the given view constraints.
|
|
||||||
This is no longer the case and all changes to the view state now follow the same logic:
|
|
||||||
target values are provided and constraints are applied on these to determine the actual values to be used.
|
|
||||||
|
|
||||||
##### Removal of the `constrainResolution` option on `View.fit`, `PinchZoom`, `MouseWheelZoom` and `ol/interaction.js`
|
|
||||||
|
|
||||||
The `constrainResolution` option is now only supported by the `View` class. A `View.setResolutionConstrained` method was added as well.
|
|
||||||
|
|
||||||
Generally, the responsibility of applying center/rotation/resolutions constraints was moved from interactions and controls to the `View` class.
|
|
||||||
|
|
||||||
##### The view `extent` option now applies to the whole viewport
|
|
||||||
|
|
||||||
Previously, this options only constrained the view *center*. This behaviour can still be obtained by specifying `constrainCenterOnly` in the view options.
|
|
||||||
|
|
||||||
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
|
|
||||||
|
|
||||||
##### 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.
|
||||||
@@ -117,58 +99,6 @@ Due to the constraint above (layers can only be added to a single map), the over
|
|||||||
|
|
||||||
Previously, a graticule was not a layer. Now it is. See the graticule example for details on how to add a graticule layer to your map.
|
Previously, a graticule was not a layer. Now it is. See the graticule example for details on how to add a graticule layer to your map.
|
||||||
|
|
||||||
##### `ol/format/Feature` API change
|
|
||||||
|
|
||||||
The `getLastExtent()` method, which was required for custom `tileLoadFunction`s in `ol/source/Vector`, has been removed because it is no longer needed (see below).
|
|
||||||
|
|
||||||
##### `ol/VectorTile` API changes
|
|
||||||
|
|
||||||
* Removal of the `getProjection()` and `setProjection()` methods. These were used in custom `tileLoadFunction`s on `ol/source/VectorTile`, which work differently now (see below).
|
|
||||||
* Removal of the `getExtent()` and `setExtent()` methods. These were used in custom `tileLoadFunction`s on `ol/source/VectorTile`, which work differently now (see below).
|
|
||||||
|
|
||||||
##### Custom tileLoadFunction on a VectorTile source needs changes
|
|
||||||
|
|
||||||
Previously, applications needed to call `setProjection()` and `setExtent()` on the tile in a custom `tileLoadFunction` on `ol/source/VectorTile`. The format's `getLastExtent()` method was used to get the extent. All this is no longer needed. Instead, the `extent` (first argument to the loader function) and `projection` (third argument to the loader function) are simply passed as `extent` and `featureProjection` options to the format's `readFeatures()` method.
|
|
||||||
|
|
||||||
Example for an old `tileLoadFunction`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function(tile, url) {
|
|
||||||
tile.setLoader(function() {
|
|
||||||
fetch(url).then(function(response) {
|
|
||||||
response.arrayBuffer().then(function(data) {
|
|
||||||
var format = tile.getFormat();
|
|
||||||
tile.setProjection(format.readProjection(data));
|
|
||||||
tile.setFeatures(format.readFeatures(data, {
|
|
||||||
// featureProjection is not required for ol/format/MVT
|
|
||||||
featureProjection: map.getView().getProjection()
|
|
||||||
}));
|
|
||||||
tile.setExtent(format.getLastExtent());
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
This function needs to be changed to:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function(tile, url) {
|
|
||||||
tile.setLoader(function(extent, resolution, projection) {
|
|
||||||
fetch(url).then(function(response) {
|
|
||||||
response.arrayBuffer().then(function(data) {
|
|
||||||
var format = tile.getFormat();
|
|
||||||
tile.setFeatures(format.readFeatures(data, {
|
|
||||||
// extent is only required for ol/format/MVT
|
|
||||||
extent: extent,
|
|
||||||
featureProjection: projection
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Drop of support for the experimental WebGL renderer
|
##### Drop of support for the experimental WebGL renderer
|
||||||
|
|
||||||
The WebGL map and layers renderers are gone, replaced by a `WebGLHelper` function that provides a lightweight,
|
The WebGL map and layers renderers are gone, replaced by a `WebGLHelper` function that provides a lightweight,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ tags: "center, rotation, openstreetmap"
|
|||||||
<div class="padding-bottom"></div>
|
<div class="padding-bottom"></div>
|
||||||
<div class="center"></div>
|
<div class="center"></div>
|
||||||
</div>
|
</div>
|
||||||
<button id="zoomtoswitzerland">Zoom to Switzerland</button> (best fit).<br/>
|
<button id="zoomtoswitzerlandbest">Zoom to Switzerland</button> (best fit),<br/>
|
||||||
|
<button id="zoomtoswitzerlandconstrained">Zoom to Switzerland</button> (respect resolution constraint).<br/>
|
||||||
|
<button id="zoomtoswitzerlandnearest">Zoom to Switzerland</button> (nearest),<br/>
|
||||||
<button id="zoomtolausanne">Zoom to Lausanne</button> (with min resolution),<br/>
|
<button id="zoomtolausanne">Zoom to Lausanne</button> (with min resolution),<br/>
|
||||||
<button id="centerlausanne">Center on Lausanne</button>
|
<button id="centerlausanne">Center on Lausanne</button>
|
||||||
|
|||||||
@@ -47,14 +47,29 @@ const map = new Map({
|
|||||||
view: view
|
view: view
|
||||||
});
|
});
|
||||||
|
|
||||||
const zoomtoswitzerland =
|
const zoomtoswitzerlandbest = document.getElementById('zoomtoswitzerlandbest');
|
||||||
document.getElementById('zoomtoswitzerland');
|
zoomtoswitzerlandbest.addEventListener('click', function() {
|
||||||
zoomtoswitzerland.addEventListener('click', function() {
|
const feature = source.getFeatures()[0];
|
||||||
|
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
||||||
|
view.fit(polygon, {padding: [170, 50, 30, 150], constrainResolution: false});
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
const zoomtoswitzerlandconstrained =
|
||||||
|
document.getElementById('zoomtoswitzerlandconstrained');
|
||||||
|
zoomtoswitzerlandconstrained.addEventListener('click', function() {
|
||||||
const feature = source.getFeatures()[0];
|
const feature = source.getFeatures()[0];
|
||||||
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
||||||
view.fit(polygon, {padding: [170, 50, 30, 150]});
|
view.fit(polygon, {padding: [170, 50, 30, 150]});
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
const zoomtoswitzerlandnearest =
|
||||||
|
document.getElementById('zoomtoswitzerlandnearest');
|
||||||
|
zoomtoswitzerlandnearest.addEventListener('click', function() {
|
||||||
|
const feature = source.getFeatures()[0];
|
||||||
|
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
|
||||||
|
view.fit(polygon, {padding: [170, 50, 30, 150], nearest: true});
|
||||||
|
}, false);
|
||||||
|
|
||||||
const zoomtolausanne = document.getElementById('zoomtolausanne');
|
const zoomtolausanne = document.getElementById('zoomtolausanne');
|
||||||
zoomtolausanne.addEventListener('click', function() {
|
zoomtolausanne.addEventListener('click', function() {
|
||||||
const feature = source.getFeatures()[1];
|
const feature = source.getFeatures()[1];
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
layout: example.html
|
|
||||||
title: Constrained Extent
|
|
||||||
shortdesc: Example of a view with a constrained extent.
|
|
||||||
docs: >
|
|
||||||
This map has a view that is constrained in an extent. This is done using the `extent` view option. Please note that specifying `constrainOnlyCenter: true` would only apply the extent restriction to the view center.
|
|
||||||
tags: "view, extent, constrain, restrict"
|
|
||||||
---
|
|
||||||
<div id="map" class="map"></div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import Map from '../src/ol/Map.js';
|
|
||||||
import View from '../src/ol/View.js';
|
|
||||||
import TileLayer from '../src/ol/layer/Tile.js';
|
|
||||||
import OSM from '../src/ol/source/OSM.js';
|
|
||||||
import {defaults as defaultControls} from '../src/ol/control/util';
|
|
||||||
import ZoomSlider from '../src/ol/control/ZoomSlider';
|
|
||||||
|
|
||||||
const view = new View({
|
|
||||||
center: [328627.563458, 5921296.662223],
|
|
||||||
zoom: 8,
|
|
||||||
extent: [-572513.341856, 5211017.966314,
|
|
||||||
916327.095083, 6636950.728974]
|
|
||||||
});
|
|
||||||
|
|
||||||
new Map({
|
|
||||||
layers: [
|
|
||||||
new TileLayer({
|
|
||||||
source: new OSM()
|
|
||||||
})
|
|
||||||
],
|
|
||||||
keyboardEventTarget: document,
|
|
||||||
target: 'map',
|
|
||||||
view: view,
|
|
||||||
controls: defaultControls().extend([new ZoomSlider()])
|
|
||||||
});
|
|
||||||
@@ -4,11 +4,16 @@ title: Interaction Options
|
|||||||
shortdesc: Shows interaction options for custom scroll and zoom behavior.
|
shortdesc: Shows interaction options for custom scroll and zoom behavior.
|
||||||
docs: >
|
docs: >
|
||||||
This example uses a custom `ol/interaction/defaults` configuration:
|
This example uses a custom `ol/interaction/defaults` configuration:
|
||||||
by default, wheel/trackpad zoom and drag panning is always active, which
|
|
||||||
|
* By default, wheel/trackpad zoom and drag panning is always active, which
|
||||||
can be unexpected on pages with a lot of scrollable content and an embedded
|
can be unexpected on pages with a lot of scrollable content and an embedded
|
||||||
map. To perform wheel/trackpad zoom and drag-pan actions only when the map
|
map. To perform wheel/trackpad zoom and drag-pan actions only when the map
|
||||||
has the focus, set `onFocusOnly: true` as option. This requires a map div
|
has the focus, set `onFocusOnly: true` as option. This requires a map div
|
||||||
with a `tabindex` attribute set.
|
with a `tabindex` attribute set.
|
||||||
|
* By default, pinch-zoom and wheel/trackpad zoom interactions can leave the
|
||||||
|
map at fractional zoom levels. If instead you want to constrain
|
||||||
|
wheel/trackpad zooming to integer zoom levels, set
|
||||||
|
`constrainResolution: true`.
|
||||||
tags: "trackpad, mousewheel, zoom, scroll, interaction, fractional"
|
tags: "trackpad, mousewheel, zoom, scroll, interaction, fractional"
|
||||||
---
|
---
|
||||||
<div tabindex="1" id="map" class="map"></div>
|
<div tabindex="1" id="map" class="map"></div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import OSM from '../src/ol/source/OSM.js';
|
|||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
interactions: defaultInteractions({
|
interactions: defaultInteractions({
|
||||||
onFocusOnly: true
|
constrainResolution: true, onFocusOnly: true
|
||||||
}),
|
}),
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
|
|||||||
@@ -203,11 +203,7 @@ const map = new Map({
|
|||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
center: [-10997148, 4569099],
|
center: [-10997148, 4569099],
|
||||||
zoom: 4,
|
zoom: 4
|
||||||
minZoom: 1,
|
|
||||||
extent: [-Infinity, -20048966.10, Infinity, 20048966.10],
|
|
||||||
smoothExtentConstraint: false,
|
|
||||||
smoothResolutionConstraint: false
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ shortdesc: Restrict pinch zooming to integer zoom levels.
|
|||||||
docs: >
|
docs: >
|
||||||
By default, the `ol/interaction/PinchZoom` can leave the map at fractional zoom levels.
|
By default, the `ol/interaction/PinchZoom` can leave the map at fractional zoom levels.
|
||||||
If instead you want to constrain pinch zooming to integer zoom levels, set
|
If instead you want to constrain pinch zooming to integer zoom levels, set
|
||||||
<code>constrainResolution: true</code> when constructing the view.
|
<code>constrainResolution: true</code> when constructing the interaction.
|
||||||
tags: "pinch, zoom, interaction"
|
tags: "pinch, zoom, interaction"
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import OSM from '../src/ol/source/OSM.js';
|
|||||||
|
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
interactions: defaultInteractions().extend([
|
interactions: defaultInteractions({pinchZoom: false}).extend([
|
||||||
new PinchZoom()
|
new PinchZoom({
|
||||||
|
constrainResolution: true // force zooming to a integer zoom
|
||||||
|
})
|
||||||
]),
|
]),
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
@@ -17,7 +19,6 @@ const map = new Map({
|
|||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
center: [0, 0],
|
center: [0, 0],
|
||||||
zoom: 2,
|
zoom: 2
|
||||||
constrainResolution: true
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -103,9 +103,6 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="12px" id="points-size" />
|
<input type="text" value="12px" id="points-size" />
|
||||||
<br />
|
<br />
|
||||||
<label>Line height: </label>
|
|
||||||
<input type="text" value="1" id="points-height" />
|
|
||||||
<br />
|
|
||||||
<label>Offset X:</label>
|
<label>Offset X:</label>
|
||||||
<input type="text" value="0" id="points-offset-x" />
|
<input type="text" value="0" id="points-offset-x" />
|
||||||
<br />
|
<br />
|
||||||
@@ -215,9 +212,6 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="12px" id="lines-size" />
|
<input type="text" value="12px" id="lines-size" />
|
||||||
<br />
|
<br />
|
||||||
<label>Line height: </label>
|
|
||||||
<input type="text" value="1.2" id="lines-height" />
|
|
||||||
<br />
|
|
||||||
<label>Offset X:</label>
|
<label>Offset X:</label>
|
||||||
<input type="text" value="0" id="lines-offset-x" />
|
<input type="text" value="0" id="lines-offset-x" />
|
||||||
<br />
|
<br />
|
||||||
@@ -327,9 +321,6 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="10px" id="polygons-size" />
|
<input type="text" value="10px" id="polygons-size" />
|
||||||
<br />
|
<br />
|
||||||
<label>Line height: </label>
|
|
||||||
<input type="text" value="1" id="polygons-height" />
|
|
||||||
<br />
|
|
||||||
<label>Offset X:</label>
|
<label>Offset X:</label>
|
||||||
<input type="text" value="0" id="polygons-offset-x" />
|
<input type="text" value="0" id="polygons-offset-x" />
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const myDom = {
|
|||||||
font: document.getElementById('points-font'),
|
font: document.getElementById('points-font'),
|
||||||
weight: document.getElementById('points-weight'),
|
weight: document.getElementById('points-weight'),
|
||||||
size: document.getElementById('points-size'),
|
size: document.getElementById('points-size'),
|
||||||
height: document.getElementById('points-height'),
|
|
||||||
offsetX: document.getElementById('points-offset-x'),
|
offsetX: document.getElementById('points-offset-x'),
|
||||||
offsetY: document.getElementById('points-offset-y'),
|
offsetY: document.getElementById('points-offset-y'),
|
||||||
color: document.getElementById('points-color'),
|
color: document.getElementById('points-color'),
|
||||||
@@ -35,7 +34,6 @@ const myDom = {
|
|||||||
maxangle: document.getElementById('lines-maxangle'),
|
maxangle: document.getElementById('lines-maxangle'),
|
||||||
overflow: document.getElementById('lines-overflow'),
|
overflow: document.getElementById('lines-overflow'),
|
||||||
size: document.getElementById('lines-size'),
|
size: document.getElementById('lines-size'),
|
||||||
height: document.getElementById('lines-height'),
|
|
||||||
offsetX: document.getElementById('lines-offset-x'),
|
offsetX: document.getElementById('lines-offset-x'),
|
||||||
offsetY: document.getElementById('lines-offset-y'),
|
offsetY: document.getElementById('lines-offset-y'),
|
||||||
color: document.getElementById('lines-color'),
|
color: document.getElementById('lines-color'),
|
||||||
@@ -54,7 +52,6 @@ const myDom = {
|
|||||||
maxangle: document.getElementById('polygons-maxangle'),
|
maxangle: document.getElementById('polygons-maxangle'),
|
||||||
overflow: document.getElementById('polygons-overflow'),
|
overflow: document.getElementById('polygons-overflow'),
|
||||||
size: document.getElementById('polygons-size'),
|
size: document.getElementById('polygons-size'),
|
||||||
height: document.getElementById('polygons-height'),
|
|
||||||
offsetX: document.getElementById('polygons-offset-x'),
|
offsetX: document.getElementById('polygons-offset-x'),
|
||||||
offsetY: document.getElementById('polygons-offset-y'),
|
offsetY: document.getElementById('polygons-offset-y'),
|
||||||
color: document.getElementById('polygons-color'),
|
color: document.getElementById('polygons-color'),
|
||||||
@@ -87,7 +84,6 @@ const createTextStyle = function(feature, resolution, dom) {
|
|||||||
const align = dom.align.value;
|
const align = dom.align.value;
|
||||||
const baseline = dom.baseline.value;
|
const baseline = dom.baseline.value;
|
||||||
const size = dom.size.value;
|
const size = dom.size.value;
|
||||||
const height = dom.height.value;
|
|
||||||
const offsetX = parseInt(dom.offsetX.value, 10);
|
const offsetX = parseInt(dom.offsetX.value, 10);
|
||||||
const offsetY = parseInt(dom.offsetY.value, 10);
|
const offsetY = parseInt(dom.offsetY.value, 10);
|
||||||
const weight = dom.weight.value;
|
const weight = dom.weight.value;
|
||||||
@@ -102,7 +98,7 @@ const createTextStyle = function(feature, resolution, dom) {
|
|||||||
document.getElementsByTagName('head')[0].appendChild(openSans);
|
document.getElementsByTagName('head')[0].appendChild(openSans);
|
||||||
openSansAdded = true;
|
openSansAdded = true;
|
||||||
}
|
}
|
||||||
const font = weight + ' ' + size + '/' + height + ' ' + dom.font.value;
|
const font = weight + ' ' + size + ' ' + dom.font.value;
|
||||||
const fillColor = dom.color.value;
|
const fillColor = dom.color.value;
|
||||||
const outlineColor = dom.outline.value;
|
const outlineColor = dom.outline.value;
|
||||||
const outlineWidth = parseInt(dom.outlineWidth.value, 10);
|
const outlineWidth = parseInt(dom.outlineWidth.value, 10);
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ol",
|
"name": "ol",
|
||||||
"version": "6.0.0-beta.3",
|
"version": "6.0.0-beta.2",
|
||||||
"description": "OpenLayers mapping library",
|
"description": "OpenLayers mapping library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"map",
|
"map",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"url": "https://github.com/openlayers/openlayers/issues"
|
"url": "https://github.com/openlayers/openlayers/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pbf": "3.2.0",
|
"pbf": "3.1.0",
|
||||||
"pixelworks": "1.1.0",
|
"pixelworks": "1.1.0",
|
||||||
"rbush": "2.0.2"
|
"rbush": "2.0.2"
|
||||||
},
|
},
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"front-matter": "^3.0.1",
|
"front-matter": "^3.0.1",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"globby": "^9.1.0",
|
"globby": "^8.0.1",
|
||||||
"handlebars": "4.1.0",
|
"handlebars": "4.1.0",
|
||||||
"istanbul": "0.4.5",
|
"istanbul": "0.4.5",
|
||||||
"jquery": "3.3.1",
|
"jquery": "3.3.1",
|
||||||
@@ -75,11 +75,11 @@
|
|||||||
"loglevelnext": "^3.0.0",
|
"loglevelnext": "^3.0.0",
|
||||||
"marked": "0.6.1",
|
"marked": "0.6.1",
|
||||||
"mocha": "6.0.2",
|
"mocha": "6.0.2",
|
||||||
"ol-mapbox-style": "^4.1.0",
|
"ol-mapbox-style": "^4.0.0",
|
||||||
"pixelmatch": "^4.0.2",
|
"pixelmatch": "^4.0.2",
|
||||||
"pngjs": "^3.3.3",
|
"pngjs": "^3.3.3",
|
||||||
"proj4": "2.5.0",
|
"proj4": "2.5.0",
|
||||||
"puppeteer": "~1.11.0",
|
"puppeteer": "^1.12.2",
|
||||||
"serve-static": "^1.13.2",
|
"serve-static": "^1.13.2",
|
||||||
"shx": "^0.3.2",
|
"shx": "^0.3.2",
|
||||||
"sinon": "^7.2.3",
|
"sinon": "^7.2.3",
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class VectorTile extends Tile {
|
|||||||
this.consumers = 0;
|
this.consumers = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extent of this tile; set by the source.
|
* @private
|
||||||
* @type {import("./extent.js").Extent}
|
* @type {import("./extent.js").Extent}
|
||||||
*/
|
*/
|
||||||
this.extent = null;
|
this.extent_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -48,16 +48,11 @@ class VectorTile extends Tile {
|
|||||||
this.loader_;
|
this.loader_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Feature projection of this tile; set by the source.
|
* Data projection
|
||||||
|
* @private
|
||||||
* @type {import("./proj/Projection.js").default}
|
* @type {import("./proj/Projection.js").default}
|
||||||
*/
|
*/
|
||||||
this.projection = null;
|
this.projection_ = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolution of this tile; set by the source.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.resolution;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -81,6 +76,15 @@ class VectorTile extends Tile {
|
|||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the extent of the vector tile.
|
||||||
|
* @return {import("./extent.js").Extent} The extent.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getExtent() {
|
||||||
|
return this.extent_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the feature format assigned for reading this tile's features.
|
* Get the feature format assigned for reading this tile's features.
|
||||||
* @return {import("./format/Feature.js").default} Feature format.
|
* @return {import("./format/Feature.js").default} Feature format.
|
||||||
@@ -91,7 +95,8 @@ class VectorTile extends Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the features for this tile. Geometries will be in the view projection.
|
* Get the features for this tile. Geometries will be in the projection returned
|
||||||
|
* by {@link module:ol/VectorTile~VectorTile#getProjection}.
|
||||||
* @return {Array<import("./Feature.js").FeatureLike>} Features.
|
* @return {Array<import("./Feature.js").FeatureLike>} Features.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
@@ -106,6 +111,16 @@ class VectorTile extends Tile {
|
|||||||
return this.url_;
|
return this.url_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the feature projection of features returned by
|
||||||
|
* {@link module:ol/VectorTile~VectorTile#getFeatures}.
|
||||||
|
* @return {import("./proj/Projection.js").default} Feature projection.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getProjection() {
|
||||||
|
return this.projection_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@@ -113,7 +128,7 @@ class VectorTile extends Tile {
|
|||||||
if (this.state == TileState.IDLE) {
|
if (this.state == TileState.IDLE) {
|
||||||
this.setState(TileState.LOADING);
|
this.setState(TileState.LOADING);
|
||||||
this.tileLoadFunction_(this, this.url_);
|
this.tileLoadFunction_(this, this.url_);
|
||||||
this.loader_(this.extent, this.resolution, this.projection);
|
this.loader_(null, NaN, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +136,11 @@ class VectorTile extends Tile {
|
|||||||
* Handler for successful tile load.
|
* Handler for successful tile load.
|
||||||
* @param {Array<import("./Feature.js").default>} features The loaded features.
|
* @param {Array<import("./Feature.js").default>} features The loaded features.
|
||||||
* @param {import("./proj/Projection.js").default} dataProjection Data projection.
|
* @param {import("./proj/Projection.js").default} dataProjection Data projection.
|
||||||
|
* @param {import("./extent.js").Extent} extent Extent.
|
||||||
*/
|
*/
|
||||||
onLoad(features, dataProjection) {
|
onLoad(features, dataProjection, extent) {
|
||||||
|
this.setProjection(dataProjection);
|
||||||
|
this.setExtent(extent);
|
||||||
this.setFeatures(features);
|
this.setFeatures(features);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +151,22 @@ class VectorTile extends Tile {
|
|||||||
this.setState(TileState.ERROR);
|
this.setState(TileState.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s
|
||||||
|
* `tileLoadFunction`. Sets the extent of the vector tile. This is only required
|
||||||
|
* for tiles in projections with `tile-pixels` as units. The extent should be
|
||||||
|
* set to `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is
|
||||||
|
* calculated by multiplying the tile size with the tile pixel ratio. For
|
||||||
|
* sources using {@link module:ol/format/MVT~MVT} as feature format, the
|
||||||
|
* {@link module:ol/format/MVT~MVT#getLastExtent} method will return the correct
|
||||||
|
* extent.
|
||||||
|
* @param {import("./extent.js").Extent} extent The extent.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
setExtent(extent) {
|
||||||
|
this.extent_ = extent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||||
* Sets the features for the tile.
|
* Sets the features for the tile.
|
||||||
@@ -144,6 +178,17 @@ class VectorTile extends Tile {
|
|||||||
this.setState(TileState.LOADED);
|
this.setState(TileState.LOADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||||
|
* Sets the projection of the features that were added with
|
||||||
|
* {@link module:ol/VectorTile~VectorTile#setFeatures}.
|
||||||
|
* @param {import("./proj/Projection.js").default} projection Feature projection.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
setProjection(projection) {
|
||||||
|
this.projection_ = projection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the feature loader for reading this tile's features.
|
* Set the feature loader for reading this tile's features.
|
||||||
* @param {import("./featureloader.js").FeatureLoader} loader Feature loader.
|
* @param {import("./featureloader.js").FeatureLoader} loader Feature loader.
|
||||||
|
|||||||
497
src/ol/View.js
497
src/ol/View.js
@@ -21,9 +21,6 @@ import {clamp, modulo} from './math.js';
|
|||||||
import {assign} from './obj.js';
|
import {assign} from './obj.js';
|
||||||
import {createProjection, METERS_PER_UNIT} from './proj.js';
|
import {createProjection, METERS_PER_UNIT} from './proj.js';
|
||||||
import Units from './proj/Units.js';
|
import Units from './proj/Units.js';
|
||||||
import {equals} from './coordinate';
|
|
||||||
import {easeOut} from './easing';
|
|
||||||
import {createMinMaxResolution} from './resolutionconstraint';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,8 +58,9 @@ import {createMinMaxResolution} from './resolutionconstraint';
|
|||||||
* @property {!Array<number>} [padding=[0, 0, 0, 0]] Padding (in pixels) to be
|
* @property {!Array<number>} [padding=[0, 0, 0, 0]] Padding (in pixels) to be
|
||||||
* cleared inside the view. Values in the array are top, right, bottom and left
|
* cleared inside the view. Values in the array are top, right, bottom and left
|
||||||
* padding.
|
* padding.
|
||||||
* @property {boolean} [nearest=false] If the view `constrainResolution` option is `true`,
|
* @property {boolean} [constrainResolution=true] Constrain the resolution.
|
||||||
* get the nearest extent instead of the closest that actually fits the view.
|
* @property {boolean} [nearest=false] If `constrainResolution` is `true`, get
|
||||||
|
* the nearest extent instead of the closest that actually fits the view.
|
||||||
* @property {number} [minResolution=0] Minimum resolution that we zoom to.
|
* @property {number} [minResolution=0] Minimum resolution that we zoom to.
|
||||||
* @property {number} [maxZoom] Maximum zoom level that we zoom to. If
|
* @property {number} [maxZoom] Maximum zoom level that we zoom to. If
|
||||||
* `minResolution` is given, this property is ignored.
|
* `minResolution` is given, this property is ignored.
|
||||||
@@ -94,12 +92,7 @@ import {createMinMaxResolution} from './resolutionconstraint';
|
|||||||
* used. The `constrainRotation` option has no effect if `enableRotation` is
|
* used. The `constrainRotation` option has no effect if `enableRotation` is
|
||||||
* `false`.
|
* `false`.
|
||||||
* @property {import("./extent.js").Extent} [extent] The extent that constrains the
|
* @property {import("./extent.js").Extent} [extent] The extent that constrains the
|
||||||
* view, in other words, nothing outside of this extent can be visible on the map.
|
* center, in other words, center cannot be set outside this extent.
|
||||||
* @property {boolean} [constrainOnlyCenter=false] If true, the extent
|
|
||||||
* constraint will only apply to the view center and not the whole extent.
|
|
||||||
* @property {boolean} [smoothExtentConstraint=true] If true, the extent
|
|
||||||
* constraint will be applied smoothly, i.e. allow the view to go slightly outside
|
|
||||||
* of the given `extent`.
|
|
||||||
* @property {number} [maxResolution] The maximum resolution used to determine
|
* @property {number} [maxResolution] The maximum resolution used to determine
|
||||||
* the resolution constraint. It is used together with `minResolution` (or
|
* the resolution constraint. It is used together with `minResolution` (or
|
||||||
* `maxZoom`) and `zoomFactor`. If unspecified it is calculated in such a way
|
* `maxZoom`) and `zoomFactor`. If unspecified it is calculated in such a way
|
||||||
@@ -120,12 +113,6 @@ 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} [constrainResolution=false] If true, the view will always
|
|
||||||
* animate to the closest zoom level after an interaction; false means
|
|
||||||
* intermediary zoom levels are allowed.
|
|
||||||
* @property {boolean} [smoothResolutionConstraint=true] If true, the resolution
|
|
||||||
* min/max values will be applied smoothly, i. e. allow the view to exceed slightly
|
|
||||||
* the given resolution or zoom bounds.
|
|
||||||
* @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] The
|
* @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] The
|
||||||
* projection. The default is Spherical Mercator.
|
* projection. The default is Spherical Mercator.
|
||||||
* @property {number} [resolution] The initial resolution for the view. The
|
* @property {number} [resolution] The initial resolution for the view. The
|
||||||
@@ -139,9 +126,10 @@ import {createMinMaxResolution} from './resolutionconstraint';
|
|||||||
* @property {number} [rotation=0] The initial rotation for the view in radians
|
* @property {number} [rotation=0] The initial rotation for the view in radians
|
||||||
* (positive rotation clockwise, 0 means North).
|
* (positive rotation clockwise, 0 means North).
|
||||||
* @property {number} [zoom] Only used if `resolution` is not defined. Zoom
|
* @property {number} [zoom] Only used if `resolution` is not defined. Zoom
|
||||||
* level used to calculate the initial resolution for the view.
|
* level used to calculate the initial resolution for the view. The initial
|
||||||
* @property {number} [zoomFactor=2] The zoom factor used to compute the
|
* resolution is determined using the {@link #constrainResolution} method.
|
||||||
* corresponding resolution.
|
* @property {number} [zoomFactor=2] The zoom factor used to determine the
|
||||||
|
* resolution constraint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -155,7 +143,7 @@ import {createMinMaxResolution} from './resolutionconstraint';
|
|||||||
* of the animation. If `zoom` is also provided, this option will be ignored.
|
* of the animation. If `zoom` is also provided, this option will be ignored.
|
||||||
* @property {number} [rotation] The rotation of the view at the end of
|
* @property {number} [rotation] The rotation of the view at the end of
|
||||||
* the animation.
|
* the animation.
|
||||||
* @property {import("./coordinate.js").Coordinate} [anchor] Optional anchor to remain fixed
|
* @property {import("./coordinate.js").Coordinate} [anchor] Optional anchor to remained fixed
|
||||||
* during a rotation or resolution animation.
|
* during a rotation or resolution animation.
|
||||||
* @property {number} [duration=1000] The duration of the animation in milliseconds.
|
* @property {number} [duration=1000] The duration of the animation in milliseconds.
|
||||||
* @property {function(number):number} [easing] The easing function used
|
* @property {function(number):number} [easing] The easing function used
|
||||||
@@ -196,12 +184,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
* and `rotation`. Each state has a corresponding getter and setter, e.g.
|
* and `rotation`. Each state has a corresponding getter and setter, e.g.
|
||||||
* `getCenter` and `setCenter` for the `center` state.
|
* `getCenter` and `setCenter` for the `center` state.
|
||||||
*
|
*
|
||||||
* The `zoom` state is actually not saved on the view: all computations
|
* An View has a `projection`. The projection determines the
|
||||||
* internally use the `resolution` state. Still, the `setZoom` and `getZoom`
|
|
||||||
* methods are available, as well as `getResolutionForZoom` and
|
|
||||||
* `getZoomForResolution` to switch from one system to the other.
|
|
||||||
*
|
|
||||||
* A View has a `projection`. The projection determines the
|
|
||||||
* coordinate system of the center, and its units determine the units of the
|
* coordinate system of the center, and its units determine the units of the
|
||||||
* resolution (projection units per pixel). The default projection is
|
* resolution (projection units per pixel). The default projection is
|
||||||
* Spherical Mercator (EPSG:3857).
|
* Spherical Mercator (EPSG:3857).
|
||||||
@@ -209,19 +192,28 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
* ### The constraints
|
* ### The constraints
|
||||||
*
|
*
|
||||||
* `setCenter`, `setResolution` and `setRotation` can be used to change the
|
* `setCenter`, `setResolution` and `setRotation` can be used to change the
|
||||||
* states of the view, but any constraint defined in the constructor will
|
* states of the view. Any value can be passed to the setters. And the value
|
||||||
* be applied along the way.
|
* that is passed to a setter will effectively be the value set in the view,
|
||||||
|
* and returned by the corresponding getter.
|
||||||
*
|
*
|
||||||
* A View object can have a *resolution constraint*, a *rotation constraint*
|
* But a View object also has a *resolution constraint*, a
|
||||||
* and a *center constraint*.
|
* *rotation constraint* and a *center constraint*.
|
||||||
*
|
*
|
||||||
* The *resolution constraint* typically restricts min/max values and
|
* As said above, no constraints are applied when the setters are used to set
|
||||||
* snaps to specific resolutions. It is determined by the following
|
* new states for the view. Applying constraints is done explicitly through
|
||||||
* options: `resolutions`, `maxResolution`, `maxZoom`, and `zoomFactor`.
|
* the use of the `constrain*` functions (`constrainResolution` and
|
||||||
* If `resolutions` is set, the other three options are ignored. See
|
* `constrainRotation` and `constrainCenter`).
|
||||||
* documentation for each option for more information. By default, the view
|
*
|
||||||
* only has a min/max restriction and allow intermediary zoom levels when
|
* The main users of the constraints are the interactions and the
|
||||||
* pinch-zooming for example.
|
* controls. For example, double-clicking on the map changes the view to
|
||||||
|
* the "next" resolution. And releasing the fingers after pinch-zooming
|
||||||
|
* snaps to the closest resolution (with an animation).
|
||||||
|
*
|
||||||
|
* The *resolution constraint* snaps to specific resolutions. It is
|
||||||
|
* determined by the following options: `resolutions`, `maxResolution`,
|
||||||
|
* `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three
|
||||||
|
* options are ignored. See documentation for each option for more
|
||||||
|
* information.
|
||||||
*
|
*
|
||||||
* The *rotation constraint* snaps to specific angles. It is determined
|
* The *rotation constraint* snaps to specific angles. It is determined
|
||||||
* by the following options: `enableRotation` and `constrainRotation`.
|
* by the following options: `enableRotation` and `constrainRotation`.
|
||||||
@@ -229,29 +221,7 @@ const DEFAULT_MIN_ZOOM = 0;
|
|||||||
* horizontal.
|
* horizontal.
|
||||||
*
|
*
|
||||||
* The *center constraint* is determined by the `extent` option. By
|
* The *center constraint* is determined by the `extent` option. By
|
||||||
* default the view center is not constrained at all.
|
* default the center is not constrained at all.
|
||||||
*
|
|
||||||
* ### Changing the view state
|
|
||||||
*
|
|
||||||
* It is important to note that `setZoom`, `setResolution`, `setCenter` and
|
|
||||||
* `setRotation` are subject to the above mentioned constraints. As such, it
|
|
||||||
* may sometimes not be possible to know in advance the resulting state of the
|
|
||||||
* View. For example, calling `setResolution(10)` does not guarantee that
|
|
||||||
* `getResolution()` will return `10`.
|
|
||||||
*
|
|
||||||
* A consequence of this is that, when applying a delta on the view state, one
|
|
||||||
* should use `adjustCenter`, `adjustRotation`, `adjustZoom` and `adjustResolution`
|
|
||||||
* rather than the corresponding setters. This will let view do its internal
|
|
||||||
* computations. Besides, the `adjust*` methods also take an `opt_anchor`
|
|
||||||
* argument which allows specifying an origin for the transformation.
|
|
||||||
*
|
|
||||||
* ### Interacting with the view
|
|
||||||
*
|
|
||||||
* View constraints are usually only applied when the view is *at rest*, meaning that
|
|
||||||
* no interaction or animation is ongoing. As such, if the user puts the view in a
|
|
||||||
* state that is not equivalent to a constrained one (e.g. rotating the view when
|
|
||||||
* the snap angle is 0), an animation will be triggered at the interaction end to
|
|
||||||
* put back the view to a stable state;
|
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
@@ -292,24 +262,6 @@ class View extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
this.projection_ = createProjection(options.projection, 'EPSG:3857');
|
this.projection_ = createProjection(options.projection, 'EPSG:3857');
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {import("./coordinate.js").Coordinate|undefined}
|
|
||||||
*/
|
|
||||||
this.targetCenter_ = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {number|undefined}
|
|
||||||
*/
|
|
||||||
this.targetResolution_;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {number|undefined}
|
|
||||||
*/
|
|
||||||
this.targetRotation_;
|
|
||||||
|
|
||||||
this.applyOptions_(options);
|
this.applyOptions_(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,6 +275,8 @@ class View extends BaseObject {
|
|||||||
* @type {Object<string, *>}
|
* @type {Object<string, *>}
|
||||||
*/
|
*/
|
||||||
const properties = {};
|
const properties = {};
|
||||||
|
properties[ViewProperty.CENTER] = options.center !== undefined ?
|
||||||
|
options.center : null;
|
||||||
|
|
||||||
const resolutionConstraintInfo = createResolutionConstraint(options);
|
const resolutionConstraintInfo = createResolutionConstraint(options);
|
||||||
|
|
||||||
@@ -370,20 +324,19 @@ class View extends BaseObject {
|
|||||||
rotation: rotationConstraint
|
rotation: rotationConstraint
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setRotation(options.rotation !== undefined ? options.rotation : 0);
|
|
||||||
this.setCenter(options.center !== undefined ? options.center : null);
|
|
||||||
if (options.resolution !== undefined) {
|
if (options.resolution !== undefined) {
|
||||||
this.setResolution(options.resolution);
|
properties[ViewProperty.RESOLUTION] = options.resolution;
|
||||||
} else if (options.zoom !== undefined) {
|
} else if (options.zoom !== undefined) {
|
||||||
if (this.resolutions_) { // in case map zoom is out of min/max zoom range
|
properties[ViewProperty.RESOLUTION] = this.constrainResolution(
|
||||||
const resolution = this.getResolutionForZoom(options.zoom);
|
this.maxResolution_, options.zoom - this.minZoom_);
|
||||||
this.setResolution(clamp(resolution,
|
|
||||||
this.minResolution_, this.maxResolution_));
|
|
||||||
} else {
|
|
||||||
this.setZoom(options.zoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (this.resolutions_) { // in case map zoom is out of min/max zoom range
|
||||||
|
properties[ViewProperty.RESOLUTION] = clamp(
|
||||||
|
Number(this.getResolution() || properties[ViewProperty.RESOLUTION]),
|
||||||
|
this.minResolution_, this.maxResolution_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties[ViewProperty.ROTATION] = options.rotation !== undefined ? options.rotation : 0;
|
||||||
this.setProperties(properties);
|
this.setProperties(properties);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -479,9 +432,9 @@ class View extends BaseObject {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let start = Date.now();
|
let start = Date.now();
|
||||||
let center = this.targetCenter_.slice();
|
let center = this.getCenter().slice();
|
||||||
let resolution = this.targetResolution_;
|
let resolution = this.getResolution();
|
||||||
let rotation = this.targetRotation_;
|
let rotation = this.getRotation();
|
||||||
const series = [];
|
const series = [];
|
||||||
for (let i = 0; i < animationCount; ++i) {
|
for (let i = 0; i < animationCount; ++i) {
|
||||||
const options = /** @type {AnimationOptions} */ (arguments[i]);
|
const options = /** @type {AnimationOptions} */ (arguments[i]);
|
||||||
@@ -497,13 +450,14 @@ class View extends BaseObject {
|
|||||||
|
|
||||||
if (options.center) {
|
if (options.center) {
|
||||||
animation.sourceCenter = center;
|
animation.sourceCenter = center;
|
||||||
animation.targetCenter = options.center.slice();
|
animation.targetCenter = options.center;
|
||||||
center = animation.targetCenter;
|
center = animation.targetCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.zoom !== undefined) {
|
if (options.zoom !== undefined) {
|
||||||
animation.sourceResolution = resolution;
|
animation.sourceResolution = resolution;
|
||||||
animation.targetResolution = this.getResolutionForZoom(options.zoom);
|
animation.targetResolution = this.constrainResolution(
|
||||||
|
this.maxResolution_, options.zoom - this.minZoom_, 0);
|
||||||
resolution = animation.targetResolution;
|
resolution = animation.targetResolution;
|
||||||
} else if (options.resolution) {
|
} else if (options.resolution) {
|
||||||
animation.sourceResolution = resolution;
|
animation.sourceResolution = resolution;
|
||||||
@@ -602,31 +556,28 @@ class View extends BaseObject {
|
|||||||
const y1 = animation.targetCenter[1];
|
const y1 = animation.targetCenter[1];
|
||||||
const x = x0 + progress * (x1 - x0);
|
const x = x0 + progress * (x1 - x0);
|
||||||
const y = y0 + progress * (y1 - y0);
|
const y = y0 + progress * (y1 - y0);
|
||||||
this.targetCenter_ = [x, y];
|
this.set(ViewProperty.CENTER, [x, y]);
|
||||||
}
|
}
|
||||||
if (animation.sourceResolution && animation.targetResolution) {
|
if (animation.sourceResolution && animation.targetResolution) {
|
||||||
const resolution = progress === 1 ?
|
const resolution = progress === 1 ?
|
||||||
animation.targetResolution :
|
animation.targetResolution :
|
||||||
animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
|
animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
|
||||||
if (animation.anchor) {
|
if (animation.anchor) {
|
||||||
const size = this.getSizeFromViewport_(this.getRotation());
|
this.set(ViewProperty.CENTER,
|
||||||
const constrainedResolution = this.constraints_.resolution(resolution, 0, size, true);
|
this.calculateCenterZoom(resolution, animation.anchor));
|
||||||
this.targetCenter_ = this.calculateCenterZoom(constrainedResolution, animation.anchor);
|
|
||||||
}
|
}
|
||||||
this.targetResolution_ = resolution;
|
this.set(ViewProperty.RESOLUTION, resolution);
|
||||||
this.applyTargetState_(true);
|
|
||||||
}
|
}
|
||||||
if (animation.sourceRotation !== undefined && animation.targetRotation !== undefined) {
|
if (animation.sourceRotation !== undefined && animation.targetRotation !== undefined) {
|
||||||
const rotation = progress === 1 ?
|
const rotation = progress === 1 ?
|
||||||
modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI :
|
modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI :
|
||||||
animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation);
|
animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation);
|
||||||
if (animation.anchor) {
|
if (animation.anchor) {
|
||||||
const constrainedRotation = this.constraints_.rotation(rotation, true);
|
this.set(ViewProperty.CENTER,
|
||||||
this.targetCenter_ = this.calculateCenterRotate(constrainedRotation, animation.anchor);
|
this.calculateCenterRotate(rotation, animation.anchor));
|
||||||
}
|
}
|
||||||
this.targetRotation_ = rotation;
|
this.set(ViewProperty.ROTATION, rotation);
|
||||||
}
|
}
|
||||||
this.applyTargetState_(true);
|
|
||||||
more = true;
|
more = true;
|
||||||
if (!animation.complete) {
|
if (!animation.complete) {
|
||||||
break;
|
break;
|
||||||
@@ -646,10 +597,6 @@ class View extends BaseObject {
|
|||||||
if (more && this.updateAnimationKey_ === undefined) {
|
if (more && this.updateAnimationKey_ === undefined) {
|
||||||
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);
|
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.getAnimating()) {
|
|
||||||
setTimeout(this.resolveConstraints_.bind(this), 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -687,10 +634,9 @@ class View extends BaseObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {number=} opt_rotation Take into account the rotation of the viewport when giving the size
|
|
||||||
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
||||||
*/
|
*/
|
||||||
getSizeFromViewport_(opt_rotation) {
|
getSizeFromViewport_() {
|
||||||
const size = [100, 100];
|
const size = [100, 100];
|
||||||
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
||||||
const element = document.querySelector(selector);
|
const element = document.querySelector(selector);
|
||||||
@@ -699,15 +645,45 @@ class View extends BaseObject {
|
|||||||
size[0] = parseInt(metrics.width, 10);
|
size[0] = parseInt(metrics.width, 10);
|
||||||
size[1] = parseInt(metrics.height, 10);
|
size[1] = parseInt(metrics.height, 10);
|
||||||
}
|
}
|
||||||
if (opt_rotation) {
|
|
||||||
const w = size[0];
|
|
||||||
const h = size[1];
|
|
||||||
size[0] = Math.abs(w * Math.cos(opt_rotation)) + Math.abs(h * Math.sin(opt_rotation));
|
|
||||||
size[1] = Math.abs(w * Math.sin(opt_rotation)) + Math.abs(h * Math.cos(opt_rotation));
|
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the constrained center of this view.
|
||||||
|
* @param {import("./coordinate.js").Coordinate|undefined} center Center.
|
||||||
|
* @return {import("./coordinate.js").Coordinate|undefined} Constrained center.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
constrainCenter(center) {
|
||||||
|
return this.constraints_.center(center);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the constrained resolution of this view.
|
||||||
|
* @param {number|undefined} resolution Resolution.
|
||||||
|
* @param {number=} opt_delta Delta. Default is `0`.
|
||||||
|
* @param {number=} opt_direction Direction. Default is `0`.
|
||||||
|
* @return {number|undefined} Constrained resolution.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
constrainResolution(resolution, opt_delta, opt_direction) {
|
||||||
|
const delta = opt_delta || 0;
|
||||||
|
const direction = opt_direction || 0;
|
||||||
|
return this.constraints_.resolution(resolution, delta, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the constrained rotation of this view.
|
||||||
|
* @param {number|undefined} rotation Rotation.
|
||||||
|
* @param {number=} opt_delta Delta. Default is `0`.
|
||||||
|
* @return {number|undefined} Constrained rotation.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
constrainRotation(rotation, opt_delta) {
|
||||||
|
const delta = opt_delta || 0;
|
||||||
|
return this.constraints_.rotation(rotation, delta);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the view center.
|
* Get the view center.
|
||||||
* @return {import("./coordinate.js").Coordinate|undefined} The center of the view.
|
* @return {import("./coordinate.js").Coordinate|undefined} The center of the view.
|
||||||
@@ -817,15 +793,6 @@ class View extends BaseObject {
|
|||||||
this.applyOptions_(this.getUpdatedOptions_({minZoom: zoom}));
|
this.applyOptions_(this.getUpdatedOptions_({minZoom: zoom}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether the view shoud allow intermediary zoom levels.
|
|
||||||
* @param {boolean} enabled Whether the resolution is constrained.
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
setConstrainResolution(enabled) {
|
|
||||||
this.applyOptions_(this.getUpdatedOptions_({constrainResolution: enabled}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the view projection.
|
* Get the view projection.
|
||||||
* @return {import("./proj/Projection.js").default} The projection of the view.
|
* @return {import("./proj/Projection.js").default} The projection of the view.
|
||||||
@@ -947,9 +914,9 @@ class View extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current zoom level. This method may return non-integer zoom levels
|
* Get the current zoom level. If you configured your view with a resolutions
|
||||||
* if the view does not constrain the resolution, or if an interaction or
|
* array (this is rare), this method may return non-integer zoom levels (so
|
||||||
* animation is underway.
|
* the zoom level is not safe to use as an index into a resolutions array).
|
||||||
* @return {number|undefined} Zoom.
|
* @return {number|undefined} Zoom.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
@@ -994,16 +961,8 @@ class View extends BaseObject {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getResolutionForZoom(zoom) {
|
getResolutionForZoom(zoom) {
|
||||||
if (this.resolutions_) {
|
return /** @type {number} */ (this.constrainResolution(
|
||||||
if (this.resolutions_.length <= 1) {
|
this.maxResolution_, zoom - this.minZoom_, 0));
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const baseLevel = clamp(Math.floor(zoom), 0, this.resolutions_.length - 2);
|
|
||||||
const zoomFactor = this.resolutions_[baseLevel] / this.resolutions_[baseLevel + 1];
|
|
||||||
return this.resolutions_[baseLevel] / Math.pow(zoomFactor, clamp(zoom - baseLevel, 0, 1));
|
|
||||||
} else {
|
|
||||||
return this.maxResolution_ / Math.pow(this.zoomFactor_, zoom - this.minZoom_);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1039,12 +998,15 @@ class View extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
|
const padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
|
||||||
|
const constrainResolution = options.constrainResolution !== undefined ?
|
||||||
|
options.constrainResolution : true;
|
||||||
const nearest = options.nearest !== undefined ? options.nearest : false;
|
const nearest = options.nearest !== undefined ? options.nearest : false;
|
||||||
let minResolution;
|
let minResolution;
|
||||||
if (options.minResolution !== undefined) {
|
if (options.minResolution !== undefined) {
|
||||||
minResolution = options.minResolution;
|
minResolution = options.minResolution;
|
||||||
} else if (options.maxZoom !== undefined) {
|
} else if (options.maxZoom !== undefined) {
|
||||||
minResolution = this.getResolutionForZoom(options.maxZoom);
|
minResolution = this.constrainResolution(
|
||||||
|
this.maxResolution_, options.maxZoom - this.minZoom_, 0);
|
||||||
} else {
|
} else {
|
||||||
minResolution = 0;
|
minResolution = 0;
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1036,14 @@ class View extends BaseObject {
|
|||||||
[size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);
|
[size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);
|
||||||
resolution = isNaN(resolution) ? minResolution :
|
resolution = isNaN(resolution) ? minResolution :
|
||||||
Math.max(resolution, minResolution);
|
Math.max(resolution, minResolution);
|
||||||
resolution = this.getConstrainedResolution(resolution, nearest ? 0 : 1);
|
if (constrainResolution) {
|
||||||
|
let constrainedResolution = this.constrainResolution(resolution, 0, 0);
|
||||||
|
if (!nearest && constrainedResolution < resolution) {
|
||||||
|
constrainedResolution = this.constrainResolution(
|
||||||
|
constrainedResolution, -1, 0);
|
||||||
|
}
|
||||||
|
resolution = constrainedResolution;
|
||||||
|
}
|
||||||
|
|
||||||
// calculate center
|
// calculate center
|
||||||
sinAngle = -sinAngle; // go back to original rotation
|
sinAngle = -sinAngle; // go back to original rotation
|
||||||
@@ -1090,14 +1059,13 @@ class View extends BaseObject {
|
|||||||
if (options.duration !== undefined) {
|
if (options.duration !== undefined) {
|
||||||
this.animate({
|
this.animate({
|
||||||
resolution: resolution,
|
resolution: resolution,
|
||||||
center: this.getConstrainedCenter(center, resolution),
|
center: center,
|
||||||
duration: options.duration,
|
duration: options.duration,
|
||||||
easing: options.easing
|
easing: options.easing
|
||||||
}, callback);
|
}, callback);
|
||||||
} else {
|
} else {
|
||||||
this.targetResolution_ = resolution;
|
this.setResolution(resolution);
|
||||||
this.targetCenter_ = center;
|
this.setCenter(center);
|
||||||
this.applyTargetState_(false, true);
|
|
||||||
animationCallback(callback, true);
|
animationCallback(callback, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1136,74 +1104,30 @@ class View extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds relative coordinates to the center of the view. Any extent constraint will apply.
|
* Rotate the view around a given coordinate.
|
||||||
* @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add.
|
* @param {number} rotation New rotation value for the view.
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
adjustCenter(deltaCoordinates) {
|
|
||||||
const center = this.targetCenter_;
|
|
||||||
this.setCenter([center[0] + deltaCoordinates[0], center[1] + deltaCoordinates[1]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiply the view resolution by a ratio, optionally using an anchor. Any resolution
|
|
||||||
* constraint will apply.
|
|
||||||
* @param {number} ratio The ratio to apply on the view resolution.
|
|
||||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
|
||||||
* @observable
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
adjustResolution(ratio, opt_anchor) {
|
|
||||||
const isMoving = this.getAnimating() || this.getInteracting();
|
|
||||||
const size = this.getSizeFromViewport_(this.getRotation());
|
|
||||||
const newResolution = this.constraints_.resolution(this.targetResolution_ * ratio, 0, size, isMoving);
|
|
||||||
|
|
||||||
if (opt_anchor !== undefined) {
|
|
||||||
this.targetCenter_ = this.calculateCenterZoom(newResolution, opt_anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.targetResolution_ *= ratio;
|
|
||||||
this.applyTargetState_();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a value to the view zoom level, optionally using an anchor. Any resolution
|
|
||||||
* constraint will apply.
|
|
||||||
* @param {number} delta Relative value to add to the zoom level.
|
|
||||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
adjustZoom(delta, opt_anchor) {
|
|
||||||
this.adjustResolution(Math.pow(this.zoomFactor_, -delta), opt_anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a value to the view rotation, optionally using an anchor. Any rotation
|
|
||||||
* constraint will apply.
|
|
||||||
* @param {number} delta Relative value to add to the zoom rotation, in radians.
|
|
||||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The rotation center.
|
* @param {import("./coordinate.js").Coordinate=} opt_anchor The rotation center.
|
||||||
* @observable
|
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
adjustRotation(delta, opt_anchor) {
|
rotate(rotation, opt_anchor) {
|
||||||
const isMoving = this.getAnimating() || this.getInteracting();
|
|
||||||
const newRotation = this.constraints_.rotation(this.targetRotation_ + delta, isMoving);
|
|
||||||
if (opt_anchor !== undefined) {
|
if (opt_anchor !== undefined) {
|
||||||
this.targetCenter_ = this.calculateCenterRotate(newRotation, opt_anchor);
|
const center = this.calculateCenterRotate(rotation, opt_anchor);
|
||||||
|
this.setCenter(center);
|
||||||
}
|
}
|
||||||
this.targetRotation_ += delta;
|
this.setRotation(rotation);
|
||||||
this.applyTargetState_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the center of the current view. Any extent constraint will apply.
|
* Set the center of the current view.
|
||||||
* @param {import("./coordinate.js").Coordinate|undefined} center The center of the view.
|
* @param {import("./coordinate.js").Coordinate|undefined} center The center of the view.
|
||||||
* @observable
|
* @observable
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setCenter(center) {
|
setCenter(center) {
|
||||||
this.targetCenter_ = center;
|
this.set(ViewProperty.CENTER, center);
|
||||||
this.applyTargetState_();
|
if (this.getAnimating()) {
|
||||||
|
this.cancelAnimations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1218,166 +1142,39 @@ class View extends BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the resolution for this view. Any resolution constraint will apply.
|
* Set the resolution for this view.
|
||||||
* @param {number|undefined} resolution The resolution of the view.
|
* @param {number|undefined} resolution The resolution of the view.
|
||||||
* @observable
|
* @observable
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setResolution(resolution) {
|
setResolution(resolution) {
|
||||||
this.targetResolution_ = resolution;
|
this.set(ViewProperty.RESOLUTION, resolution);
|
||||||
this.applyTargetState_();
|
if (this.getAnimating()) {
|
||||||
|
this.cancelAnimations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the rotation for this view. Any rotation constraint will apply.
|
* Set the rotation for this view.
|
||||||
* @param {number} rotation The rotation of the view in radians.
|
* @param {number} rotation The rotation of the view in radians.
|
||||||
* @observable
|
* @observable
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setRotation(rotation) {
|
setRotation(rotation) {
|
||||||
this.targetRotation_ = rotation;
|
this.set(ViewProperty.ROTATION, rotation);
|
||||||
this.applyTargetState_();
|
if (this.getAnimating()) {
|
||||||
|
this.cancelAnimations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom to a specific zoom level. Any resolution constrain will apply.
|
* Zoom to a specific zoom level.
|
||||||
* @param {number} zoom Zoom level.
|
* @param {number} zoom Zoom level.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setZoom(zoom) {
|
setZoom(zoom) {
|
||||||
this.setResolution(this.getResolutionForZoom(zoom));
|
this.setResolution(this.getResolutionForZoom(zoom));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recompute rotation/resolution/center based on target values.
|
|
||||||
* Note: we have to compute rotation first, then resolution and center considering that
|
|
||||||
* parameters can influence one another in case a view extent constraint is present.
|
|
||||||
* @param {boolean=} opt_doNotCancelAnims Do not cancel animations.
|
|
||||||
* @param {boolean=} opt_forceMoving Apply constraints as if the view is moving.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
applyTargetState_(opt_doNotCancelAnims, opt_forceMoving) {
|
|
||||||
const isMoving = this.getAnimating() || this.getInteracting() || opt_forceMoving;
|
|
||||||
|
|
||||||
// compute rotation
|
|
||||||
const newRotation = this.constraints_.rotation(this.targetRotation_, isMoving);
|
|
||||||
const size = this.getSizeFromViewport_(newRotation);
|
|
||||||
const newResolution = this.constraints_.resolution(this.targetResolution_, 0, size, isMoving);
|
|
||||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size, isMoving);
|
|
||||||
|
|
||||||
if (this.get(ViewProperty.ROTATION) !== newRotation) {
|
|
||||||
this.set(ViewProperty.ROTATION, newRotation);
|
|
||||||
}
|
|
||||||
if (this.get(ViewProperty.RESOLUTION) !== newResolution) {
|
|
||||||
this.set(ViewProperty.RESOLUTION, newResolution);
|
|
||||||
}
|
|
||||||
if (!this.get(ViewProperty.CENTER) || !equals(this.get(ViewProperty.CENTER), newCenter)) {
|
|
||||||
this.set(ViewProperty.CENTER, newCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getAnimating() && !opt_doNotCancelAnims) {
|
|
||||||
this.cancelAnimations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If any constraints need to be applied, an animation will be triggered.
|
|
||||||
* This is typically done on interaction end.
|
|
||||||
* @param {number=} opt_duration The animation duration in ms.
|
|
||||||
* @param {number=} opt_resolutionDirection Which direction to zoom.
|
|
||||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
resolveConstraints_(opt_duration, opt_resolutionDirection, opt_anchor) {
|
|
||||||
const duration = opt_duration !== undefined ? opt_duration : 200;
|
|
||||||
const direction = opt_resolutionDirection || 0;
|
|
||||||
|
|
||||||
const newRotation = this.constraints_.rotation(this.targetRotation_);
|
|
||||||
const size = this.getSizeFromViewport_(newRotation);
|
|
||||||
const newResolution = this.constraints_.resolution(this.targetResolution_, direction, size);
|
|
||||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size);
|
|
||||||
|
|
||||||
if (this.getResolution() !== newResolution ||
|
|
||||||
this.getRotation() !== newRotation ||
|
|
||||||
!this.getCenter() ||
|
|
||||||
!equals(this.getCenter(), newCenter)) {
|
|
||||||
|
|
||||||
if (this.getAnimating()) {
|
|
||||||
this.cancelAnimations();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.animate({
|
|
||||||
rotation: newRotation,
|
|
||||||
center: newCenter,
|
|
||||||
resolution: newResolution,
|
|
||||||
duration: duration,
|
|
||||||
easing: easeOut,
|
|
||||||
anchor: opt_anchor
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the View that an interaction has started.
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
beginInteraction() {
|
|
||||||
this.setHint(ViewHint.INTERACTING, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the View that an interaction has ended. The view state will be resolved
|
|
||||||
* to a stable one if needed (depending on its constraints).
|
|
||||||
* @param {number=} opt_duration Animation duration in ms.
|
|
||||||
* @param {number=} opt_resolutionDirection Which direction to zoom.
|
|
||||||
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
endInteraction(opt_duration, opt_resolutionDirection, opt_anchor) {
|
|
||||||
this.setHint(ViewHint.INTERACTING, -1);
|
|
||||||
|
|
||||||
this.resolveConstraints_(opt_duration, opt_resolutionDirection, opt_anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a valid position for the view center according to the current constraints.
|
|
||||||
* @param {import("./coordinate.js").Coordinate|undefined} targetCenter Target center position.
|
|
||||||
* @param {number=} opt_targetResolution Target resolution. If not supplied, the current one will be used.
|
|
||||||
* This is useful to guess a valid center position at a different zoom level.
|
|
||||||
* @return {import("./coordinate.js").Coordinate|undefined} Valid center position.
|
|
||||||
*/
|
|
||||||
getConstrainedCenter(targetCenter, opt_targetResolution) {
|
|
||||||
const size = this.getSizeFromViewport_(this.getRotation());
|
|
||||||
return this.constraints_.center(targetCenter, opt_targetResolution || this.getResolution(), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a valid zoom level according to the current view constraints.
|
|
||||||
* @param {number|undefined} targetZoom Target zoom.
|
|
||||||
* @param {number=} opt_direction Direction. Default is `0`. Specify `-1` or `1` to return
|
|
||||||
* the available value respectively lower or greater than the target one. Leaving `0` will simply choose
|
|
||||||
* the nearest available value.
|
|
||||||
* @return {number|undefined} Valid zoom level.
|
|
||||||
*/
|
|
||||||
getConstrainedZoom(targetZoom, opt_direction) {
|
|
||||||
const targetRes = this.getResolutionForZoom(targetZoom);
|
|
||||||
return this.getZoomForResolution(this.getConstrainedResolution(targetRes));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a valid resolution according to the current view constraints.
|
|
||||||
* @param {number|undefined} targetResolution Target resolution.
|
|
||||||
* @param {number=} opt_direction Direction. Default is `0`. Specify `-1` or `1` to return
|
|
||||||
* the available value respectively lower or greater than the target one. Leaving `0` will simply choose
|
|
||||||
* the nearest available value.
|
|
||||||
* @return {number|undefined} Valid resolution.
|
|
||||||
*/
|
|
||||||
getConstrainedResolution(targetResolution, opt_direction) {
|
|
||||||
const direction = opt_direction || 0;
|
|
||||||
const size = this.getSizeFromViewport_(this.getRotation());
|
|
||||||
|
|
||||||
return this.constraints_.resolution(targetResolution, direction, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1398,8 +1195,7 @@ function animationCallback(callback, returnValue) {
|
|||||||
*/
|
*/
|
||||||
export function createCenterConstraint(options) {
|
export function createCenterConstraint(options) {
|
||||||
if (options.extent !== undefined) {
|
if (options.extent !== undefined) {
|
||||||
return createExtent(options.extent, options.constrainOnlyCenter,
|
return createExtent(options.extent);
|
||||||
options.smoothExtentConstraint !== undefined ? options.smoothExtentConstraint : true);
|
|
||||||
} else {
|
} else {
|
||||||
return centerNone;
|
return centerNone;
|
||||||
}
|
}
|
||||||
@@ -1430,22 +1226,13 @@ export function createResolutionConstraint(options) {
|
|||||||
const zoomFactor = options.zoomFactor !== undefined ?
|
const zoomFactor = options.zoomFactor !== undefined ?
|
||||||
options.zoomFactor : defaultZoomFactor;
|
options.zoomFactor : defaultZoomFactor;
|
||||||
|
|
||||||
const smooth =
|
|
||||||
options.smoothResolutionConstraint !== undefined ? options.smoothResolutionConstraint : true;
|
|
||||||
|
|
||||||
if (options.resolutions !== undefined) {
|
if (options.resolutions !== undefined) {
|
||||||
const resolutions = options.resolutions;
|
const resolutions = options.resolutions;
|
||||||
maxResolution = resolutions[minZoom];
|
maxResolution = resolutions[minZoom];
|
||||||
minResolution = resolutions[maxZoom] !== undefined ?
|
minResolution = resolutions[maxZoom] !== undefined ?
|
||||||
resolutions[maxZoom] : resolutions[resolutions.length - 1];
|
resolutions[maxZoom] : resolutions[resolutions.length - 1];
|
||||||
|
resolutionConstraint = createSnapToResolutions(
|
||||||
if (options.constrainResolution) {
|
resolutions);
|
||||||
resolutionConstraint = createSnapToResolutions(resolutions, smooth,
|
|
||||||
!options.constrainOnlyCenter && options.extent);
|
|
||||||
} else {
|
|
||||||
resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth,
|
|
||||||
!options.constrainOnlyCenter && options.extent);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// calculate the default min and max resolution
|
// calculate the default min and max resolution
|
||||||
const projection = createProjection(options.projection, 'EPSG:3857');
|
const projection = createProjection(options.projection, 'EPSG:3857');
|
||||||
@@ -1489,14 +1276,8 @@ export function createResolutionConstraint(options) {
|
|||||||
Math.log(maxResolution / minResolution) / Math.log(zoomFactor));
|
Math.log(maxResolution / minResolution) / Math.log(zoomFactor));
|
||||||
minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
|
minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
|
||||||
|
|
||||||
if (options.constrainResolution) {
|
|
||||||
resolutionConstraint = createSnapToPower(
|
resolutionConstraint = createSnapToPower(
|
||||||
zoomFactor, maxResolution, minResolution, smooth,
|
zoomFactor, maxResolution, maxZoom - minZoom);
|
||||||
!options.constrainOnlyCenter && options.extent);
|
|
||||||
} else {
|
|
||||||
resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth,
|
|
||||||
!options.constrainOnlyCenter && options.extent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {constraint: resolutionConstraint, maxResolution: maxResolution,
|
return {constraint: resolutionConstraint, maxResolution: maxResolution,
|
||||||
minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor};
|
minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor};
|
||||||
|
|||||||
@@ -5,57 +5,26 @@ import {clamp} from './math.js';
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {function((import("./coordinate.js").Coordinate|undefined), number, import("./size.js").Size, boolean=): (import("./coordinate.js").Coordinate|undefined)} Type
|
* @typedef {function((import("./coordinate.js").Coordinate|undefined)): (import("./coordinate.js").Coordinate|undefined)} Type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./extent.js").Extent} extent Extent.
|
* @param {import("./extent.js").Extent} extent Extent.
|
||||||
* @param {boolean} onlyCenter If true, the constraint will only apply to the view center.
|
|
||||||
* @param {boolean} smooth If true, the view will be able to go slightly out of the given extent
|
|
||||||
* (only during interaction and animation).
|
|
||||||
* @return {Type} The constraint.
|
* @return {Type} The constraint.
|
||||||
*/
|
*/
|
||||||
export function createExtent(extent, onlyCenter, smooth) {
|
export function createExtent(extent) {
|
||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {import("./coordinate.js").Coordinate|undefined} center Center.
|
* @param {import("./coordinate.js").Coordinate=} center Center.
|
||||||
* @param {number} resolution Resolution.
|
|
||||||
* @param {import("./size.js").Size} size Viewport size; unused if `onlyCenter` was specified.
|
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
|
||||||
* @return {import("./coordinate.js").Coordinate|undefined} Center.
|
* @return {import("./coordinate.js").Coordinate|undefined} Center.
|
||||||
*/
|
*/
|
||||||
function(center, resolution, size, opt_isMoving) {
|
function(center) {
|
||||||
if (center) {
|
if (center) {
|
||||||
const viewWidth = onlyCenter ? 0 : size[0] * resolution;
|
return [
|
||||||
const viewHeight = onlyCenter ? 0 : size[1] * resolution;
|
clamp(center[0], extent[0], extent[2]),
|
||||||
let minX = extent[0] + viewWidth / 2;
|
clamp(center[1], extent[1], extent[3])
|
||||||
let maxX = extent[2] - viewWidth / 2;
|
];
|
||||||
let minY = extent[1] + viewHeight / 2;
|
|
||||||
let maxY = extent[3] - viewHeight / 2;
|
|
||||||
|
|
||||||
// note: when zooming out of bounds, min and max values for x and y may
|
|
||||||
// end up inverted (min > max); this has to be accounted for
|
|
||||||
if (minX > maxX) {
|
|
||||||
minX = maxX = (maxX + minX) / 2;
|
|
||||||
}
|
|
||||||
if (minY > maxY) {
|
|
||||||
minY = maxY = (maxY + minY) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = clamp(center[0], minX, maxX);
|
|
||||||
let y = clamp(center[1], minY, maxY);
|
|
||||||
const ratio = 30 * resolution;
|
|
||||||
|
|
||||||
// during an interaction, allow some overscroll
|
|
||||||
if (opt_isMoving && smooth) {
|
|
||||||
x += -ratio * Math.log(1 + Math.max(0, minX - center[0]) / ratio) +
|
|
||||||
ratio * Math.log(1 + Math.max(0, center[0] - maxX) / ratio);
|
|
||||||
y += -ratio * Math.log(1 + Math.max(0, minY - center[1]) / ratio) +
|
|
||||||
ratio * Math.log(1 + Math.max(0, center[1] - maxY) / ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [x, y];
|
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,20 +114,20 @@ class Zoom extends Control {
|
|||||||
// upon it
|
// upon it
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const currentZoom = view.getZoom();
|
const currentResolution = view.getResolution();
|
||||||
if (currentZoom !== undefined) {
|
if (currentResolution) {
|
||||||
const newZoom = view.getConstrainedZoom(currentZoom + delta);
|
const newResolution = view.constrainResolution(currentResolution, delta);
|
||||||
if (this.duration_ > 0) {
|
if (this.duration_ > 0) {
|
||||||
if (view.getAnimating()) {
|
if (view.getAnimating()) {
|
||||||
view.cancelAnimations();
|
view.cancelAnimations();
|
||||||
}
|
}
|
||||||
view.animate({
|
view.animate({
|
||||||
zoom: newZoom,
|
resolution: newResolution,
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
view.setZoom(newZoom);
|
view.setResolution(newResolution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/control/ZoomSlider
|
* @module ol/control/ZoomSlider
|
||||||
*/
|
*/
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import Control from './Control.js';
|
import Control from './Control.js';
|
||||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
|
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
|
||||||
import {easeOut} from '../easing.js';
|
import {easeOut} from '../easing.js';
|
||||||
@@ -101,13 +102,13 @@ class ZoomSlider extends Control {
|
|||||||
* @type {number|undefined}
|
* @type {number|undefined}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.startX_;
|
this.previousX_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number|undefined}
|
* @type {number|undefined}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.startY_;
|
this.previousY_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The calculated thumb size (border box plus margins). Set when initSlider_
|
* The calculated thumb size (border box plus margins). Set when initSlider_
|
||||||
@@ -217,10 +218,9 @@ class ZoomSlider extends Control {
|
|||||||
event.offsetY - this.thumbSize_[1] / 2);
|
event.offsetY - this.thumbSize_[1] / 2);
|
||||||
|
|
||||||
const resolution = this.getResolutionForPosition_(relativePosition);
|
const resolution = this.getResolutionForPosition_(relativePosition);
|
||||||
const zoom = view.getConstrainedZoom(view.getZoomForResolution(resolution));
|
|
||||||
|
|
||||||
view.animate({
|
view.animate({
|
||||||
zoom: zoom,
|
resolution: view.constrainResolution(resolution),
|
||||||
duration: this.duration_,
|
duration: this.duration_,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
@@ -233,10 +233,9 @@ class ZoomSlider extends Control {
|
|||||||
*/
|
*/
|
||||||
handleDraggerStart_(event) {
|
handleDraggerStart_(event) {
|
||||||
if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
|
if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
|
||||||
const element = /** @type {HTMLElement} */ (this.element.firstElementChild);
|
this.getMap().getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
this.getMap().getView().beginInteraction();
|
this.previousX_ = event.clientX;
|
||||||
this.startX_ = event.clientX - parseFloat(element.style.left);
|
this.previousY_ = event.clientY;
|
||||||
this.startY_ = event.clientY - parseFloat(element.style.top);
|
|
||||||
this.dragging_ = true;
|
this.dragging_ = true;
|
||||||
|
|
||||||
if (this.dragListenerKeys_.length === 0) {
|
if (this.dragListenerKeys_.length === 0) {
|
||||||
@@ -260,11 +259,15 @@ class ZoomSlider extends Control {
|
|||||||
*/
|
*/
|
||||||
handleDraggerDrag_(event) {
|
handleDraggerDrag_(event) {
|
||||||
if (this.dragging_) {
|
if (this.dragging_) {
|
||||||
const deltaX = event.clientX - this.startX_;
|
const element = /** @type {HTMLElement} */ (this.element.firstElementChild);
|
||||||
const deltaY = event.clientY - this.startY_;
|
const deltaX = event.clientX - this.previousX_ + parseFloat(element.style.left);
|
||||||
|
const deltaY = event.clientY - this.previousY_ + parseFloat(element.style.top);
|
||||||
const relativePosition = this.getRelativePosition_(deltaX, deltaY);
|
const relativePosition = this.getRelativePosition_(deltaX, deltaY);
|
||||||
this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
|
this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
|
||||||
this.getMap().getView().setResolution(this.currentResolution_);
|
this.getMap().getView().setResolution(this.currentResolution_);
|
||||||
|
this.setThumbPosition_(this.currentResolution_);
|
||||||
|
this.previousX_ = event.clientX;
|
||||||
|
this.previousY_ = event.clientY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,11 +279,17 @@ class ZoomSlider extends Control {
|
|||||||
handleDraggerEnd_(event) {
|
handleDraggerEnd_(event) {
|
||||||
if (this.dragging_) {
|
if (this.dragging_) {
|
||||||
const view = this.getMap().getView();
|
const view = this.getMap().getView();
|
||||||
view.endInteraction();
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
|
|
||||||
|
view.animate({
|
||||||
|
resolution: view.constrainResolution(this.currentResolution_),
|
||||||
|
duration: this.duration_,
|
||||||
|
easing: easeOut
|
||||||
|
});
|
||||||
|
|
||||||
this.dragging_ = false;
|
this.dragging_ = false;
|
||||||
this.startX_ = undefined;
|
this.previousX_ = undefined;
|
||||||
this.startY_ = undefined;
|
this.previousY_ = undefined;
|
||||||
this.dragListenerKeys_.forEach(unlistenByKey);
|
this.dragListenerKeys_.forEach(unlistenByKey);
|
||||||
this.dragListenerKeys_.length = 0;
|
this.dragListenerKeys_.length = 0;
|
||||||
}
|
}
|
||||||
@@ -347,7 +356,7 @@ class ZoomSlider extends Control {
|
|||||||
*/
|
*/
|
||||||
getPositionForResolution_(res) {
|
getPositionForResolution_(res) {
|
||||||
const fn = this.getMap().getView().getValueForResolutionFunction();
|
const fn = this.getMap().getView().getValueForResolutionFunction();
|
||||||
return clamp(1 - fn(res), 0, 1);
|
return 1 - fn(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,8 +375,10 @@ export function render(mapEvent) {
|
|||||||
this.initSlider_();
|
this.initSlider_();
|
||||||
}
|
}
|
||||||
const res = mapEvent.frameState.viewState.resolution;
|
const res = mapEvent.frameState.viewState.resolution;
|
||||||
|
if (res !== this.currentResolution_) {
|
||||||
this.currentResolution_ = res;
|
this.currentResolution_ = res;
|
||||||
this.setThumbPosition_(res);
|
this.setThumbPosition_(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,11 +83,9 @@ export function loadFeaturesXhr(url, format, success, failure) {
|
|||||||
source = /** @type {ArrayBuffer} */ (xhr.response);
|
source = /** @type {ArrayBuffer} */ (xhr.response);
|
||||||
}
|
}
|
||||||
if (source) {
|
if (source) {
|
||||||
success.call(this, format.readFeatures(source, {
|
success.call(this, format.readFeatures(source,
|
||||||
extent: extent,
|
{featureProjection: projection}),
|
||||||
featureProjection: projection
|
format.readProjection(source), format.getLastExtent());
|
||||||
}),
|
|
||||||
format.readProjection(source));
|
|
||||||
} else {
|
} else {
|
||||||
failure.call(this);
|
failure.call(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,14 @@ class FeatureFormat {
|
|||||||
}, options);
|
}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the extent from the source of the last {@link readFeatures} call.
|
||||||
|
* @return {import("../extent.js").Extent} Tile extent.
|
||||||
|
*/
|
||||||
|
getLastExtent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
* @return {import("./FormatType.js").default} Format.
|
* @return {import("./FormatType.js").default} Format.
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {linearRingIsClockwise} from '../geom/flat/orient.js';
|
|||||||
import Projection from '../proj/Projection.js';
|
import Projection from '../proj/Projection.js';
|
||||||
import Units from '../proj/Units.js';
|
import Units from '../proj/Units.js';
|
||||||
import RenderFeature from '../render/Feature.js';
|
import RenderFeature from '../render/Feature.js';
|
||||||
import {get} from '../proj.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +83,12 @@ class MVT extends FeatureFormat {
|
|||||||
*/
|
*/
|
||||||
this.layers_ = options.layers ? options.layers : null;
|
this.layers_ = options.layers ? options.layers : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {import("../extent.js").Extent}
|
||||||
|
*/
|
||||||
|
this.extent_ = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,10 +159,10 @@ class MVT extends FeatureFormat {
|
|||||||
* @private
|
* @private
|
||||||
* @param {PBF} pbf PBF
|
* @param {PBF} pbf PBF
|
||||||
* @param {Object} rawFeature Raw Mapbox feature.
|
* @param {Object} rawFeature Raw Mapbox feature.
|
||||||
* @param {import("./Feature.js").ReadOptions} options Read options.
|
* @param {import("./Feature.js").ReadOptions=} opt_options Read options.
|
||||||
* @return {import("../Feature.js").FeatureLike} Feature.
|
* @return {import("../Feature.js").FeatureLike} Feature.
|
||||||
*/
|
*/
|
||||||
createFeature_(pbf, rawFeature, options) {
|
createFeature_(pbf, rawFeature, opt_options) {
|
||||||
const type = rawFeature.type;
|
const type = rawFeature.type;
|
||||||
if (type === 0) {
|
if (type === 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -176,7 +181,6 @@ class MVT extends FeatureFormat {
|
|||||||
|
|
||||||
if (this.featureClass_ === RenderFeature) {
|
if (this.featureClass_ === RenderFeature) {
|
||||||
feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
|
feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
|
||||||
feature.transform(options.dataProjection, options.featureProjection);
|
|
||||||
} else {
|
} else {
|
||||||
let geom;
|
let geom;
|
||||||
if (geometryType == GeometryType.POLYGON) {
|
if (geometryType == GeometryType.POLYGON) {
|
||||||
@@ -209,7 +213,7 @@ class MVT extends FeatureFormat {
|
|||||||
if (this.geometryName_) {
|
if (this.geometryName_) {
|
||||||
feature.setGeometryName(this.geometryName_);
|
feature.setGeometryName(this.geometryName_);
|
||||||
}
|
}
|
||||||
const geometry = transformGeometryWithOptions(geom, false, options);
|
const geometry = transformGeometryWithOptions(geom, false, this.adaptOptions(opt_options));
|
||||||
feature.setGeometry(geometry);
|
feature.setGeometry(geometry);
|
||||||
feature.setId(id);
|
feature.setId(id);
|
||||||
feature.setProperties(values, true);
|
feature.setProperties(values, true);
|
||||||
@@ -218,6 +222,14 @@ class MVT extends FeatureFormat {
|
|||||||
return feature;
|
return feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getLastExtent() {
|
||||||
|
return this.extent_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@@ -226,22 +238,15 @@ class MVT extends FeatureFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all features.
|
* @inheritDoc
|
||||||
*
|
|
||||||
* @param {ArrayBuffer} source Source.
|
|
||||||
* @param {import("./Feature.js").ReadOptions=} opt_options Read options.
|
|
||||||
* @return {Array<import("../Feature.js").FeatureLike>} Features.
|
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
readFeatures(source, opt_options) {
|
readFeatures(source, opt_options) {
|
||||||
const layers = this.layers_;
|
const layers = this.layers_;
|
||||||
const options = /** @type {import("./Feature.js").ReadOptions} */ (this.adaptOptions(opt_options));
|
|
||||||
const dataProjection = get(options.dataProjection);
|
|
||||||
dataProjection.setWorldExtent(options.extent);
|
|
||||||
options.dataProjection = dataProjection;
|
|
||||||
|
|
||||||
const pbf = new PBF(/** @type {ArrayBuffer} */ (source));
|
const pbf = new PBF(/** @type {ArrayBuffer} */ (source));
|
||||||
const pbfLayers = pbf.readFields(layersPBFReader, {});
|
const pbfLayers = pbf.readFields(layersPBFReader, {});
|
||||||
|
/** @type {Array<import("../Feature.js").FeatureLike>} */
|
||||||
const features = [];
|
const features = [];
|
||||||
for (const name in pbfLayers) {
|
for (const name in pbfLayers) {
|
||||||
if (layers && layers.indexOf(name) == -1) {
|
if (layers && layers.indexOf(name) == -1) {
|
||||||
@@ -249,13 +254,11 @@ class MVT extends FeatureFormat {
|
|||||||
}
|
}
|
||||||
const pbfLayer = pbfLayers[name];
|
const pbfLayer = pbfLayers[name];
|
||||||
|
|
||||||
const extent = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
|
||||||
dataProjection.setExtent(extent);
|
|
||||||
|
|
||||||
for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
|
for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
|
||||||
const rawFeature = readRawFeature(pbf, pbfLayer, i);
|
const rawFeature = readRawFeature(pbf, pbfLayer, i);
|
||||||
features.push(this.createFeature_(pbf, rawFeature, options));
|
features.push(this.createFeature_(pbf, rawFeature));
|
||||||
}
|
}
|
||||||
|
this.extent_ = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return features;
|
return features;
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ export {default as Translate} from './interaction/Translate.js';
|
|||||||
* focus. This affects the `MouseWheelZoom` and `DragPan` interactions and is
|
* focus. This affects the `MouseWheelZoom` and `DragPan` interactions and is
|
||||||
* useful when page scroll is desired for maps that do not have the browser's
|
* useful when page scroll is desired for maps that do not have the browser's
|
||||||
* focus.
|
* focus.
|
||||||
|
* @property {boolean} [constrainResolution=false] Zoom to the closest integer
|
||||||
|
* zoom level after the wheel/trackpad or pinch gesture ends.
|
||||||
* @property {boolean} [doubleClickZoom=true] Whether double click zoom is
|
* @property {boolean} [doubleClickZoom=true] Whether double click zoom is
|
||||||
* desired.
|
* desired.
|
||||||
* @property {boolean} [keyboard=true] Whether keyboard interaction is desired.
|
* @property {boolean} [keyboard=true] Whether keyboard interaction is desired.
|
||||||
@@ -125,6 +127,7 @@ export function defaults(opt_options) {
|
|||||||
const pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
|
const pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
|
||||||
if (pinchZoom) {
|
if (pinchZoom) {
|
||||||
interactions.push(new PinchZoom({
|
interactions.push(new PinchZoom({
|
||||||
|
constrainResolution: options.constrainResolution,
|
||||||
duration: options.zoomDuration
|
duration: options.zoomDuration
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -143,6 +146,7 @@ export function defaults(opt_options) {
|
|||||||
if (mouseWheelZoom) {
|
if (mouseWheelZoom) {
|
||||||
interactions.push(new MouseWheelZoom({
|
interactions.push(new MouseWheelZoom({
|
||||||
condition: options.onFocusOnly ? focus : undefined,
|
condition: options.onFocusOnly ? focus : undefined,
|
||||||
|
constrainResolution: options.constrainResolution,
|
||||||
duration: options.zoomDuration
|
duration: options.zoomDuration
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/interaction/DragPan
|
* @module ol/interaction/DragPan
|
||||||
*/
|
*/
|
||||||
import {scale as scaleCoordinate, rotate as rotateCoordinate} from '../coordinate.js';
|
import ViewHint from '../ViewHint.js';
|
||||||
|
import {scale as scaleCoordinate, rotate as rotateCoordinate, add as addCoordinate} from '../coordinate.js';
|
||||||
import {easeOut} from '../easing.js';
|
import {easeOut} from '../easing.js';
|
||||||
import {noModifierKeys} from '../events/condition.js';
|
import {noModifierKeys} from '../events/condition.js';
|
||||||
import {FALSE} from '../functions.js';
|
import {FALSE} from '../functions.js';
|
||||||
@@ -73,6 +74,10 @@ class DragPan extends PointerInteraction {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
handleDragEvent(mapBrowserEvent) {
|
handleDragEvent(mapBrowserEvent) {
|
||||||
|
if (!this.panning_) {
|
||||||
|
this.panning_ = true;
|
||||||
|
this.getMap().getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
|
}
|
||||||
const targetPointers = this.targetPointers;
|
const targetPointers = this.targetPointers;
|
||||||
const centroid = centroidFromPointers(targetPointers);
|
const centroid = centroidFromPointers(targetPointers);
|
||||||
if (targetPointers.length == this.lastPointersCount_) {
|
if (targetPointers.length == this.lastPointersCount_) {
|
||||||
@@ -80,15 +85,16 @@ class DragPan extends PointerInteraction {
|
|||||||
this.kinetic_.update(centroid[0], centroid[1]);
|
this.kinetic_.update(centroid[0], centroid[1]);
|
||||||
}
|
}
|
||||||
if (this.lastCentroid) {
|
if (this.lastCentroid) {
|
||||||
const delta = [
|
const deltaX = this.lastCentroid[0] - centroid[0];
|
||||||
this.lastCentroid[0] - centroid[0],
|
const deltaY = centroid[1] - this.lastCentroid[1];
|
||||||
centroid[1] - this.lastCentroid[1]
|
|
||||||
];
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
scaleCoordinate(delta, view.getResolution());
|
let center = [deltaX, deltaY];
|
||||||
rotateCoordinate(delta, view.getRotation());
|
scaleCoordinate(center, view.getResolution());
|
||||||
view.adjustCenter(delta);
|
rotateCoordinate(center, view.getRotation());
|
||||||
|
addCoordinate(center, view.getCenter());
|
||||||
|
center = view.constrainCenter(center);
|
||||||
|
view.setCenter(center);
|
||||||
}
|
}
|
||||||
} else if (this.kinetic_) {
|
} else if (this.kinetic_) {
|
||||||
// reset so we don't overestimate the kinetic energy after
|
// reset so we don't overestimate the kinetic energy after
|
||||||
@@ -116,14 +122,14 @@ class DragPan extends PointerInteraction {
|
|||||||
centerpx[1] - distance * Math.sin(angle)
|
centerpx[1] - distance * Math.sin(angle)
|
||||||
]);
|
]);
|
||||||
view.animate({
|
view.animate({
|
||||||
center: view.getConstrainedCenter(dest),
|
center: view.constrainCenter(dest),
|
||||||
duration: 500,
|
duration: 500,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.panning_) {
|
if (this.panning_) {
|
||||||
this.panning_ = false;
|
this.panning_ = false;
|
||||||
view.endInteraction();
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@@ -147,11 +153,7 @@ class DragPan extends PointerInteraction {
|
|||||||
this.lastCentroid = null;
|
this.lastCentroid = null;
|
||||||
// stop any current animation
|
// stop any current animation
|
||||||
if (view.getAnimating()) {
|
if (view.getAnimating()) {
|
||||||
view.cancelAnimations();
|
view.setCenter(mapBrowserEvent.frameState.viewState.center);
|
||||||
}
|
|
||||||
if (!this.panning_) {
|
|
||||||
this.panning_ = true;
|
|
||||||
this.getMap().getView().beginInteraction();
|
|
||||||
}
|
}
|
||||||
if (this.kinetic_) {
|
if (this.kinetic_) {
|
||||||
this.kinetic_.begin();
|
this.kinetic_.begin();
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
* @module ol/interaction/DragRotate
|
* @module ol/interaction/DragRotate
|
||||||
*/
|
*/
|
||||||
import {disable} from '../rotationconstraint.js';
|
import {disable} from '../rotationconstraint.js';
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import {altShiftKeysOnly, mouseOnly, mouseActionButton} from '../events/condition.js';
|
import {altShiftKeysOnly, mouseOnly, mouseActionButton} from '../events/condition.js';
|
||||||
import {FALSE} from '../functions.js';
|
import {FALSE} from '../functions.js';
|
||||||
|
import {rotate, rotateWithoutConstraints} from './Interaction.js';
|
||||||
import PointerInteraction from './Pointer.js';
|
import PointerInteraction from './Pointer.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +80,8 @@ class DragRotate extends PointerInteraction {
|
|||||||
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
|
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
|
||||||
if (this.lastAngle_ !== undefined) {
|
if (this.lastAngle_ !== undefined) {
|
||||||
const delta = theta - this.lastAngle_;
|
const delta = theta - this.lastAngle_;
|
||||||
view.adjustRotation(-delta);
|
const rotation = view.getRotation();
|
||||||
|
rotateWithoutConstraints(view, rotation - delta);
|
||||||
}
|
}
|
||||||
this.lastAngle_ = theta;
|
this.lastAngle_ = theta;
|
||||||
}
|
}
|
||||||
@@ -94,7 +97,9 @@ class DragRotate extends PointerInteraction {
|
|||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction(this.duration_);
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
|
const rotation = view.getRotation();
|
||||||
|
rotate(view, rotation, undefined, this.duration_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +114,7 @@ class DragRotate extends PointerInteraction {
|
|||||||
|
|
||||||
if (mouseActionButton(mapBrowserEvent) && this.condition_(mapBrowserEvent)) {
|
if (mouseActionButton(mapBrowserEvent) && this.condition_(mapBrowserEvent)) {
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
map.getView().beginInteraction();
|
map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
this.lastAngle_ = undefined;
|
this.lastAngle_ = undefined;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/interaction/DragRotateAndZoom
|
* @module ol/interaction/DragRotateAndZoom
|
||||||
*/
|
*/
|
||||||
|
import {disable} from '../rotationconstraint.js';
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import {shiftKeyOnly, mouseOnly} from '../events/condition.js';
|
import {shiftKeyOnly, mouseOnly} from '../events/condition.js';
|
||||||
|
import {rotate, rotateWithoutConstraints, zoom, zoomWithoutConstraints} from './Interaction.js';
|
||||||
import PointerInteraction from './Pointer.js';
|
import PointerInteraction from './Pointer.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -85,13 +88,14 @@ class DragRotateAndZoom extends PointerInteraction {
|
|||||||
const theta = Math.atan2(deltaY, deltaX);
|
const theta = Math.atan2(deltaY, deltaX);
|
||||||
const magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
const magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
if (this.lastAngle_ !== undefined) {
|
if (view.getConstraints().rotation !== disable && this.lastAngle_ !== undefined) {
|
||||||
const angleDelta = this.lastAngle_ - theta;
|
const angleDelta = theta - this.lastAngle_;
|
||||||
view.adjustRotation(angleDelta);
|
rotateWithoutConstraints(view, view.getRotation() - angleDelta);
|
||||||
}
|
}
|
||||||
this.lastAngle_ = theta;
|
this.lastAngle_ = theta;
|
||||||
if (this.lastMagnitude_ !== undefined) {
|
if (this.lastMagnitude_ !== undefined) {
|
||||||
view.adjustResolution(this.lastMagnitude_ / magnitude);
|
const resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);
|
||||||
|
zoomWithoutConstraints(view, resolution);
|
||||||
}
|
}
|
||||||
if (this.lastMagnitude_ !== undefined) {
|
if (this.lastMagnitude_ !== undefined) {
|
||||||
this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
|
this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
|
||||||
@@ -109,8 +113,10 @@ class DragRotateAndZoom extends PointerInteraction {
|
|||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
view.endInteraction(this.duration_, direction);
|
const direction = this.lastScaleDelta_ - 1;
|
||||||
|
rotate(view, view.getRotation());
|
||||||
|
zoom(view, view.getResolution(), undefined, this.duration_, direction);
|
||||||
this.lastScaleDelta_ = 0;
|
this.lastScaleDelta_ = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -124,7 +130,7 @@ class DragRotateAndZoom extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.condition_(mapBrowserEvent)) {
|
if (this.condition_(mapBrowserEvent)) {
|
||||||
mapBrowserEvent.map.getView().beginInteraction();
|
mapBrowserEvent.map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
this.lastAngle_ = undefined;
|
this.lastAngle_ = undefined;
|
||||||
this.lastMagnitude_ = undefined;
|
this.lastMagnitude_ = undefined;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -80,8 +80,11 @@ function onBoxEnd() {
|
|||||||
extent = mapExtent;
|
extent = mapExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolution = view.getConstrainedResolution(view.getResolutionForExtent(extent, size));
|
const resolution = view.constrainResolution(
|
||||||
const center = view.getConstrainedCenter(getCenter(extent), resolution);
|
view.getResolutionForExtent(extent, size));
|
||||||
|
|
||||||
|
let center = getCenter(extent);
|
||||||
|
center = view.constrainCenter(center);
|
||||||
|
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: resolution,
|
resolution: resolution,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import BaseObject from '../Object.js';
|
import BaseObject from '../Object.js';
|
||||||
import {easeOut, linear} from '../easing.js';
|
import {easeOut, linear} from '../easing.js';
|
||||||
import InteractionProperty from './Property.js';
|
import InteractionProperty from './Property.js';
|
||||||
|
import {clamp} from '../math.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,15 +111,77 @@ class Interaction extends BaseObject {
|
|||||||
export function pan(view, delta, opt_duration) {
|
export function pan(view, delta, opt_duration) {
|
||||||
const currentCenter = view.getCenter();
|
const currentCenter = view.getCenter();
|
||||||
if (currentCenter) {
|
if (currentCenter) {
|
||||||
const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
|
const center = view.constrainCenter(
|
||||||
|
[currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);
|
||||||
|
if (opt_duration) {
|
||||||
view.animate({
|
view.animate({
|
||||||
duration: opt_duration !== undefined ? opt_duration : 250,
|
duration: opt_duration,
|
||||||
easing: linear,
|
easing: linear,
|
||||||
center: view.getConstrainedCenter(center)
|
center: center
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
view.setCenter(center);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../View.js").default} view View.
|
||||||
|
* @param {number|undefined} rotation Rotation.
|
||||||
|
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||||
|
* @param {number=} opt_duration Duration.
|
||||||
|
*/
|
||||||
|
export function rotate(view, rotation, opt_anchor, opt_duration) {
|
||||||
|
rotation = view.constrainRotation(rotation, 0);
|
||||||
|
rotateWithoutConstraints(view, rotation, opt_anchor, opt_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../View.js").default} view View.
|
||||||
|
* @param {number|undefined} rotation Rotation.
|
||||||
|
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||||
|
* @param {number=} opt_duration Duration.
|
||||||
|
*/
|
||||||
|
export function rotateWithoutConstraints(view, rotation, opt_anchor, opt_duration) {
|
||||||
|
if (rotation !== undefined) {
|
||||||
|
const currentRotation = view.getRotation();
|
||||||
|
const currentCenter = view.getCenter();
|
||||||
|
if (currentRotation !== undefined && currentCenter && opt_duration > 0) {
|
||||||
|
view.animate({
|
||||||
|
rotation: rotation,
|
||||||
|
anchor: opt_anchor,
|
||||||
|
duration: opt_duration,
|
||||||
|
easing: easeOut
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
view.rotate(rotation, opt_anchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../View.js").default} view View.
|
||||||
|
* @param {number|undefined} resolution Resolution to go to.
|
||||||
|
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||||
|
* @param {number=} opt_duration Duration.
|
||||||
|
* @param {number=} opt_direction Zooming direction; > 0 indicates
|
||||||
|
* zooming out, in which case the constraints system will select
|
||||||
|
* the largest nearest resolution; < 0 indicates zooming in, in
|
||||||
|
* which case the constraints system will select the smallest
|
||||||
|
* nearest resolution; == 0 indicates that the zooming direction
|
||||||
|
* is unknown/not relevant, in which case the constraints system
|
||||||
|
* will select the nearest resolution. If not defined 0 is
|
||||||
|
* assumed.
|
||||||
|
*/
|
||||||
|
export function zoom(view, resolution, opt_anchor, opt_duration, opt_direction) {
|
||||||
|
resolution = view.constrainResolution(resolution, 0, opt_direction);
|
||||||
|
zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../View.js").default} view View.
|
* @param {import("../View.js").default} view View.
|
||||||
* @param {number} delta Delta from previous zoom level.
|
* @param {number} delta Delta from previous zoom level.
|
||||||
@@ -126,24 +189,63 @@ export function pan(view, delta, opt_duration) {
|
|||||||
* @param {number=} opt_duration Duration.
|
* @param {number=} opt_duration Duration.
|
||||||
*/
|
*/
|
||||||
export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
|
export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
|
||||||
const currentZoom = view.getZoom();
|
const currentResolution = view.getResolution();
|
||||||
|
let resolution = view.constrainResolution(currentResolution, delta, 0);
|
||||||
|
|
||||||
if (currentZoom === undefined) {
|
if (resolution !== undefined) {
|
||||||
return;
|
const resolutions = view.getResolutions();
|
||||||
|
resolution = clamp(
|
||||||
|
resolution,
|
||||||
|
view.getMinResolution() || resolutions[resolutions.length - 1],
|
||||||
|
view.getMaxResolution() || resolutions[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newZoom = view.getConstrainedZoom(currentZoom + delta);
|
// If we have a constraint on center, we need to change the anchor so that the
|
||||||
const newResolution = view.getResolutionForZoom(newZoom);
|
// new center is within the extent. We first calculate the new center, apply
|
||||||
|
// the constraint to it, and then calculate back the anchor
|
||||||
|
if (opt_anchor && resolution !== undefined && resolution !== currentResolution) {
|
||||||
|
const currentCenter = view.getCenter();
|
||||||
|
let center = view.calculateCenterZoom(resolution, opt_anchor);
|
||||||
|
center = view.constrainCenter(center);
|
||||||
|
|
||||||
if (view.getAnimating()) {
|
opt_anchor = [
|
||||||
view.cancelAnimations();
|
(resolution * currentCenter[0] - currentResolution * center[0]) /
|
||||||
|
(resolution - currentResolution),
|
||||||
|
(resolution * currentCenter[1] - currentResolution * center[1]) /
|
||||||
|
(resolution - currentResolution)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../View.js").default} view View.
|
||||||
|
* @param {number|undefined} resolution Resolution to go to.
|
||||||
|
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
|
||||||
|
* @param {number=} opt_duration Duration.
|
||||||
|
*/
|
||||||
|
export function zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration) {
|
||||||
|
if (resolution) {
|
||||||
|
const currentResolution = view.getResolution();
|
||||||
|
const currentCenter = view.getCenter();
|
||||||
|
if (currentResolution !== undefined && currentCenter &&
|
||||||
|
resolution !== currentResolution && opt_duration) {
|
||||||
view.animate({
|
view.animate({
|
||||||
resolution: newResolution,
|
resolution: resolution,
|
||||||
anchor: opt_anchor,
|
anchor: opt_anchor,
|
||||||
duration: opt_duration !== undefined ? opt_duration : 250,
|
duration: opt_duration,
|
||||||
easing: easeOut
|
easing: easeOut
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (opt_anchor) {
|
||||||
|
const center = view.calculateCenterZoom(resolution, opt_anchor);
|
||||||
|
view.setCenter(center);
|
||||||
|
}
|
||||||
|
view.setResolution(resolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Interaction;
|
export default Interaction;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/interaction/MouseWheelZoom
|
* @module ol/interaction/MouseWheelZoom
|
||||||
*/
|
*/
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import {always} from '../events/condition.js';
|
import {always} from '../events/condition.js';
|
||||||
|
import {easeOut} from '../easing.js';
|
||||||
import EventType from '../events/EventType.js';
|
import EventType from '../events/EventType.js';
|
||||||
import {DEVICE_PIXEL_RATIO, FIREFOX, SAFARI} from '../has.js';
|
import {DEVICE_PIXEL_RATIO, FIREFOX, SAFARI} from '../has.js';
|
||||||
import Interaction, {zoomByDelta} from './Interaction.js';
|
import Interaction, {zoomByDelta} from './Interaction.js';
|
||||||
@@ -32,6 +34,9 @@ export const Mode = {
|
|||||||
* {@link module:ol/events/condition~always}.
|
* {@link module:ol/events/condition~always}.
|
||||||
* @property {number} [duration=250] Animation duration in milliseconds.
|
* @property {number} [duration=250] Animation duration in milliseconds.
|
||||||
* @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds.
|
* @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds.
|
||||||
|
* @property {boolean} [constrainResolution=false] When using a trackpad or
|
||||||
|
* magic mouse, zoom to the closest integer zoom level after the scroll gesture
|
||||||
|
* ends.
|
||||||
* @property {boolean} [useAnchor=true] Enable zooming using the mouse's
|
* @property {boolean} [useAnchor=true] Enable zooming using the mouse's
|
||||||
* location as the anchor. When set to `false`, zooming in and out will zoom to
|
* location as the anchor. When set to `false`, zooming in and out will zoom to
|
||||||
* the center of the screen instead of zooming on the mouse's location.
|
* the center of the screen instead of zooming on the mouse's location.
|
||||||
@@ -57,13 +62,7 @@ class MouseWheelZoom extends Interaction {
|
|||||||
* @private
|
* @private
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.totalDelta_ = 0;
|
this.delta_ = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.lastDelta_ = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -83,6 +82,12 @@ class MouseWheelZoom extends Interaction {
|
|||||||
*/
|
*/
|
||||||
this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true;
|
this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.constrainResolution_ = options.constrainResolution || false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("../events/condition.js").Condition}
|
* @type {import("../events/condition.js").Condition}
|
||||||
@@ -132,15 +137,22 @@ class MouseWheelZoom extends Interaction {
|
|||||||
*/
|
*/
|
||||||
this.trackpadDeltaPerZoom_ = 300;
|
this.trackpadDeltaPerZoom_ = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The zoom factor by which scroll zooming is allowed to exceed the limits.
|
||||||
|
* @private
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.trackpadZoomBuffer_ = 1.5;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
endInteraction_() {
|
decrementInteractingHint_() {
|
||||||
this.trackpadTimeoutId_ = undefined;
|
this.trackpadTimeoutId_ = undefined;
|
||||||
const view = this.getMap().getView();
|
const view = this.getMap().getView();
|
||||||
view.endInteraction(undefined, Math.sign(this.lastDelta_), this.lastAnchor_);
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -187,8 +199,6 @@ class MouseWheelZoom extends Interaction {
|
|||||||
|
|
||||||
if (delta === 0) {
|
if (delta === 0) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
this.lastDelta_ = delta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -208,15 +218,55 @@ class MouseWheelZoom extends Interaction {
|
|||||||
if (this.trackpadTimeoutId_) {
|
if (this.trackpadTimeoutId_) {
|
||||||
clearTimeout(this.trackpadTimeoutId_);
|
clearTimeout(this.trackpadTimeoutId_);
|
||||||
} else {
|
} else {
|
||||||
view.beginInteraction();
|
view.setHint(ViewHint.INTERACTING, 1);
|
||||||
|
}
|
||||||
|
this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);
|
||||||
|
let resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
|
||||||
|
const minResolution = view.getMinResolution();
|
||||||
|
const maxResolution = view.getMaxResolution();
|
||||||
|
let rebound = 0;
|
||||||
|
if (resolution < minResolution) {
|
||||||
|
resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
|
||||||
|
rebound = 1;
|
||||||
|
} else if (resolution > maxResolution) {
|
||||||
|
resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
|
||||||
|
rebound = -1;
|
||||||
|
}
|
||||||
|
if (this.lastAnchor_) {
|
||||||
|
const center = view.calculateCenterZoom(resolution, this.lastAnchor_);
|
||||||
|
view.setCenter(view.constrainCenter(center));
|
||||||
|
}
|
||||||
|
view.setResolution(resolution);
|
||||||
|
|
||||||
|
if (rebound === 0 && this.constrainResolution_) {
|
||||||
|
view.animate({
|
||||||
|
resolution: view.constrainResolution(resolution, delta > 0 ? -1 : 1),
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: this.duration_
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rebound > 0) {
|
||||||
|
view.animate({
|
||||||
|
resolution: minResolution,
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
} else if (rebound < 0) {
|
||||||
|
view.animate({
|
||||||
|
resolution: maxResolution,
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.trackpadTimeoutId_ = setTimeout(this.endInteraction_.bind(this), this.trackpadEventGap_);
|
|
||||||
view.adjustZoom(-delta / this.trackpadDeltaPerZoom_, this.lastAnchor_);
|
|
||||||
this.startTime_ = now;
|
this.startTime_ = now;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.totalDelta_ += delta;
|
this.delta_ += delta;
|
||||||
|
|
||||||
const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
|
const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
|
||||||
|
|
||||||
@@ -236,10 +286,10 @@ class MouseWheelZoom extends Interaction {
|
|||||||
view.cancelAnimations();
|
view.cancelAnimations();
|
||||||
}
|
}
|
||||||
const maxDelta = MAX_DELTA;
|
const maxDelta = MAX_DELTA;
|
||||||
const delta = clamp(this.totalDelta_, -maxDelta, maxDelta);
|
const delta = clamp(this.delta_, -maxDelta, maxDelta);
|
||||||
zoomByDelta(view, -delta, this.lastAnchor_, this.duration_);
|
zoomByDelta(view, -delta, this.lastAnchor_, this.duration_);
|
||||||
this.mode_ = undefined;
|
this.mode_ = undefined;
|
||||||
this.totalDelta_ = 0;
|
this.delta_ = 0;
|
||||||
this.lastAnchor_ = null;
|
this.lastAnchor_ = null;
|
||||||
this.startTime_ = undefined;
|
this.startTime_ = undefined;
|
||||||
this.timeoutId_ = undefined;
|
this.timeoutId_ = undefined;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/interaction/PinchRotate
|
* @module ol/interaction/PinchRotate
|
||||||
*/
|
*/
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import {FALSE} from '../functions.js';
|
import {FALSE} from '../functions.js';
|
||||||
|
import {rotate, rotateWithoutConstraints} from './Interaction.js';
|
||||||
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
||||||
import {disable} from '../rotationconstraint.js';
|
import {disable} from '../rotationconstraint.js';
|
||||||
|
|
||||||
@@ -116,8 +118,9 @@ class PinchRotate extends PointerInteraction {
|
|||||||
|
|
||||||
// rotate
|
// rotate
|
||||||
if (this.rotating_) {
|
if (this.rotating_) {
|
||||||
|
const rotation = view.getRotation();
|
||||||
map.render();
|
map.render();
|
||||||
view.adjustRotation(rotationDelta, this.anchor_);
|
rotateWithoutConstraints(view, rotation + rotationDelta, this.anchor_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +131,11 @@ class PinchRotate extends PointerInteraction {
|
|||||||
if (this.targetPointers.length < 2) {
|
if (this.targetPointers.length < 2) {
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.endInteraction(this.duration_);
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
|
if (this.rotating_) {
|
||||||
|
const rotation = view.getRotation();
|
||||||
|
rotate(view, rotation, this.anchor_, this.duration_);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@@ -146,7 +153,7 @@ class PinchRotate extends PointerInteraction {
|
|||||||
this.rotating_ = false;
|
this.rotating_ = false;
|
||||||
this.rotationDelta_ = 0.0;
|
this.rotationDelta_ = 0.0;
|
||||||
if (!this.handlingDownUpSequence) {
|
if (!this.handlingDownUpSequence) {
|
||||||
map.getView().beginInteraction();
|
map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/interaction/PinchZoom
|
* @module ol/interaction/PinchZoom
|
||||||
*/
|
*/
|
||||||
|
import ViewHint from '../ViewHint.js';
|
||||||
import {FALSE} from '../functions.js';
|
import {FALSE} from '../functions.js';
|
||||||
|
import {zoom, zoomWithoutConstraints} from './Interaction.js';
|
||||||
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {number} [duration=400] Animation duration in milliseconds.
|
* @property {number} [duration=400] Animation duration in milliseconds.
|
||||||
|
* @property {boolean} [constrainResolution=false] Zoom to the closest integer
|
||||||
|
* zoom level after the pinch gesture ends.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +37,12 @@ class PinchZoom extends PointerInteraction {
|
|||||||
|
|
||||||
super(pointerOptions);
|
super(pointerOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.constrainResolution_ = options.constrainResolution || false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("../coordinate.js").Coordinate}
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
@@ -81,6 +91,17 @@ class PinchZoom extends PointerInteraction {
|
|||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
|
const resolution = view.getResolution();
|
||||||
|
const maxResolution = view.getMaxResolution();
|
||||||
|
const minResolution = view.getMinResolution();
|
||||||
|
let newResolution = resolution * scaleDelta;
|
||||||
|
if (newResolution > maxResolution) {
|
||||||
|
scaleDelta = maxResolution / resolution;
|
||||||
|
newResolution = maxResolution;
|
||||||
|
} else if (newResolution < minResolution) {
|
||||||
|
scaleDelta = minResolution / resolution;
|
||||||
|
newResolution = minResolution;
|
||||||
|
}
|
||||||
|
|
||||||
if (scaleDelta != 1.0) {
|
if (scaleDelta != 1.0) {
|
||||||
this.lastScaleDelta_ = scaleDelta;
|
this.lastScaleDelta_ = scaleDelta;
|
||||||
@@ -95,7 +116,7 @@ class PinchZoom extends PointerInteraction {
|
|||||||
|
|
||||||
// scale, bypass the resolution constraint
|
// scale, bypass the resolution constraint
|
||||||
map.render();
|
map.render();
|
||||||
view.adjustResolution(scaleDelta, this.anchor_);
|
zoomWithoutConstraints(view, newResolution, this.anchor_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,8 +126,17 @@ class PinchZoom extends PointerInteraction {
|
|||||||
if (this.targetPointers.length < 2) {
|
if (this.targetPointers.length < 2) {
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
view.endInteraction(this.duration_, direction);
|
const resolution = view.getResolution();
|
||||||
|
if (this.constrainResolution_ ||
|
||||||
|
resolution < view.getMinResolution() ||
|
||||||
|
resolution > view.getMaxResolution()) {
|
||||||
|
// Zoom to final resolution, with an animation, and provide a
|
||||||
|
// direction not to zoom out/in if user was pinching in/out.
|
||||||
|
// Direction is > 0 if pinching out, and < 0 if pinching in.
|
||||||
|
const direction = this.lastScaleDelta_ - 1;
|
||||||
|
zoom(view, resolution, this.anchor_, this.duration_, direction);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@@ -123,7 +153,7 @@ class PinchZoom extends PointerInteraction {
|
|||||||
this.lastDistance_ = undefined;
|
this.lastDistance_ = undefined;
|
||||||
this.lastScaleDelta_ = 1;
|
this.lastScaleDelta_ = 1;
|
||||||
if (!this.handlingDownUpSequence) {
|
if (!this.handlingDownUpSequence) {
|
||||||
map.getView().beginInteraction();
|
map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -288,22 +288,22 @@ function getMeasureContext() {
|
|||||||
* @return {import("../size.js").Size} Measurement.
|
* @return {import("../size.js").Size} Measurement.
|
||||||
*/
|
*/
|
||||||
export const measureTextHeight = (function() {
|
export const measureTextHeight = (function() {
|
||||||
let div;
|
let span;
|
||||||
const heights = textHeights;
|
const heights = textHeights;
|
||||||
return function(font) {
|
return function(font) {
|
||||||
let height = heights[font];
|
let height = heights[font];
|
||||||
if (height == undefined) {
|
if (height == undefined) {
|
||||||
if (!div) {
|
if (!span) {
|
||||||
div = document.createElement('div');
|
span = document.createElement('span');
|
||||||
div.innerHTML = 'M';
|
span.textContent = 'M';
|
||||||
div.style.margin = div.style.padding = '0 !important';
|
span.style.margin = span.style.padding = '0 !important';
|
||||||
div.style.position = 'absolute !important';
|
span.style.position = 'absolute !important';
|
||||||
div.style.left = '-99999px !important';
|
span.style.left = '-99999px !important';
|
||||||
}
|
}
|
||||||
div.style.font = font;
|
span.style.font = font;
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(span);
|
||||||
height = heights[font] = div.offsetHeight;
|
height = heights[font] = span.offsetHeight;
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(span);
|
||||||
}
|
}
|
||||||
return height;
|
return height;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -143,8 +143,6 @@ class ExecutorGroup extends Disposable {
|
|||||||
executors[key].disposeInternal();
|
executors[key].disposeInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const canvas = this.hitDetectionContext_.canvas;
|
|
||||||
canvas.width = canvas.height = 0;
|
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,14 +63,6 @@ class CanvasLayerRenderer extends LayerRenderer {
|
|||||||
canvas.className = this.getLayer().getClassName();
|
canvas.className = this.getLayer().getClassName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
disposeInternal() {
|
|
||||||
this.context.canvas.width = this.context.canvas.height = 0;
|
|
||||||
super.disposeInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {CanvasRenderingContext2D} context Context.
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import EventType from '../../events/EventType.js';
|
|||||||
import rbush from 'rbush';
|
import rbush from 'rbush';
|
||||||
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
|
||||||
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
|
||||||
|
import {equivalent as equivalentProjection} from '../../proj.js';
|
||||||
|
import Units from '../../proj/Units.js';
|
||||||
import ReplayType from '../../render/canvas/BuilderType.js';
|
import ReplayType from '../../render/canvas/BuilderType.js';
|
||||||
import {labelCache} from '../../render/canvas.js';
|
import {labelCache} from '../../render/canvas.js';
|
||||||
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
|
||||||
@@ -150,7 +152,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
*/
|
*/
|
||||||
disposeInternal() {
|
disposeInternal() {
|
||||||
unlisten(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
unlisten(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||||
this.overlayContext_.canvas.width = this.overlayContext_.canvas.height = 0;
|
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +263,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
const sharedExtent = getIntersection(tileExtent, sourceTileExtent);
|
const sharedExtent = getIntersection(tileExtent, sourceTileExtent);
|
||||||
const bufferedExtent = equals(sourceTileExtent, sharedExtent) ? null :
|
const bufferedExtent = equals(sourceTileExtent, sharedExtent) ? null :
|
||||||
buffer(sharedExtent, layer.getRenderBuffer() * resolution, this.tmpExtent);
|
buffer(sharedExtent, layer.getRenderBuffer() * resolution, this.tmpExtent);
|
||||||
|
const tileProjection = sourceTile.getProjection();
|
||||||
|
let reproject = false;
|
||||||
|
if (!equivalentProjection(projection, tileProjection)) {
|
||||||
|
reproject = true;
|
||||||
|
sourceTile.setProjection(projection);
|
||||||
|
}
|
||||||
builderState.dirty = false;
|
builderState.dirty = false;
|
||||||
const builderGroup = new CanvasBuilderGroup(0, sharedExtent, resolution,
|
const builderGroup = new CanvasBuilderGroup(0, sharedExtent, resolution,
|
||||||
pixelRatio, !!this.declutterTree_);
|
pixelRatio, !!this.declutterTree_);
|
||||||
@@ -290,6 +297,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
|||||||
}
|
}
|
||||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||||
const feature = features[i];
|
const feature = features[i];
|
||||||
|
if (reproject) {
|
||||||
|
if (tileProjection.getUnits() == Units.TILE_PIXELS) {
|
||||||
|
// projected tile extent
|
||||||
|
tileProjection.setWorldExtent(sourceTileExtent);
|
||||||
|
// tile extent in tile pixel space
|
||||||
|
tileProjection.setExtent(sourceTile.getExtent());
|
||||||
|
}
|
||||||
|
feature.getGeometry().transform(tileProjection, projection);
|
||||||
|
}
|
||||||
if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) {
|
if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) {
|
||||||
render.call(this, feature);
|
render.call(this, feature);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,87 +2,37 @@
|
|||||||
* @module ol/resolutionconstraint
|
* @module ol/resolutionconstraint
|
||||||
*/
|
*/
|
||||||
import {linearFindNearest} from './array.js';
|
import {linearFindNearest} from './array.js';
|
||||||
import {getHeight, getWidth} from './extent';
|
import {clamp} from './math.js';
|
||||||
import {clamp} from './math';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {function((number|undefined), number, import("./size.js").Size, boolean=): (number|undefined)} Type
|
* @typedef {function((number|undefined), number, number): (number|undefined)} Type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a modified resolution taking into acocunt the viewport size and maximum
|
|
||||||
* allowed extent.
|
|
||||||
* @param {number} resolution Resolution
|
|
||||||
* @param {import("./extent.js").Extent=} maxExtent Maximum allowed extent.
|
|
||||||
* @param {import("./size.js").Size} viewportSize Viewport size.
|
|
||||||
* @return {number} Capped resolution.
|
|
||||||
*/
|
|
||||||
function getViewportClampedResolution(resolution, maxExtent, viewportSize) {
|
|
||||||
const xResolution = getWidth(maxExtent) / viewportSize[0];
|
|
||||||
const yResolution = getHeight(maxExtent) / viewportSize[1];
|
|
||||||
return Math.min(resolution, Math.min(xResolution, yResolution));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a modified resolution to be between maxResolution and minResolution while
|
|
||||||
* still allowing the value to be slightly out of bounds.
|
|
||||||
* Note: the computation is based on the logarithm function (ln):
|
|
||||||
* - at 1, ln(x) is 0
|
|
||||||
* - above 1, ln(x) keeps increasing but at a much slower pace than x
|
|
||||||
* The final result is clamped to prevent getting too far away from bounds.
|
|
||||||
* @param {number} resolution Resolution.
|
|
||||||
* @param {number} maxResolution Max resolution.
|
|
||||||
* @param {number} minResolution Min resolution.
|
|
||||||
* @return {number} Smoothed resolution.
|
|
||||||
*/
|
|
||||||
function getSmoothClampedResolution(resolution, maxResolution, minResolution) {
|
|
||||||
let result = Math.min(resolution, maxResolution);
|
|
||||||
const ratio = 50;
|
|
||||||
|
|
||||||
result *= Math.log(1 + ratio * Math.max(0, resolution / maxResolution - 1)) / ratio + 1;
|
|
||||||
if (minResolution) {
|
|
||||||
result = Math.max(result, minResolution);
|
|
||||||
result /= Math.log(1 + ratio * Math.max(0, minResolution / resolution - 1)) / ratio + 1;
|
|
||||||
}
|
|
||||||
return clamp(result, minResolution / 2, maxResolution * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array<number>} resolutions Resolutions.
|
* @param {Array<number>} resolutions Resolutions.
|
||||||
* @param {boolean=} opt_smooth If true, the view will be able to slightly exceed resolution limits. Default: true.
|
|
||||||
* @param {import("./extent.js").Extent=} opt_maxExtent Maximum allowed extent.
|
|
||||||
* @return {Type} Zoom function.
|
* @return {Type} Zoom function.
|
||||||
*/
|
*/
|
||||||
export function createSnapToResolutions(resolutions, opt_smooth, opt_maxExtent) {
|
export function createSnapToResolutions(resolutions) {
|
||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} resolution Resolution.
|
* @param {number|undefined} resolution Resolution.
|
||||||
|
* @param {number} delta Delta.
|
||||||
* @param {number} direction Direction.
|
* @param {number} direction Direction.
|
||||||
* @param {import("./size.js").Size} size Viewport size.
|
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
|
||||||
* @return {number|undefined} Resolution.
|
* @return {number|undefined} Resolution.
|
||||||
*/
|
*/
|
||||||
function(resolution, direction, size, opt_isMoving) {
|
function(resolution, delta, direction) {
|
||||||
if (resolution !== undefined) {
|
if (resolution !== undefined) {
|
||||||
const maxResolution = resolutions[0];
|
let z = linearFindNearest(resolutions, resolution, direction);
|
||||||
const minResolution = resolutions[resolutions.length - 1];
|
z = clamp(z + delta, 0, resolutions.length - 1);
|
||||||
const cappedMaxRes = opt_maxExtent ?
|
const index = Math.floor(z);
|
||||||
getViewportClampedResolution(maxResolution, opt_maxExtent, size) :
|
if (z != index && index < resolutions.length - 1) {
|
||||||
maxResolution;
|
const power = resolutions[index] / resolutions[index + 1];
|
||||||
|
return resolutions[index] / Math.pow(power, z - index);
|
||||||
// during interacting or animating, allow intermediary values
|
} else {
|
||||||
if (opt_isMoving) {
|
return resolutions[index];
|
||||||
const smooth = opt_smooth !== undefined ? opt_smooth : true;
|
|
||||||
if (!smooth) {
|
|
||||||
return clamp(resolution, minResolution, cappedMaxRes);
|
|
||||||
}
|
}
|
||||||
return getSmoothClampedResolution(resolution, cappedMaxRes, minResolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
const capped = Math.min(cappedMaxRes, resolution);
|
|
||||||
const z = Math.floor(linearFindNearest(resolutions, capped, direction));
|
|
||||||
return resolutions[z];
|
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -94,78 +44,29 @@ export function createSnapToResolutions(resolutions, opt_smooth, opt_maxExtent)
|
|||||||
/**
|
/**
|
||||||
* @param {number} power Power.
|
* @param {number} power Power.
|
||||||
* @param {number} maxResolution Maximum resolution.
|
* @param {number} maxResolution Maximum resolution.
|
||||||
* @param {number=} opt_minResolution Minimum resolution.
|
* @param {number=} opt_maxLevel Maximum level.
|
||||||
* @param {boolean=} opt_smooth If true, the view will be able to slightly exceed resolution limits. Default: true.
|
|
||||||
* @param {import("./extent.js").Extent=} opt_maxExtent Maximum allowed extent.
|
|
||||||
* @return {Type} Zoom function.
|
* @return {Type} Zoom function.
|
||||||
*/
|
*/
|
||||||
export function createSnapToPower(power, maxResolution, opt_minResolution, opt_smooth, opt_maxExtent) {
|
export function createSnapToPower(power, maxResolution, opt_maxLevel) {
|
||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} resolution Resolution.
|
* @param {number|undefined} resolution Resolution.
|
||||||
|
* @param {number} delta Delta.
|
||||||
* @param {number} direction Direction.
|
* @param {number} direction Direction.
|
||||||
* @param {import("./size.js").Size} size Viewport size.
|
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
|
||||||
* @return {number|undefined} Resolution.
|
* @return {number|undefined} Resolution.
|
||||||
*/
|
*/
|
||||||
function(resolution, direction, size, opt_isMoving) {
|
function(resolution, delta, direction) {
|
||||||
if (resolution !== undefined) {
|
if (resolution !== undefined) {
|
||||||
const cappedMaxRes = opt_maxExtent ?
|
const offset = -direction / 2 + 0.5;
|
||||||
getViewportClampedResolution(maxResolution, opt_maxExtent, size) :
|
const oldLevel = Math.floor(
|
||||||
maxResolution;
|
Math.log(maxResolution / resolution) / Math.log(power) + offset);
|
||||||
const minResolution = opt_minResolution !== undefined ? opt_minResolution : 0;
|
let newLevel = Math.max(oldLevel + delta, 0);
|
||||||
|
if (opt_maxLevel !== undefined) {
|
||||||
// during interacting or animating, allow intermediary values
|
newLevel = Math.min(newLevel, opt_maxLevel);
|
||||||
if (opt_isMoving) {
|
|
||||||
const smooth = opt_smooth !== undefined ? opt_smooth : true;
|
|
||||||
if (!smooth) {
|
|
||||||
return clamp(resolution, minResolution, cappedMaxRes);
|
|
||||||
}
|
}
|
||||||
return getSmoothClampedResolution(resolution, cappedMaxRes, minResolution);
|
return maxResolution / Math.pow(power, newLevel);
|
||||||
}
|
|
||||||
|
|
||||||
const offset = -direction * (0.5 - 1e-9) + 0.5;
|
|
||||||
const capped = Math.min(cappedMaxRes, resolution);
|
|
||||||
const zoomLevel = Math.floor(
|
|
||||||
Math.log(maxResolution / capped) / Math.log(power) + offset);
|
|
||||||
const newResolution = maxResolution / Math.pow(power, zoomLevel);
|
|
||||||
return clamp(newResolution, minResolution, cappedMaxRes);
|
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} maxResolution Max resolution.
|
|
||||||
* @param {number} minResolution Min resolution.
|
|
||||||
* @param {boolean=} opt_smooth If true, the view will be able to slightly exceed resolution limits. Default: true.
|
|
||||||
* @param {import("./extent.js").Extent=} opt_maxExtent Maximum allowed extent.
|
|
||||||
* @return {Type} Zoom function.
|
|
||||||
*/
|
|
||||||
export function createMinMaxResolution(maxResolution, minResolution, opt_smooth, opt_maxExtent) {
|
|
||||||
return (
|
|
||||||
/**
|
|
||||||
* @param {number|undefined} resolution Resolution.
|
|
||||||
* @param {number} direction Direction.
|
|
||||||
* @param {import("./size.js").Size} size Viewport size.
|
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
|
||||||
* @return {number|undefined} Resolution.
|
|
||||||
*/
|
|
||||||
function(resolution, direction, size, opt_isMoving) {
|
|
||||||
if (resolution !== undefined) {
|
|
||||||
const cappedMaxRes = opt_maxExtent ?
|
|
||||||
getViewportClampedResolution(maxResolution, opt_maxExtent, size) :
|
|
||||||
maxResolution;
|
|
||||||
const smooth = opt_smooth !== undefined ? opt_smooth : true;
|
|
||||||
|
|
||||||
if (!smooth || !opt_isMoving) {
|
|
||||||
return clamp(resolution, minResolution, cappedMaxRes);
|
|
||||||
}
|
|
||||||
return getSmoothClampedResolution(resolution, cappedMaxRes, minResolution);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ import {toRadians} from './math.js';
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {function((number|undefined), boolean=): (number|undefined)} Type
|
* @typedef {function((number|undefined), number): (number|undefined)} Type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
|
* @param {number} delta Delta.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
export function disable(rotation) {
|
export function disable(rotation, delta) {
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -24,11 +25,12 @@ export function disable(rotation) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
|
* @param {number} delta Delta.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
export function none(rotation) {
|
export function none(rotation, delta) {
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
return rotation;
|
return rotation + delta;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -44,16 +46,12 @@ export function createSnapToN(n) {
|
|||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
* @param {boolean=} opt_isMoving True if an interaction or animation is in progress.
|
* @param {number} delta Delta.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
function(rotation, opt_isMoving) {
|
function(rotation, delta) {
|
||||||
if (opt_isMoving) {
|
|
||||||
return rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
rotation = Math.floor(rotation / theta + 0.5) * theta;
|
rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;
|
||||||
return rotation;
|
return rotation;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -71,19 +69,15 @@ export function createSnapToZero(opt_tolerance) {
|
|||||||
return (
|
return (
|
||||||
/**
|
/**
|
||||||
* @param {number|undefined} rotation Rotation.
|
* @param {number|undefined} rotation Rotation.
|
||||||
* @param {boolean} opt_isMoving True if an interaction or animation is in progress.
|
* @param {number} delta Delta.
|
||||||
* @return {number|undefined} Rotation.
|
* @return {number|undefined} Rotation.
|
||||||
*/
|
*/
|
||||||
function(rotation, opt_isMoving) {
|
function(rotation, delta) {
|
||||||
if (opt_isMoving) {
|
|
||||||
return rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rotation !== undefined) {
|
if (rotation !== undefined) {
|
||||||
if (Math.abs(rotation) <= tolerance) {
|
if (Math.abs(rotation + delta) <= tolerance) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return rotation;
|
return rotation + delta;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const LayerConfig = {
|
|||||||
*/
|
*/
|
||||||
const ProviderConfig = {
|
const ProviderConfig = {
|
||||||
'terrain': {
|
'terrain': {
|
||||||
minZoom: 0,
|
minZoom: 4,
|
||||||
maxZoom: 18
|
maxZoom: 18
|
||||||
},
|
},
|
||||||
'toner': {
|
'toner': {
|
||||||
@@ -82,8 +82,8 @@ const ProviderConfig = {
|
|||||||
maxZoom: 20
|
maxZoom: 20
|
||||||
},
|
},
|
||||||
'watercolor': {
|
'watercolor': {
|
||||||
minZoom: 0,
|
minZoom: 1,
|
||||||
maxZoom: 18
|
maxZoom: 16
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,8 +103,6 @@ const ProviderConfig = {
|
|||||||
* imageTile.getImage().src = src;
|
* imageTile.getImage().src = src;
|
||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
|
||||||
* To disable the opacity transition, pass `transition: 0`.
|
|
||||||
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
|
||||||
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
|
||||||
*/
|
*/
|
||||||
@@ -139,7 +137,6 @@ class Stamen extends XYZ {
|
|||||||
opaque: layerConfig.opaque,
|
opaque: layerConfig.opaque,
|
||||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||||
tileLoadFunction: options.tileLoadFunction,
|
tileLoadFunction: options.tileLoadFunction,
|
||||||
transition: options.transition,
|
|
||||||
url: url,
|
url: url,
|
||||||
wrapX: options.wrapX
|
wrapX: options.wrapX
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {equals} from '../array.js';
|
|||||||
* to `false` (e.g. for sources with polygons that represent administrative
|
* to `false` (e.g. for sources with polygons that represent administrative
|
||||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||||
* stroke operations.
|
* stroke operations.
|
||||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection of the tile grid.
|
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||||
* @property {import("./State.js").default} [state] Source state.
|
* @property {import("./State.js").default} [state] Source state.
|
||||||
* @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles.
|
* @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles.
|
||||||
* Default is {@link module:ol/VectorTile}.
|
* Default is {@link module:ol/VectorTile}.
|
||||||
@@ -35,20 +35,18 @@ import {equals} from '../array.js';
|
|||||||
* @property {number|import("../size.js").Size} [tileSize=512] Optional tile size.
|
* @property {number|import("../size.js").Size} [tileSize=512] Optional tile size.
|
||||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||||
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
|
* @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
|
||||||
* Optional function to load a tile given a URL. Could look like this for pbf tiles:
|
* Optional function to load a tile given a URL. Could look like this:
|
||||||
* ```js
|
* ```js
|
||||||
* function(tile, url) {
|
* function(tile, url) {
|
||||||
* tile.setLoader(function(extent, resolution, projection) {
|
* tile.setLoader(function() {
|
||||||
* fetch(url).then(function(response) {
|
* var data = // ... fetch data
|
||||||
* response.arrayBuffer().then(function(data) {
|
* var format = tile.getFormat();
|
||||||
* const format = tile.getFormat() // ol/format/MVT configured as source format
|
* tile.setProjection(format.readProjection(data));
|
||||||
* const features = format.readFeatures(data, {
|
* tile.setExtent(format.getLastExtent()); // line only required for ol/format/MVT
|
||||||
* extent: extent,
|
* tile.setFeatures(format.readFeatures(data, {
|
||||||
* featureProjection: projection
|
* // featureProjection is not required for ol/format/MVT
|
||||||
* });
|
* featureProjection: map.getView().getProjection()
|
||||||
* tile.setFeatures(features);
|
* }));
|
||||||
* });
|
|
||||||
* });
|
|
||||||
* }
|
* }
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
@@ -189,9 +187,9 @@ class VectorTile extends UrlTile {
|
|||||||
const sourceTileGrid = this.tileGrid;
|
const sourceTileGrid = this.tileGrid;
|
||||||
const sourceExtent = sourceTileGrid.getExtent();
|
const sourceExtent = sourceTileGrid.getExtent();
|
||||||
if (sourceExtent) {
|
if (sourceExtent) {
|
||||||
getIntersection(extent, sourceExtent, extent);
|
getIntersection(extent, sourceTileGrid.getExtent(), extent);
|
||||||
}
|
}
|
||||||
const sourceZ = sourceTileGrid.getZForResolution(resolution/*, 1*/);
|
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||||
const minZoom = sourceTileGrid.getMinZoom();
|
const minZoom = sourceTileGrid.getMinZoom();
|
||||||
|
|
||||||
let loadedZ = sourceZ + 1;
|
let loadedZ = sourceZ + 1;
|
||||||
@@ -217,9 +215,6 @@ class VectorTile extends UrlTile {
|
|||||||
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
||||||
tileUrl == undefined ? '' : tileUrl,
|
tileUrl == undefined ? '' : tileUrl,
|
||||||
this.format_, this.tileLoadFunction);
|
this.format_, this.tileLoadFunction);
|
||||||
sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
|
||||||
sourceTile.projection = projection;
|
|
||||||
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
|
|
||||||
this.sourceTiles_[tileKey] = sourceTile;
|
this.sourceTiles_[tileKey] = sourceTile;
|
||||||
empty = empty && sourceTile.getState() === TileState.EMPTY;
|
empty = empty && sourceTile.getState() === TileState.EMPTY;
|
||||||
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
|
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Feature from '../../../../src/ol/Feature.js';
|
import Feature from '../../../../src/ol/Feature.js';
|
||||||
|
import {getWidth} from '../../../../src/ol/extent.js';
|
||||||
import MVT from '../../../../src/ol/format/MVT.js';
|
import MVT from '../../../../src/ol/format/MVT.js';
|
||||||
import Point from '../../../../src/ol/geom/Point.js';
|
import Point from '../../../../src/ol/geom/Point.js';
|
||||||
import Polygon from '../../../../src/ol/geom/Polygon.js';
|
import Polygon from '../../../../src/ol/geom/Polygon.js';
|
||||||
@@ -21,20 +22,15 @@ where('ArrayBuffer.isView').describe('ol.format.MVT', function() {
|
|||||||
|
|
||||||
describe('#readFeatures', function() {
|
describe('#readFeatures', function() {
|
||||||
|
|
||||||
const options = {
|
|
||||||
featureProjection: 'EPSG:3857',
|
|
||||||
extent: [1824704.739223726, 6141868.096770482, 1827150.7241288517, 6144314.081675608]
|
|
||||||
};
|
|
||||||
|
|
||||||
it('uses ol.render.Feature as feature class by default', function() {
|
it('uses ol.render.Feature as feature class by default', function() {
|
||||||
const format = new MVT({layers: ['water']});
|
const format = new MVT({layers: ['water']});
|
||||||
const features = format.readFeatures(data, options);
|
const features = format.readFeatures(data);
|
||||||
expect(features[0]).to.be.a(RenderFeature);
|
expect(features[0]).to.be.a(RenderFeature);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses only specified layers', function() {
|
it('parses only specified layers', function() {
|
||||||
const format = new MVT({layers: ['water']});
|
const format = new MVT({layers: ['water']});
|
||||||
const features = format.readFeatures(data, options);
|
const features = format.readFeatures(data);
|
||||||
expect(features.length).to.be(10);
|
expect(features.length).to.be(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,27 +64,29 @@ where('ArrayBuffer.isView').describe('ol.format.MVT', function() {
|
|||||||
featureClass: Feature,
|
featureClass: Feature,
|
||||||
layers: ['building']
|
layers: ['building']
|
||||||
});
|
});
|
||||||
let features = format.readFeatures(data, options);
|
let features = format.readFeatures(data);
|
||||||
expect(features[0].getId()).to.be(2);
|
expect(features[0].getId()).to.be(2);
|
||||||
// ol.render.Feature
|
// ol.render.Feature
|
||||||
format = new MVT({
|
format = new MVT({
|
||||||
layers: ['building']
|
layers: ['building']
|
||||||
});
|
});
|
||||||
features = format.readFeatures(data, options);
|
features = format.readFeatures(data);
|
||||||
expect(features[0].getId()).to.be(2);
|
expect(features[0].getId()).to.be(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets the extent of the last readFeatures call', function() {
|
||||||
|
const format = new MVT();
|
||||||
|
format.readFeatures(data);
|
||||||
|
const extent = format.getLastExtent();
|
||||||
|
expect(getWidth(extent)).to.be(4096);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ol.format.MVT', function() {
|
describe('ol.format.MVT', function() {
|
||||||
|
|
||||||
const options = {
|
|
||||||
featureProjection: 'EPSG:3857',
|
|
||||||
extent: [1824704.739223726, 6141868.096770482, 1827150.7241288517, 6144314.081675608]
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('#createFeature_', function() {
|
describe('#createFeature_', function() {
|
||||||
it('accepts a geometryName', function() {
|
it('accepts a geometryName', function() {
|
||||||
const format = new MVT({
|
const format = new MVT({
|
||||||
@@ -178,9 +176,7 @@ describe('ol.format.MVT', function() {
|
|||||||
ends.push(10, 20);
|
ends.push(10, 20);
|
||||||
createdEnds = ends;
|
createdEnds = ends;
|
||||||
};
|
};
|
||||||
format.dataProjection.setExtent([0, 0, 4096, 4096]);
|
const feature = format.createFeature_({}, rawFeature);
|
||||||
format.dataProjection.setWorldExtent(options.extent);
|
|
||||||
const feature = format.createFeature_({}, rawFeature, format.adaptOptions(options));
|
|
||||||
expect(feature).to.be.a(RenderFeature);
|
expect(feature).to.be.a(RenderFeature);
|
||||||
expect(feature.getType()).to.be('Polygon');
|
expect(feature.getType()).to.be('Polygon');
|
||||||
expect(feature.getFlatCoordinates()).to.equal(createdFlatCoordinates);
|
expect(feature.getFlatCoordinates()).to.equal(createdFlatCoordinates);
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ describe('ol.geom.flat.interpolate', function() {
|
|||||||
expect(point).to.eql([2, 3]);
|
expect(point).to.eql([2, 3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('also when vertices are repeated', function() {
|
xit('also when vertices are repeated', function() {
|
||||||
const flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5];
|
const flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5];
|
||||||
const point = interpolatePoint(
|
const point = interpolatePoint(
|
||||||
flatCoordinates, 0, 8, 2, 0.5);
|
flatCoordinates, 0, 6, 2, 0.5);
|
||||||
expect(point).to.eql([2, 3]);
|
expect(point).to.eql([2, 3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@ describe('ol.geom.flat.interpolate', function() {
|
|||||||
expect(point).to.eql([3, 4]);
|
expect(point).to.eql([3, 4]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('also when vertices are repeated', function() {
|
xit('also when vertices are repeated', function() {
|
||||||
const flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5, 6, 7];
|
const flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5, 6, 7];
|
||||||
const point = interpolatePoint(
|
const point = interpolatePoint(
|
||||||
flatCoordinates, 0, 10, 2, 0.5);
|
flatCoordinates, 0, 8, 2, 0.5);
|
||||||
expect(point).to.eql([3, 4]);
|
expect(point).to.eql([3, 4]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ describe('ol.geom.flat.interpolate', function() {
|
|||||||
expect(point).to.eql([3, 4]);
|
expect(point).to.eql([3, 4]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('also when vertices are repeated',
|
xit('also when vertices are repeated',
|
||||||
function() {
|
function() {
|
||||||
const flatCoordinates = [0, 1, 2, 3, 2, 3, 6, 7];
|
const flatCoordinates = [0, 1, 2, 3, 2, 3, 6, 7];
|
||||||
const point = interpolatePoint(
|
const point = interpolatePoint(
|
||||||
flatCoordinates, 0, 8, 2, 0.5);
|
flatCoordinates, 0, 6, 2, 0.5);
|
||||||
expect(point).to.eql([3, 4]);
|
expect(point).to.eql([3, 4]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -62,18 +62,13 @@ describe('ol.interaction.DragRotateAndZoom', function() {
|
|||||||
true);
|
true);
|
||||||
interaction.lastAngle_ = Math.PI;
|
interaction.lastAngle_ = Math.PI;
|
||||||
|
|
||||||
let callCount = 0;
|
|
||||||
|
|
||||||
let view = map.getView();
|
let view = map.getView();
|
||||||
view.on('change:rotation', function() {
|
let spy = sinon.spy(view, 'rotate');
|
||||||
callCount++;
|
|
||||||
});
|
|
||||||
|
|
||||||
interaction.handleDragEvent(event);
|
interaction.handleDragEvent(event);
|
||||||
expect(callCount).to.be(1);
|
expect(spy.callCount).to.be(1);
|
||||||
expect(interaction.lastAngle_).to.be(-0.8308214428190254);
|
expect(interaction.lastAngle_).to.be(-0.8308214428190254);
|
||||||
|
view.rotate.restore();
|
||||||
|
|
||||||
callCount = 0;
|
|
||||||
view = new View({
|
view = new View({
|
||||||
projection: 'EPSG:4326',
|
projection: 'EPSG:4326',
|
||||||
center: [0, 0],
|
center: [0, 0],
|
||||||
@@ -81,16 +76,15 @@ describe('ol.interaction.DragRotateAndZoom', function() {
|
|||||||
enableRotation: false
|
enableRotation: false
|
||||||
});
|
});
|
||||||
map.setView(view);
|
map.setView(view);
|
||||||
view.on('change:rotation', function() {
|
|
||||||
callCount++;
|
|
||||||
});
|
|
||||||
|
|
||||||
event = new MapBrowserPointerEvent('pointermove', map,
|
event = new MapBrowserPointerEvent('pointermove', map,
|
||||||
new PointerEvent('pointermove', {clientX: 24, clientY: 16}, {pointerType: 'mouse'}),
|
new PointerEvent('pointermove', {clientX: 24, clientY: 16}, {pointerType: 'mouse'}),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
spy = sinon.spy(view, 'rotate');
|
||||||
interaction.handleDragEvent(event);
|
interaction.handleDragEvent(event);
|
||||||
expect(callCount).to.be(0);
|
expect(spy.callCount).to.be(0);
|
||||||
|
view.rotate.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ describe('ol.interaction.DragZoom', function() {
|
|||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
const resolution = view.getResolution();
|
const resolution = view.getResolution();
|
||||||
expect(resolution).to.eql(view.getConstrainedResolution(0.5));
|
expect(resolution).to.eql(view.constrainResolution(0.5));
|
||||||
done();
|
done();
|
||||||
}, 50);
|
}, 50);
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Map from '../../../../src/ol/Map.js';
|
import Map from '../../../../src/ol/Map.js';
|
||||||
|
import View from '../../../../src/ol/View.js';
|
||||||
import EventTarget from '../../../../src/ol/events/Target.js';
|
import EventTarget from '../../../../src/ol/events/Target.js';
|
||||||
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
import Interaction, {zoomByDelta} from '../../../../src/ol/interaction/Interaction.js';
|
||||||
import {FALSE} from '../../../../src/ol/functions.js';
|
import {FALSE} from '../../../../src/ol/functions.js';
|
||||||
|
|
||||||
describe('ol.interaction.Interaction', function() {
|
describe('ol.interaction.Interaction', function() {
|
||||||
@@ -86,4 +87,67 @@ describe('ol.interaction.Interaction', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('zoomByDelta()', function() {
|
||||||
|
|
||||||
|
it('changes view resolution', function() {
|
||||||
|
const view = new View({
|
||||||
|
resolution: 1,
|
||||||
|
resolutions: [4, 2, 1, 0.5, 0.25]
|
||||||
|
});
|
||||||
|
|
||||||
|
zoomByDelta(view, 1);
|
||||||
|
expect(view.getResolution()).to.be(0.5);
|
||||||
|
|
||||||
|
zoomByDelta(view, -1);
|
||||||
|
expect(view.getResolution()).to.be(1);
|
||||||
|
|
||||||
|
zoomByDelta(view, 2);
|
||||||
|
expect(view.getResolution()).to.be(0.25);
|
||||||
|
|
||||||
|
zoomByDelta(view, -2);
|
||||||
|
expect(view.getResolution()).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('changes view resolution and center relative to the anchor', function() {
|
||||||
|
const view = new View({
|
||||||
|
center: [0, 0],
|
||||||
|
resolution: 1,
|
||||||
|
resolutions: [4, 2, 1, 0.5, 0.25]
|
||||||
|
});
|
||||||
|
|
||||||
|
zoomByDelta(view, 1, [10, 10]);
|
||||||
|
expect(view.getCenter()).to.eql([5, 5]);
|
||||||
|
|
||||||
|
zoomByDelta(view, -1, [0, 0]);
|
||||||
|
expect(view.getCenter()).to.eql([10, 10]);
|
||||||
|
|
||||||
|
zoomByDelta(view, 2, [0, 0]);
|
||||||
|
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
||||||
|
|
||||||
|
zoomByDelta(view, -2, [0, 0]);
|
||||||
|
expect(view.getCenter()).to.eql([10, 10]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('changes view resolution and center relative to the anchor, while respecting the extent', function() {
|
||||||
|
const view = new View({
|
||||||
|
center: [0, 0],
|
||||||
|
extent: [-2.5, -2.5, 2.5, 2.5],
|
||||||
|
resolution: 1,
|
||||||
|
resolutions: [4, 2, 1, 0.5, 0.25]
|
||||||
|
});
|
||||||
|
|
||||||
|
zoomByDelta(view, 1, [10, 10]);
|
||||||
|
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
||||||
|
|
||||||
|
zoomByDelta(view, -1, [0, 0]);
|
||||||
|
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
||||||
|
|
||||||
|
zoomByDelta(view, 2, [10, 10]);
|
||||||
|
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
||||||
|
|
||||||
|
zoomByDelta(view, -2, [0, 0]);
|
||||||
|
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -565,6 +565,7 @@ describe('ol.Map', function() {
|
|||||||
const interactions = defaultInteractions(options);
|
const interactions = defaultInteractions(options);
|
||||||
expect(interactions.getLength()).to.eql(1);
|
expect(interactions.getLength()).to.eql(1);
|
||||||
expect(interactions.item(0)).to.be.a(MouseWheelZoom);
|
expect(interactions.item(0)).to.be.a(MouseWheelZoom);
|
||||||
|
expect(interactions.item(0).constrainResolution_).to.eql(false);
|
||||||
expect(interactions.item(0).useAnchor_).to.eql(true);
|
expect(interactions.item(0).useAnchor_).to.eql(true);
|
||||||
interactions.item(0).setMouseAnchor(false);
|
interactions.item(0).setMouseAnchor(false);
|
||||||
expect(interactions.item(0).useAnchor_).to.eql(false);
|
expect(interactions.item(0).useAnchor_).to.eql(false);
|
||||||
@@ -600,6 +601,21 @@ describe('ol.Map', function() {
|
|||||||
const interactions = defaultInteractions(options);
|
const interactions = defaultInteractions(options);
|
||||||
expect(interactions.getLength()).to.eql(1);
|
expect(interactions.getLength()).to.eql(1);
|
||||||
expect(interactions.item(0)).to.be.a(PinchZoom);
|
expect(interactions.item(0)).to.be.a(PinchZoom);
|
||||||
|
expect(interactions.item(0).constrainResolution_).to.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('set constrainResolution option', function() {
|
||||||
|
it('set constrainResolution option', function() {
|
||||||
|
options.pinchZoom = true;
|
||||||
|
options.mouseWheelZoom = true;
|
||||||
|
options.constrainResolution = true;
|
||||||
|
const interactions = defaultInteractions(options);
|
||||||
|
expect(interactions.getLength()).to.eql(2);
|
||||||
|
expect(interactions.item(0)).to.be.a(PinchZoom);
|
||||||
|
expect(interactions.item(0).constrainResolution_).to.eql(true);
|
||||||
|
expect(interactions.item(1)).to.be.a(MouseWheelZoom);
|
||||||
|
expect(interactions.item(1).constrainResolution_).to.eql(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -76,14 +76,6 @@ describe('ol.render.canvas', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('measureTextHeight', function() {
|
|
||||||
it('respects line-height', function() {
|
|
||||||
const height = render.measureTextHeight('12px/1.2 sans-serif');
|
|
||||||
expect(render.measureTextHeight('12px/2.4 sans-serif')).to.be.greaterThan(height);
|
|
||||||
expect(render.measureTextHeight('12px/0.1 sans-serif')).to.be.lessThan(height);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('rotateAtOffset', function() {
|
describe('rotateAtOffset', function() {
|
||||||
it('rotates a canvas at an offset point', function() {
|
it('rotates a canvas at an offset point', function() {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import {getCenter} from '../../../../../src/ol/extent.js';
|
|||||||
import MVT from '../../../../../src/ol/format/MVT.js';
|
import MVT from '../../../../../src/ol/format/MVT.js';
|
||||||
import Point from '../../../../../src/ol/geom/Point.js';
|
import Point from '../../../../../src/ol/geom/Point.js';
|
||||||
import VectorTileLayer from '../../../../../src/ol/layer/VectorTile.js';
|
import VectorTileLayer from '../../../../../src/ol/layer/VectorTile.js';
|
||||||
import {get as getProjection} from '../../../../../src/ol/proj.js';
|
import {get as getProjection, fromLonLat} from '../../../../../src/ol/proj.js';
|
||||||
|
import Projection from '../../../../../src/ol/proj/Projection.js';
|
||||||
import {checkedFonts} from '../../../../../src/ol/render/canvas.js';
|
import {checkedFonts} from '../../../../../src/ol/render/canvas.js';
|
||||||
import RenderFeature from '../../../../../src/ol/render/Feature.js';
|
import RenderFeature from '../../../../../src/ol/render/Feature.js';
|
||||||
import CanvasVectorTileLayerRenderer from '../../../../../src/ol/renderer/canvas/VectorTileLayer.js';
|
import CanvasVectorTileLayerRenderer from '../../../../../src/ol/renderer/canvas/VectorTileLayer.js';
|
||||||
@@ -63,6 +64,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this.setFeatures([feature1, feature2, feature3]);
|
this.setFeatures([feature1, feature2, feature3]);
|
||||||
|
this.setProjection(getProjection('EPSG:4326'));
|
||||||
this.setState(TileState.LOADED);
|
this.setState(TileState.LOADED);
|
||||||
tileCallback(this);
|
tileCallback(this);
|
||||||
}
|
}
|
||||||
@@ -186,6 +188,30 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
}, 1600);
|
}, 1600);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('transforms geometries when tile and view projection are different', function() {
|
||||||
|
let tile;
|
||||||
|
tileCallback = function(t) {
|
||||||
|
tile = t;
|
||||||
|
};
|
||||||
|
map.renderSync();
|
||||||
|
expect(tile.getProjection()).to.equal(getProjection('EPSG:3857'));
|
||||||
|
expect(feature1.getGeometry().getCoordinates()).to.eql(fromLonLat([1, -1]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Geometries are transformed from tile-pixels', function() {
|
||||||
|
const proj = new Projection({code: 'EPSG:3857', units: 'tile-pixels'});
|
||||||
|
let tile;
|
||||||
|
tileCallback = function(t) {
|
||||||
|
t.setProjection(proj);
|
||||||
|
t.setExtent([0, 0, 4096, 4096]);
|
||||||
|
tile = t;
|
||||||
|
};
|
||||||
|
map.renderSync();
|
||||||
|
expect(tile.getProjection()).to.equal(getProjection('EPSG:3857'));
|
||||||
|
expect(feature1.getGeometry().getCoordinates()).to.eql([-20027724.40316874, 20047292.282409746]);
|
||||||
|
expect(feature3.flatCoordinates_).to.eql([-20027724.40316874, 20047292.282409746]);
|
||||||
|
});
|
||||||
|
|
||||||
it('works for multiple layers that use the same source', function() {
|
it('works for multiple layers that use the same source', function() {
|
||||||
const layer2 = new VectorTileLayer({
|
const layer2 = new VectorTileLayer({
|
||||||
source: source,
|
source: source,
|
||||||
@@ -214,6 +240,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
const sourceTile = new VectorTile([0, 0, 0], 2);
|
const sourceTile = new VectorTile([0, 0, 0], 2);
|
||||||
|
sourceTile.setProjection(getProjection('EPSG:3857'));
|
||||||
sourceTile.features_ = [];
|
sourceTile.features_ = [];
|
||||||
sourceTile.getImage = function() {
|
sourceTile.getImage = function() {
|
||||||
return document.createElement('canvas');
|
return document.createElement('canvas');
|
||||||
@@ -272,6 +299,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
const sourceTile = new VectorTile([0, 0, 0]);
|
const sourceTile = new VectorTile([0, 0, 0]);
|
||||||
sourceTile.setState(TileState.LOADED);
|
sourceTile.setState(TileState.LOADED);
|
||||||
|
sourceTile.setProjection(getProjection('EPSG:3857'));
|
||||||
source = new VectorTileSource({
|
source = new VectorTileSource({
|
||||||
tileClass: TileClass,
|
tileClass: TileClass,
|
||||||
tileGrid: createXYZ()
|
tileGrid: createXYZ()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {createSnapToResolutions, createSnapToPower} from '../../../src/ol/resolutionconstraint.js';
|
import {createSnapToResolutions, createSnapToPower} from '../../../src/ol/resolutionconstraint.js';
|
||||||
import {createMinMaxResolution} from '../../../src/ol/resolutionconstraint';
|
|
||||||
|
|
||||||
|
|
||||||
describe('ol.resolutionconstraint', function() {
|
describe('ol.resolutionconstraint', function() {
|
||||||
@@ -13,30 +12,30 @@ describe('ol.resolutionconstraint', function() {
|
|||||||
[1000, 500, 250, 100]);
|
[1000, 500, 250, 100]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 0', function() {
|
describe('delta 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1000, 0)).to.eql(1000);
|
expect(resolutionConstraint(1000, 0, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(500, 0)).to.eql(500);
|
expect(resolutionConstraint(500, 0, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(250, 0)).to.eql(250);
|
expect(resolutionConstraint(250, 0, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(100, 0)).to.eql(100);
|
expect(resolutionConstraint(100, 0, 0)).to.eql(100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 1', function() {
|
describe('zoom in', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1000, 1)).to.eql(1000);
|
expect(resolutionConstraint(1000, 1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(500, 1)).to.eql(500);
|
expect(resolutionConstraint(500, 1, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(250, 1)).to.eql(250);
|
expect(resolutionConstraint(250, 1, 0)).to.eql(100);
|
||||||
expect(resolutionConstraint(100, 1)).to.eql(100);
|
expect(resolutionConstraint(100, 1, 0)).to.eql(100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction -1', function() {
|
describe('zoom out', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1000, -1)).to.eql(1000);
|
expect(resolutionConstraint(1000, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(500, -1)).to.eql(500);
|
expect(resolutionConstraint(500, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(250, -1)).to.eql(250);
|
expect(resolutionConstraint(250, -1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(100, -1)).to.eql(100);
|
expect(resolutionConstraint(100, -1, 0)).to.eql(250);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -51,42 +50,42 @@ describe('ol.resolutionconstraint', function() {
|
|||||||
[1000, 500, 250, 100]);
|
[1000, 500, 250, 100]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 0', function() {
|
describe('delta 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, 0)).to.eql(1000);
|
expect(resolutionConstraint(1050, 0, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(950, 0)).to.eql(1000);
|
expect(resolutionConstraint(950, 0, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(550, 0)).to.eql(500);
|
expect(resolutionConstraint(550, 0, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(400, 0)).to.eql(500);
|
expect(resolutionConstraint(400, 0, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(300, 0)).to.eql(250);
|
expect(resolutionConstraint(300, 0, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(200, 0)).to.eql(250);
|
expect(resolutionConstraint(200, 0, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(150, 0)).to.eql(100);
|
expect(resolutionConstraint(150, 0, 0)).to.eql(100);
|
||||||
expect(resolutionConstraint(50, 0)).to.eql(100);
|
expect(resolutionConstraint(50, 0, 0)).to.eql(100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 1', function() {
|
describe('zoom in', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, 1)).to.eql(1000);
|
expect(resolutionConstraint(1050, 1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(950, 1)).to.eql(1000);
|
expect(resolutionConstraint(950, 1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(550, 1)).to.eql(1000);
|
expect(resolutionConstraint(550, 1, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(450, 1)).to.eql(500);
|
expect(resolutionConstraint(450, 1, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(300, 1)).to.eql(500);
|
expect(resolutionConstraint(300, 1, 0)).to.eql(100);
|
||||||
expect(resolutionConstraint(200, 1)).to.eql(250);
|
expect(resolutionConstraint(200, 1, 0)).to.eql(100);
|
||||||
expect(resolutionConstraint(150, 1)).to.eql(250);
|
expect(resolutionConstraint(150, 1, 0)).to.eql(100);
|
||||||
expect(resolutionConstraint(50, 1)).to.eql(100);
|
expect(resolutionConstraint(50, 1, 0)).to.eql(100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction -1', function() {
|
describe('zoom out', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, -1)).to.eql(1000);
|
expect(resolutionConstraint(1050, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(950, -1)).to.eql(500);
|
expect(resolutionConstraint(950, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(550, -1)).to.eql(500);
|
expect(resolutionConstraint(550, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(450, -1)).to.eql(250);
|
expect(resolutionConstraint(450, -1, 0)).to.eql(1000);
|
||||||
expect(resolutionConstraint(300, -1)).to.eql(250);
|
expect(resolutionConstraint(300, -1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(200, -1)).to.eql(100);
|
expect(resolutionConstraint(200, -1, 0)).to.eql(500);
|
||||||
expect(resolutionConstraint(150, -1)).to.eql(100);
|
expect(resolutionConstraint(150, -1, 0)).to.eql(250);
|
||||||
expect(resolutionConstraint(50, -1)).to.eql(100);
|
expect(resolutionConstraint(50, -1, 0)).to.eql(250);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -97,54 +96,54 @@ describe('ol.resolutionconstraint', function() {
|
|||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
resolutionConstraint =
|
resolutionConstraint =
|
||||||
createSnapToPower(2, 1024, 1);
|
createSnapToPower(2, 1024, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('delta 0', function() {
|
describe('delta 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1024, 0)).to.eql(1024);
|
expect(resolutionConstraint(1024, 0, 0)).to.eql(1024);
|
||||||
expect(resolutionConstraint(512, 0)).to.eql(512);
|
expect(resolutionConstraint(512, 0, 0)).to.eql(512);
|
||||||
expect(resolutionConstraint(256, 0)).to.eql(256);
|
expect(resolutionConstraint(256, 0, 0)).to.eql(256);
|
||||||
expect(resolutionConstraint(128, 0)).to.eql(128);
|
expect(resolutionConstraint(128, 0, 0)).to.eql(128);
|
||||||
expect(resolutionConstraint(64, 0)).to.eql(64);
|
expect(resolutionConstraint(64, 0, 0)).to.eql(64);
|
||||||
expect(resolutionConstraint(32, 0)).to.eql(32);
|
expect(resolutionConstraint(32, 0, 0)).to.eql(32);
|
||||||
expect(resolutionConstraint(16, 0)).to.eql(16);
|
expect(resolutionConstraint(16, 0, 0)).to.eql(16);
|
||||||
expect(resolutionConstraint(8, 0)).to.eql(8);
|
expect(resolutionConstraint(8, 0, 0)).to.eql(8);
|
||||||
expect(resolutionConstraint(4, 0)).to.eql(4);
|
expect(resolutionConstraint(4, 0, 0)).to.eql(4);
|
||||||
expect(resolutionConstraint(2, 0)).to.eql(2);
|
expect(resolutionConstraint(2, 0, 0)).to.eql(2);
|
||||||
expect(resolutionConstraint(1, 0)).to.eql(1);
|
expect(resolutionConstraint(1, 0, 0)).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 1', function() {
|
describe('zoom in', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1024, 1)).to.eql(1024);
|
expect(resolutionConstraint(1024, 1, 0)).to.eql(512);
|
||||||
expect(resolutionConstraint(512, 1)).to.eql(512);
|
expect(resolutionConstraint(512, 1, 0)).to.eql(256);
|
||||||
expect(resolutionConstraint(256, 1)).to.eql(256);
|
expect(resolutionConstraint(256, 1, 0)).to.eql(128);
|
||||||
expect(resolutionConstraint(128, 1)).to.eql(128);
|
expect(resolutionConstraint(128, 1, 0)).to.eql(64);
|
||||||
expect(resolutionConstraint(64, 1)).to.eql(64);
|
expect(resolutionConstraint(64, 1, 0)).to.eql(32);
|
||||||
expect(resolutionConstraint(32, 1)).to.eql(32);
|
expect(resolutionConstraint(32, 1, 0)).to.eql(16);
|
||||||
expect(resolutionConstraint(16, 1)).to.eql(16);
|
expect(resolutionConstraint(16, 1, 0)).to.eql(8);
|
||||||
expect(resolutionConstraint(8, 1)).to.eql(8);
|
expect(resolutionConstraint(8, 1, 0)).to.eql(4);
|
||||||
expect(resolutionConstraint(4, 1)).to.eql(4);
|
expect(resolutionConstraint(4, 1, 0)).to.eql(2);
|
||||||
expect(resolutionConstraint(2, 1)).to.eql(2);
|
expect(resolutionConstraint(2, 1, 0)).to.eql(1);
|
||||||
expect(resolutionConstraint(1, 1)).to.eql(1);
|
expect(resolutionConstraint(1, 1, 0)).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction -1', function() {
|
describe('zoom out', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1024, -1)).to.eql(1024);
|
expect(resolutionConstraint(1024, -1, 0)).to.eql(1024);
|
||||||
expect(resolutionConstraint(512, -1)).to.eql(512);
|
expect(resolutionConstraint(512, -1, 0)).to.eql(1024);
|
||||||
expect(resolutionConstraint(256, -1)).to.eql(256);
|
expect(resolutionConstraint(256, -1, 0)).to.eql(512);
|
||||||
expect(resolutionConstraint(128, -1)).to.eql(128);
|
expect(resolutionConstraint(128, -1, 0)).to.eql(256);
|
||||||
expect(resolutionConstraint(64, -1)).to.eql(64);
|
expect(resolutionConstraint(64, -1, 0)).to.eql(128);
|
||||||
expect(resolutionConstraint(32, -1)).to.eql(32);
|
expect(resolutionConstraint(32, -1, 0)).to.eql(64);
|
||||||
expect(resolutionConstraint(16, -1)).to.eql(16);
|
expect(resolutionConstraint(16, -1, 0)).to.eql(32);
|
||||||
expect(resolutionConstraint(8, -1)).to.eql(8);
|
expect(resolutionConstraint(8, -1, 0)).to.eql(16);
|
||||||
expect(resolutionConstraint(4, -1)).to.eql(4);
|
expect(resolutionConstraint(4, -1, 0)).to.eql(8);
|
||||||
expect(resolutionConstraint(2, -1)).to.eql(2);
|
expect(resolutionConstraint(2, -1, 0)).to.eql(4);
|
||||||
expect(resolutionConstraint(1, -1)).to.eql(1);
|
expect(resolutionConstraint(1, -1, 0)).to.eql(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -155,182 +154,88 @@ describe('ol.resolutionconstraint', function() {
|
|||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
resolutionConstraint =
|
resolutionConstraint =
|
||||||
createSnapToPower(2, 1024, 1);
|
createSnapToPower(2, 1024, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 0', function() {
|
describe('delta 0, direction 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, 0)).to.eql(1024);
|
expect(resolutionConstraint(1050, 0, 0)).to.eql(1024);
|
||||||
expect(resolutionConstraint(9050, 0)).to.eql(1024);
|
expect(resolutionConstraint(9050, 0, 0)).to.eql(1024);
|
||||||
expect(resolutionConstraint(550, 0)).to.eql(512);
|
expect(resolutionConstraint(550, 0, 0)).to.eql(512);
|
||||||
expect(resolutionConstraint(450, 0)).to.eql(512);
|
expect(resolutionConstraint(450, 0, 0)).to.eql(512);
|
||||||
expect(resolutionConstraint(300, 0)).to.eql(256);
|
expect(resolutionConstraint(300, 0, 0)).to.eql(256);
|
||||||
expect(resolutionConstraint(250, 0)).to.eql(256);
|
expect(resolutionConstraint(250, 0, 0)).to.eql(256);
|
||||||
expect(resolutionConstraint(150, 0)).to.eql(128);
|
expect(resolutionConstraint(150, 0, 0)).to.eql(128);
|
||||||
expect(resolutionConstraint(100, 0)).to.eql(128);
|
expect(resolutionConstraint(100, 0, 0)).to.eql(128);
|
||||||
expect(resolutionConstraint(75, 0)).to.eql(64);
|
expect(resolutionConstraint(75, 0, 0)).to.eql(64);
|
||||||
expect(resolutionConstraint(50, 0)).to.eql(64);
|
expect(resolutionConstraint(50, 0, 0)).to.eql(64);
|
||||||
expect(resolutionConstraint(40, 0)).to.eql(32);
|
expect(resolutionConstraint(40, 0, 0)).to.eql(32);
|
||||||
expect(resolutionConstraint(30, 0)).to.eql(32);
|
expect(resolutionConstraint(30, 0, 0)).to.eql(32);
|
||||||
expect(resolutionConstraint(20, 0)).to.eql(16);
|
expect(resolutionConstraint(20, 0, 0)).to.eql(16);
|
||||||
expect(resolutionConstraint(12, 0)).to.eql(16);
|
expect(resolutionConstraint(12, 0, 0)).to.eql(16);
|
||||||
expect(resolutionConstraint(9, 0)).to.eql(8);
|
expect(resolutionConstraint(9, 0, 0)).to.eql(8);
|
||||||
expect(resolutionConstraint(7, 0)).to.eql(8);
|
expect(resolutionConstraint(7, 0, 0)).to.eql(8);
|
||||||
expect(resolutionConstraint(5, 0)).to.eql(4);
|
expect(resolutionConstraint(5, 0, 0)).to.eql(4);
|
||||||
expect(resolutionConstraint(3.5, 0)).to.eql(4);
|
expect(resolutionConstraint(3.5, 0, 0)).to.eql(4);
|
||||||
expect(resolutionConstraint(2.1, 0)).to.eql(2);
|
expect(resolutionConstraint(2.1, 0, 0)).to.eql(2);
|
||||||
expect(resolutionConstraint(1.9, 0)).to.eql(2);
|
expect(resolutionConstraint(1.9, 0, 0)).to.eql(2);
|
||||||
expect(resolutionConstraint(1.1, 0)).to.eql(1);
|
expect(resolutionConstraint(1.1, 0, 0)).to.eql(1);
|
||||||
expect(resolutionConstraint(0.9, 0)).to.eql(1);
|
expect(resolutionConstraint(0.9, 0, 0)).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction 1', function() {
|
describe('delta 0, direction > 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, 1)).to.eql(1024);
|
expect(resolutionConstraint(1050, 0, 1)).to.eql(1024);
|
||||||
expect(resolutionConstraint(9050, 1)).to.eql(1024);
|
expect(resolutionConstraint(9050, 0, 1)).to.eql(1024);
|
||||||
expect(resolutionConstraint(550, 1)).to.eql(1024);
|
expect(resolutionConstraint(550, 0, 1)).to.eql(1024);
|
||||||
expect(resolutionConstraint(450, 1)).to.eql(512);
|
expect(resolutionConstraint(450, 0, 1)).to.eql(512);
|
||||||
expect(resolutionConstraint(300, 1)).to.eql(512);
|
expect(resolutionConstraint(300, 0, 1)).to.eql(512);
|
||||||
expect(resolutionConstraint(250, 1)).to.eql(256);
|
expect(resolutionConstraint(250, 0, 1)).to.eql(256);
|
||||||
expect(resolutionConstraint(150, 1)).to.eql(256);
|
expect(resolutionConstraint(150, 0, 1)).to.eql(256);
|
||||||
expect(resolutionConstraint(100, 1)).to.eql(128);
|
expect(resolutionConstraint(100, 0, 1)).to.eql(128);
|
||||||
expect(resolutionConstraint(75, 1)).to.eql(128);
|
expect(resolutionConstraint(75, 0, 1)).to.eql(128);
|
||||||
expect(resolutionConstraint(50, 1)).to.eql(64);
|
expect(resolutionConstraint(50, 0, 1)).to.eql(64);
|
||||||
expect(resolutionConstraint(40, 1)).to.eql(64);
|
expect(resolutionConstraint(40, 0, 1)).to.eql(64);
|
||||||
expect(resolutionConstraint(30, 1)).to.eql(32);
|
expect(resolutionConstraint(30, 0, 1)).to.eql(32);
|
||||||
expect(resolutionConstraint(20, 1)).to.eql(32);
|
expect(resolutionConstraint(20, 0, 1)).to.eql(32);
|
||||||
expect(resolutionConstraint(12, 1)).to.eql(16);
|
expect(resolutionConstraint(12, 0, 1)).to.eql(16);
|
||||||
expect(resolutionConstraint(9, 1)).to.eql(16);
|
expect(resolutionConstraint(9, 0, 1)).to.eql(16);
|
||||||
expect(resolutionConstraint(7, 1)).to.eql(8);
|
expect(resolutionConstraint(7, 0, 1)).to.eql(8);
|
||||||
expect(resolutionConstraint(5, 1)).to.eql(8);
|
expect(resolutionConstraint(5, 0, 1)).to.eql(8);
|
||||||
expect(resolutionConstraint(3.5, 1)).to.eql(4);
|
expect(resolutionConstraint(3.5, 0, 1)).to.eql(4);
|
||||||
expect(resolutionConstraint(2.1, 1)).to.eql(4);
|
expect(resolutionConstraint(2.1, 0, 1)).to.eql(4);
|
||||||
expect(resolutionConstraint(1.9, 1)).to.eql(2);
|
expect(resolutionConstraint(1.9, 0, 1)).to.eql(2);
|
||||||
expect(resolutionConstraint(1.1, 1)).to.eql(2);
|
expect(resolutionConstraint(1.1, 0, 1)).to.eql(2);
|
||||||
expect(resolutionConstraint(0.9, 1)).to.eql(1);
|
expect(resolutionConstraint(0.9, 0, 1)).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('direction -1', function() {
|
describe('delta 0, direction < 0', function() {
|
||||||
it('returns expected resolution value', function() {
|
it('returns expected resolution value', function() {
|
||||||
expect(resolutionConstraint(1050, -1)).to.eql(1024);
|
expect(resolutionConstraint(1050, 0, -1)).to.eql(1024);
|
||||||
expect(resolutionConstraint(9050, -1)).to.eql(1024);
|
expect(resolutionConstraint(9050, 0, -1)).to.eql(1024);
|
||||||
expect(resolutionConstraint(550, -1)).to.eql(512);
|
expect(resolutionConstraint(550, 0, -1)).to.eql(512);
|
||||||
expect(resolutionConstraint(450, -1)).to.eql(256);
|
expect(resolutionConstraint(450, 0, -1)).to.eql(256);
|
||||||
expect(resolutionConstraint(300, -1)).to.eql(256);
|
expect(resolutionConstraint(300, 0, -1)).to.eql(256);
|
||||||
expect(resolutionConstraint(250, -1)).to.eql(128);
|
expect(resolutionConstraint(250, 0, -1)).to.eql(128);
|
||||||
expect(resolutionConstraint(150, -1)).to.eql(128);
|
expect(resolutionConstraint(150, 0, -1)).to.eql(128);
|
||||||
expect(resolutionConstraint(100, -1)).to.eql(64);
|
expect(resolutionConstraint(100, 0, -1)).to.eql(64);
|
||||||
expect(resolutionConstraint(75, -1)).to.eql(64);
|
expect(resolutionConstraint(75, 0, -1)).to.eql(64);
|
||||||
expect(resolutionConstraint(50, -1)).to.eql(32);
|
expect(resolutionConstraint(50, 0, -1)).to.eql(32);
|
||||||
expect(resolutionConstraint(40, -1)).to.eql(32);
|
expect(resolutionConstraint(40, 0, -1)).to.eql(32);
|
||||||
expect(resolutionConstraint(30, -1)).to.eql(16);
|
expect(resolutionConstraint(30, 0, -1)).to.eql(16);
|
||||||
expect(resolutionConstraint(20, -1)).to.eql(16);
|
expect(resolutionConstraint(20, 0, -1)).to.eql(16);
|
||||||
expect(resolutionConstraint(12, -1)).to.eql(8);
|
expect(resolutionConstraint(12, 0, -1)).to.eql(8);
|
||||||
expect(resolutionConstraint(9, -1)).to.eql(8);
|
expect(resolutionConstraint(9, 0, -1)).to.eql(8);
|
||||||
expect(resolutionConstraint(7, -1)).to.eql(4);
|
expect(resolutionConstraint(7, 0, -1)).to.eql(4);
|
||||||
expect(resolutionConstraint(5, -1)).to.eql(4);
|
expect(resolutionConstraint(5, 0, -1)).to.eql(4);
|
||||||
expect(resolutionConstraint(3.5, -1)).to.eql(2);
|
expect(resolutionConstraint(3.5, 0, -1)).to.eql(2);
|
||||||
expect(resolutionConstraint(2.1, -1)).to.eql(2);
|
expect(resolutionConstraint(2.1, 0, -1)).to.eql(2);
|
||||||
expect(resolutionConstraint(1.9, -1)).to.eql(1);
|
expect(resolutionConstraint(1.9, 0, -1)).to.eql(1);
|
||||||
expect(resolutionConstraint(1.1, -1)).to.eql(1);
|
expect(resolutionConstraint(1.1, 0, -1)).to.eql(1);
|
||||||
expect(resolutionConstraint(0.9, -1)).to.eql(1);
|
expect(resolutionConstraint(0.9, 0, -1)).to.eql(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('SnapToPower smooth constraint', function() {
|
|
||||||
|
|
||||||
describe('snap to power, smooth constraint on', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createSnapToPower(2, 128, 16, true);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.lessThan(150);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.lessThan(130);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.greaterThan(15);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.greaterThan(10);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('snap to power, smooth constraint off', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createSnapToPower(2, 128, 16, false);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.eql(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('snap to resolutions, smooth constraint on', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createSnapToResolutions([128, 64, 32, 16], true);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.lessThan(150);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.lessThan(130);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.greaterThan(15);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.greaterThan(10);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('snap to resolutions, smooth constraint off', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createSnapToResolutions([128, 64, 32, 16], false);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.eql(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('min/max, smooth constraint on', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createMinMaxResolution(128, 16, true);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.be.lessThan(150);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.greaterThan(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.be.lessThan(130);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.greaterThan(15);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.greaterThan(10);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.be.lessThan(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('min/max, smooth constraint off', function() {
|
|
||||||
it('returns expected resolution value', function() {
|
|
||||||
const resolutionConstraint = createMinMaxResolution(128, 16, false);
|
|
||||||
|
|
||||||
expect(resolutionConstraint(150, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(130, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(128, 0, [100, 100], true)).to.eql(128);
|
|
||||||
expect(resolutionConstraint(16, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(15, 0, [100, 100], true)).to.eql(16);
|
|
||||||
expect(resolutionConstraint(10, 0, [100, 100], true)).to.eql(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,15 +8,27 @@ describe('ol.rotationconstraint', function() {
|
|||||||
it('returns expected rotation value', function() {
|
it('returns expected rotation value', function() {
|
||||||
const rotationConstraint = createSnapToZero(0.3);
|
const rotationConstraint = createSnapToZero(0.3);
|
||||||
|
|
||||||
expect(rotationConstraint(0.1)).to.eql(0);
|
expect(rotationConstraint(0.1, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(0.2)).to.eql(0);
|
expect(rotationConstraint(0.2, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(0.3)).to.eql(0);
|
expect(rotationConstraint(0.3, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(0.4)).to.eql(0.4);
|
expect(rotationConstraint(0.4, 0)).to.eql(0.4);
|
||||||
|
|
||||||
expect(rotationConstraint(-0.1)).to.eql(0);
|
expect(rotationConstraint(-0.1, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.2)).to.eql(0);
|
expect(rotationConstraint(-0.2, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.3)).to.eql(0);
|
expect(rotationConstraint(-0.3, 0)).to.eql(0);
|
||||||
expect(rotationConstraint(-0.4)).to.eql(-0.4);
|
expect(rotationConstraint(-0.4, 0)).to.eql(-0.4);
|
||||||
|
|
||||||
|
expect(rotationConstraint(1, -0.9)).to.eql(0);
|
||||||
|
expect(rotationConstraint(1, -0.8)).to.eql(0);
|
||||||
|
// floating-point arithmetic
|
||||||
|
expect(rotationConstraint(1, -0.7)).not.to.eql(0);
|
||||||
|
expect(rotationConstraint(1, -0.6)).to.eql(0.4);
|
||||||
|
|
||||||
|
expect(rotationConstraint(-1, 0.9)).to.eql(0);
|
||||||
|
expect(rotationConstraint(-1, 0.8)).to.eql(0);
|
||||||
|
// floating-point arithmetic
|
||||||
|
expect(rotationConstraint(-1, 0.7)).not.to.eql(0);
|
||||||
|
expect(rotationConstraint(-1, 0.6)).to.eql(-0.4);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,43 +1,38 @@
|
|||||||
|
import Feature from '../../../src/ol/Feature.js';
|
||||||
import {defaultLoadFunction} from '../../../src/ol/source/VectorTile.js';
|
import {defaultLoadFunction} from '../../../src/ol/source/VectorTile.js';
|
||||||
import VectorTile from '../../../src/ol/VectorTile.js';
|
import VectorTile from '../../../src/ol/VectorTile.js';
|
||||||
import {listen} from '../../../src/ol/events.js';
|
import {listen} from '../../../src/ol/events.js';
|
||||||
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
|
import TextFeature from '../../../src/ol/format/TextFeature.js';
|
||||||
import MVT from '../../../src/ol/format/MVT.js';
|
|
||||||
import {get as getProjection} from '../../../src/ol/proj.js';
|
import {get as getProjection} from '../../../src/ol/proj.js';
|
||||||
import {createXYZ} from '../../../src/ol/tilegrid.js';
|
import Projection from '../../../src/ol/proj/Projection.js';
|
||||||
|
|
||||||
|
|
||||||
describe('ol.VectorTile', function() {
|
describe('ol.VectorTile', function() {
|
||||||
|
|
||||||
it('loader reprojects GeoJSON features', function(done) {
|
it('loader sets features on the tile and updates proj units', function(done) {
|
||||||
const format = new GeoJSON();
|
// mock format that return a tile-pixels feature
|
||||||
|
const format = new TextFeature();
|
||||||
|
format.readProjection = function(source) {
|
||||||
|
return new Projection({
|
||||||
|
code: '',
|
||||||
|
units: 'tile-pixels'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
format.readFeatures = function(source, options) {
|
||||||
|
return [new Feature()];
|
||||||
|
};
|
||||||
|
|
||||||
const tile = new VectorTile([0, 0, 0], null, null, format);
|
const tile = new VectorTile([0, 0, 0], null, null, format);
|
||||||
const url = 'spec/ol/data/point.json';
|
const url = 'spec/ol/data/point.json';
|
||||||
|
|
||||||
defaultLoadFunction(tile, url);
|
defaultLoadFunction(tile, url);
|
||||||
const loader = tile.loader_;
|
const loader = tile.loader_;
|
||||||
listen(tile, 'change', function(e) {
|
listen(tile, 'change', function(e) {
|
||||||
expect(tile.getFeatures()[0].getGeometry().getFlatCoordinates()).to.eql([-9724792.346778862, 4164041.638405114]);
|
expect(tile.getFeatures().length).to.be.greaterThan(0);
|
||||||
|
expect(tile.getProjection().getUnits()).to.be('tile-pixels');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
loader.call(tile, [], 1, getProjection('EPSG:3857'));
|
loader.call(tile, [], 1, getProjection('EPSG:3857'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loader reprojects MVT features', function(done) {
|
|
||||||
const format = new MVT();
|
|
||||||
const tileGrid = createXYZ({
|
|
||||||
tileSize: 512
|
|
||||||
});
|
|
||||||
const tile = new VectorTile([14, 8938, 5680], null, null, format);
|
|
||||||
const url = 'spec/ol/data/14-8938-5680.vector.pbf';
|
|
||||||
defaultLoadFunction(tile, url);
|
|
||||||
const loader = tile.loader_;
|
|
||||||
listen(tile, 'change', function(e) {
|
|
||||||
expect(tile.getFeatures()[1246].getGeometry().getFlatCoordinates()).to.eql([1827804.0218549764, 6144812.116688028]);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
const extent = tileGrid.getTileCoordExtent(tile.tileCoord);
|
|
||||||
loader.call(tile, extent, 1, getProjection('EPSG:3857'));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,36 +42,15 @@ describe('ol.View', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with extent option and center only', function() {
|
|
||||||
it('gives a correct center constraint function', function() {
|
|
||||||
const options = {
|
|
||||||
extent: [0, 0, 1, 1],
|
|
||||||
constrainOnlyCenter: true
|
|
||||||
};
|
|
||||||
const fn = createCenterConstraint(options);
|
|
||||||
expect(fn([0, 0])).to.eql([0, 0]);
|
|
||||||
expect(fn([-10, 0])).to.eql([0, 0]);
|
|
||||||
expect(fn([100, 100])).to.eql([1, 1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with extent option', function() {
|
describe('with extent option', function() {
|
||||||
it('gives a correct center constraint function', function() {
|
it('gives a correct center constraint function', function() {
|
||||||
const options = {
|
const options = {
|
||||||
extent: [0, 0, 1, 1]
|
extent: [0, 0, 1, 1]
|
||||||
};
|
};
|
||||||
const fn = createCenterConstraint(options);
|
const fn = createCenterConstraint(options);
|
||||||
const res = 1;
|
expect(fn([0, 0])).to.eql([0, 0]);
|
||||||
const size = [0.15, 0.1];
|
expect(fn([-10, 0])).to.eql([0, 0]);
|
||||||
expect(fn([0, 0], res, size)).to.eql([0.075, 0.05]);
|
expect(fn([100, 100])).to.eql([1, 1]);
|
||||||
expect(fn([0.5, 0.5], res, size)).to.eql([0.5, 0.5]);
|
|
||||||
expect(fn([10, 10], res, size)).to.eql([0.925, 0.95]);
|
|
||||||
|
|
||||||
const overshootCenter = fn([10, 10], res, size, true);
|
|
||||||
expect(overshootCenter[0] > 0.925).to.eql(true);
|
|
||||||
expect(overshootCenter[1] > 0.95).to.eql(true);
|
|
||||||
expect(overshootCenter[0] < 9).to.eql(true);
|
|
||||||
expect(overshootCenter[1] < 9).to.eql(true);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -239,8 +218,7 @@ describe('ol.View', function() {
|
|||||||
it('works with minResolution and maxResolution', function() {
|
it('works with minResolution and maxResolution', function() {
|
||||||
const constraint = getConstraint({
|
const constraint = getConstraint({
|
||||||
maxResolution: 500,
|
maxResolution: 500,
|
||||||
minResolution: 100,
|
minResolution: 100
|
||||||
constrainResolution: true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(constraint(600, 0, 0)).to.be(500);
|
expect(constraint(600, 0, 0)).to.be(500);
|
||||||
@@ -256,8 +234,7 @@ describe('ol.View', function() {
|
|||||||
const constraint = getConstraint({
|
const constraint = getConstraint({
|
||||||
maxResolution: 500,
|
maxResolution: 500,
|
||||||
minResolution: 1,
|
minResolution: 1,
|
||||||
zoomFactor: 10,
|
zoomFactor: 10
|
||||||
constrainResolution: true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(constraint(1000, 0, 0)).to.be(500);
|
expect(constraint(1000, 0, 0)).to.be(500);
|
||||||
@@ -388,7 +365,6 @@ describe('ol.View', function() {
|
|||||||
it('applies the current resolution if resolution was originally supplied', function() {
|
it('applies the current resolution if resolution was originally supplied', function() {
|
||||||
const view = new View({
|
const view = new View({
|
||||||
center: [0, 0],
|
center: [0, 0],
|
||||||
maxResolution: 2000,
|
|
||||||
resolution: 1000
|
resolution: 1000
|
||||||
});
|
});
|
||||||
view.setResolution(500);
|
view.setResolution(500);
|
||||||
@@ -988,8 +964,7 @@ describe('ol.View', function() {
|
|||||||
let view;
|
let view;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
view = new View({
|
view = new View({
|
||||||
resolutions: [1024, 512, 256, 128, 64, 32, 16, 8],
|
resolutions: [512, 256, 128, 64, 32, 16]
|
||||||
smoothResolutionConstraint: false
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -998,31 +973,30 @@ describe('ol.View', function() {
|
|||||||
expect(view.getZoom()).to.be(undefined);
|
expect(view.getZoom()).to.be(undefined);
|
||||||
|
|
||||||
view.setResolution(513);
|
view.setResolution(513);
|
||||||
expect(view.getZoom()).to.roughlyEqual(Math.log(1024 / 513) / Math.LN2, 1e-9);
|
expect(view.getZoom()).to.roughlyEqual(Math.log(512 / 513) / Math.LN2, 1e-9);
|
||||||
|
|
||||||
view.setResolution(512);
|
view.setResolution(512);
|
||||||
expect(view.getZoom()).to.be(1);
|
expect(view.getZoom()).to.be(0);
|
||||||
|
|
||||||
view.setResolution(100);
|
view.setResolution(100);
|
||||||
expect(view.getZoom()).to.roughlyEqual(3.35614, 1e-5);
|
expect(view.getZoom()).to.roughlyEqual(2.35614, 1e-5);
|
||||||
|
|
||||||
view.setResolution(65);
|
view.setResolution(65);
|
||||||
expect(view.getZoom()).to.roughlyEqual(3.97763, 1e-5);
|
expect(view.getZoom()).to.roughlyEqual(2.97763, 1e-5);
|
||||||
|
|
||||||
view.setResolution(64);
|
view.setResolution(64);
|
||||||
expect(view.getZoom()).to.be(4);
|
expect(view.getZoom()).to.be(3);
|
||||||
|
|
||||||
view.setResolution(16);
|
view.setResolution(16);
|
||||||
expect(view.getZoom()).to.be(6);
|
expect(view.getZoom()).to.be(5);
|
||||||
|
|
||||||
view.setResolution(15);
|
view.setResolution(15);
|
||||||
expect(view.getZoom()).to.roughlyEqual(Math.log(1024 / 15) / Math.LN2, 1e-9);
|
expect(view.getZoom()).to.roughlyEqual(Math.log(512 / 15) / Math.LN2, 1e-9);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('works for resolution arrays with variable zoom factors', function() {
|
it('works for resolution arrays with variable zoom factors', function() {
|
||||||
const view = new View({
|
const view = new View({
|
||||||
resolutions: [10, 5, 2, 1],
|
resolutions: [10, 5, 2, 1]
|
||||||
smoothResolutionConstraint: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
view.setZoom(1);
|
view.setZoom(1);
|
||||||
@@ -1047,8 +1021,7 @@ describe('ol.View', function() {
|
|||||||
it('returns correct zoom levels', function() {
|
it('returns correct zoom levels', function() {
|
||||||
const view = new View({
|
const view = new View({
|
||||||
minZoom: 10,
|
minZoom: 10,
|
||||||
maxZoom: 20,
|
maxZoom: 20
|
||||||
smoothResolutionConstraint: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
view.setZoom(5);
|
view.setZoom(5);
|
||||||
@@ -1124,16 +1097,12 @@ describe('ol.View', function() {
|
|||||||
describe('#getResolutionForZoom', function() {
|
describe('#getResolutionForZoom', function() {
|
||||||
|
|
||||||
it('returns correct zoom resolution', function() {
|
it('returns correct zoom resolution', function() {
|
||||||
const view = new View({
|
const view = new View();
|
||||||
smoothResolutionConstraint: false
|
|
||||||
});
|
|
||||||
const max = view.getMaxZoom();
|
const max = view.getMaxZoom();
|
||||||
const min = view.getMinZoom();
|
const min = view.getMinZoom();
|
||||||
|
|
||||||
expect(view.getResolutionForZoom(max)).to.be(view.getMinResolution());
|
expect(view.getResolutionForZoom(max)).to.be(view.getMinResolution());
|
||||||
expect(view.getResolutionForZoom(max + 1)).to.be(view.getMinResolution() / 2);
|
|
||||||
expect(view.getResolutionForZoom(min)).to.be(view.getMaxResolution());
|
expect(view.getResolutionForZoom(min)).to.be(view.getMaxResolution());
|
||||||
expect(view.getResolutionForZoom(min - 1)).to.be(view.getMaxResolution() * 2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns correct zoom levels for specifically configured resolutions', function() {
|
it('returns correct zoom levels for specifically configured resolutions', function() {
|
||||||
@@ -1141,30 +1110,11 @@ describe('ol.View', function() {
|
|||||||
resolutions: [10, 8, 6, 4, 2]
|
resolutions: [10, 8, 6, 4, 2]
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(view.getResolutionForZoom(-1)).to.be(10);
|
|
||||||
expect(view.getResolutionForZoom(0)).to.be(10);
|
expect(view.getResolutionForZoom(0)).to.be(10);
|
||||||
expect(view.getResolutionForZoom(1)).to.be(8);
|
expect(view.getResolutionForZoom(1)).to.be(8);
|
||||||
expect(view.getResolutionForZoom(2)).to.be(6);
|
expect(view.getResolutionForZoom(2)).to.be(6);
|
||||||
expect(view.getResolutionForZoom(3)).to.be(4);
|
expect(view.getResolutionForZoom(3)).to.be(4);
|
||||||
expect(view.getResolutionForZoom(4)).to.be(2);
|
expect(view.getResolutionForZoom(4)).to.be(2);
|
||||||
expect(view.getResolutionForZoom(5)).to.be(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns correct zoom levels for resolutions with variable zoom levels', function() {
|
|
||||||
const view = new View({
|
|
||||||
resolutions: [50, 10, 5, 2.5, 1.25, 0.625]
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(view.getResolutionForZoom(-1)).to.be(50);
|
|
||||||
expect(view.getResolutionForZoom(0)).to.be(50);
|
|
||||||
expect(view.getResolutionForZoom(0.5)).to.be(50 / Math.pow(5, 0.5));
|
|
||||||
expect(view.getResolutionForZoom(1)).to.be(10);
|
|
||||||
expect(view.getResolutionForZoom(2)).to.be(5);
|
|
||||||
expect(view.getResolutionForZoom(2.75)).to.be(5 / Math.pow(2, 0.75));
|
|
||||||
expect(view.getResolutionForZoom(3)).to.be(2.5);
|
|
||||||
expect(view.getResolutionForZoom(4)).to.be(1.25);
|
|
||||||
expect(view.getResolutionForZoom(5)).to.be(0.625);
|
|
||||||
expect(view.getResolutionForZoom(6)).to.be(0.625);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -1296,14 +1246,8 @@ describe('ol.View', function() {
|
|||||||
document.body.removeChild(target);
|
document.body.removeChild(target);
|
||||||
});
|
});
|
||||||
it('calculates the size correctly', function() {
|
it('calculates the size correctly', function() {
|
||||||
let size = map.getView().getSizeFromViewport_();
|
const size = map.getView().getSizeFromViewport_();
|
||||||
expect(size).to.eql([200, 150]);
|
expect(size).to.eql([200, 150]);
|
||||||
size = map.getView().getSizeFromViewport_(Math.PI / 2);
|
|
||||||
expect(size[0]).to.roughlyEqual(150, 1e-9);
|
|
||||||
expect(size[1]).to.roughlyEqual(200, 1e-9);
|
|
||||||
size = map.getView().getSizeFromViewport_(Math.PI);
|
|
||||||
expect(size[0]).to.roughlyEqual(200, 1e-9);
|
|
||||||
expect(size[1]).to.roughlyEqual(150, 1e-9);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1334,40 +1278,14 @@ describe('ol.View', function() {
|
|||||||
zoom: 5
|
zoom: 5
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('fits correctly to the geometry (with unconstrained resolution)', function() {
|
it('fits correctly to the geometry', function() {
|
||||||
view.fit(
|
view.fit(
|
||||||
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
||||||
{size: [200, 200], padding: [100, 0, 0, 100]});
|
{size: [200, 200], padding: [100, 0, 0, 100], constrainResolution: false});
|
||||||
expect(view.getResolution()).to.be(11);
|
expect(view.getResolution()).to.be(11);
|
||||||
expect(view.getCenter()[0]).to.be(5950);
|
expect(view.getCenter()[0]).to.be(5950);
|
||||||
expect(view.getCenter()[1]).to.be(47100);
|
expect(view.getCenter()[1]).to.be(47100);
|
||||||
|
|
||||||
view.fit(
|
|
||||||
new Circle([6000, 46000], 1000),
|
|
||||||
{size: [200, 200]});
|
|
||||||
expect(view.getResolution()).to.be(10);
|
|
||||||
expect(view.getCenter()[0]).to.be(6000);
|
|
||||||
expect(view.getCenter()[1]).to.be(46000);
|
|
||||||
|
|
||||||
view.setRotation(Math.PI / 8);
|
|
||||||
view.fit(
|
|
||||||
new Circle([6000, 46000], 1000),
|
|
||||||
{size: [200, 200]});
|
|
||||||
expect(view.getResolution()).to.roughlyEqual(10, 1e-9);
|
|
||||||
expect(view.getCenter()[0]).to.roughlyEqual(6000, 1e-9);
|
|
||||||
expect(view.getCenter()[1]).to.roughlyEqual(46000, 1e-9);
|
|
||||||
|
|
||||||
view.setRotation(Math.PI / 4);
|
|
||||||
view.fit(
|
|
||||||
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
|
||||||
{size: [200, 200], padding: [100, 0, 0, 100]});
|
|
||||||
expect(view.getResolution()).to.roughlyEqual(14.849242404917458, 1e-9);
|
|
||||||
expect(view.getCenter()[0]).to.roughlyEqual(5200, 1e-9);
|
|
||||||
expect(view.getCenter()[1]).to.roughlyEqual(46300, 1e-9);
|
|
||||||
});
|
|
||||||
it('fits correctly to the geometry', function() {
|
|
||||||
view.setConstrainResolution(true);
|
|
||||||
|
|
||||||
view.fit(
|
view.fit(
|
||||||
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
||||||
{size: [200, 200], padding: [100, 0, 0, 100]});
|
{size: [200, 200], padding: [100, 0, 0, 100]});
|
||||||
@@ -1396,8 +1314,30 @@ describe('ol.View', function() {
|
|||||||
expect(view.getZoom()).to.be(6);
|
expect(view.getZoom()).to.be(6);
|
||||||
expect(view.getCenter()[0]).to.be(5900);
|
expect(view.getCenter()[0]).to.be(5900);
|
||||||
expect(view.getCenter()[1]).to.be(46100);
|
expect(view.getCenter()[1]).to.be(46100);
|
||||||
});
|
|
||||||
|
|
||||||
|
view.fit(
|
||||||
|
new Circle([6000, 46000], 1000),
|
||||||
|
{size: [200, 200], constrainResolution: false});
|
||||||
|
expect(view.getResolution()).to.be(10);
|
||||||
|
expect(view.getCenter()[0]).to.be(6000);
|
||||||
|
expect(view.getCenter()[1]).to.be(46000);
|
||||||
|
|
||||||
|
view.setRotation(Math.PI / 8);
|
||||||
|
view.fit(
|
||||||
|
new Circle([6000, 46000], 1000),
|
||||||
|
{size: [200, 200], constrainResolution: false});
|
||||||
|
expect(view.getResolution()).to.roughlyEqual(10, 1e-9);
|
||||||
|
expect(view.getCenter()[0]).to.roughlyEqual(6000, 1e-9);
|
||||||
|
expect(view.getCenter()[1]).to.roughlyEqual(46000, 1e-9);
|
||||||
|
|
||||||
|
view.setRotation(Math.PI / 4);
|
||||||
|
view.fit(
|
||||||
|
new LineString([[6000, 46000], [6000, 47100], [7000, 46000]]),
|
||||||
|
{size: [200, 200], padding: [100, 0, 0, 100], constrainResolution: false});
|
||||||
|
expect(view.getResolution()).to.roughlyEqual(14.849242404917458, 1e-9);
|
||||||
|
expect(view.getCenter()[0]).to.roughlyEqual(5200, 1e-9);
|
||||||
|
expect(view.getCenter()[1]).to.roughlyEqual(46300, 1e-9);
|
||||||
|
});
|
||||||
it('fits correctly to the extent', function() {
|
it('fits correctly to the extent', function() {
|
||||||
view.fit([1000, 1000, 2000, 2000], {size: [200, 200]});
|
view.fit([1000, 1000, 2000, 2000], {size: [200, 200]});
|
||||||
expect(view.getResolution()).to.be(5);
|
expect(view.getResolution()).to.be(5);
|
||||||
@@ -1420,6 +1360,7 @@ describe('ol.View', function() {
|
|||||||
{
|
{
|
||||||
size: [200, 200],
|
size: [200, 200],
|
||||||
padding: [100, 0, 0, 100],
|
padding: [100, 0, 0, 100],
|
||||||
|
constrainResolution: false,
|
||||||
duration: 25
|
duration: 25
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1481,235 +1422,6 @@ describe('ol.View', function() {
|
|||||||
expect(view.getCenter()[1]).to.roughlyEqual(46000, 1e-9);
|
expect(view.getCenter()[1]).to.roughlyEqual(46000, 1e-9);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#beginInteraction() and endInteraction()', function() {
|
|
||||||
let view;
|
|
||||||
beforeEach(function() {
|
|
||||||
view = new View();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('correctly changes the view hint', function() {
|
|
||||||
view.beginInteraction();
|
|
||||||
expect(view.getHints()[1]).to.be(1);
|
|
||||||
view.beginInteraction();
|
|
||||||
expect(view.getHints()[1]).to.be(2);
|
|
||||||
view.endInteraction();
|
|
||||||
view.endInteraction();
|
|
||||||
expect(view.getHints()[1]).to.be(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#getConstrainedZoom()', function() {
|
|
||||||
let view;
|
|
||||||
|
|
||||||
it('works correctly without constraint', function() {
|
|
||||||
view = new View({
|
|
||||||
zoom: 0
|
|
||||||
});
|
|
||||||
expect(view.getConstrainedZoom(3)).to.be(3);
|
|
||||||
});
|
|
||||||
it('works correctly with resolution constraints', function() {
|
|
||||||
view = new View({
|
|
||||||
zoom: 4,
|
|
||||||
minZoom: 4,
|
|
||||||
maxZoom: 8
|
|
||||||
});
|
|
||||||
expect(view.getConstrainedZoom(3)).to.be(4);
|
|
||||||
expect(view.getConstrainedZoom(10)).to.be(8);
|
|
||||||
});
|
|
||||||
it('works correctly with a specific resolution set', function() {
|
|
||||||
view = new View({
|
|
||||||
zoom: 0,
|
|
||||||
resolutions: [512, 256, 128, 64, 32, 16, 8]
|
|
||||||
});
|
|
||||||
expect(view.getConstrainedZoom(0)).to.be(0);
|
|
||||||
expect(view.getConstrainedZoom(4)).to.be(4);
|
|
||||||
expect(view.getConstrainedZoom(8)).to.be(6);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#getConstrainedResolution()', function() {
|
|
||||||
let view;
|
|
||||||
const defaultMaxRes = 156543.03392804097;
|
|
||||||
|
|
||||||
it('works correctly by snapping to power of 2', function() {
|
|
||||||
view = new View();
|
|
||||||
expect(view.getConstrainedResolution(1000000)).to.be(defaultMaxRes);
|
|
||||||
expect(view.getConstrainedResolution(defaultMaxRes / 8)).to.be(defaultMaxRes / 8);
|
|
||||||
});
|
|
||||||
it('works correctly by snapping to a custom zoom factor', function() {
|
|
||||||
view = new View({
|
|
||||||
maxResolution: 2500,
|
|
||||||
zoomFactor: 5,
|
|
||||||
maxZoom: 4,
|
|
||||||
constrainResolution: true
|
|
||||||
});
|
|
||||||
expect(view.getConstrainedResolution(90, 1)).to.be(100);
|
|
||||||
expect(view.getConstrainedResolution(90, -1)).to.be(20);
|
|
||||||
expect(view.getConstrainedResolution(20)).to.be(20);
|
|
||||||
expect(view.getConstrainedResolution(5)).to.be(4);
|
|
||||||
expect(view.getConstrainedResolution(1)).to.be(4);
|
|
||||||
});
|
|
||||||
it('works correctly with a specific resolution set', function() {
|
|
||||||
view = new View({
|
|
||||||
zoom: 0,
|
|
||||||
resolutions: [512, 256, 128, 64, 32, 16, 8],
|
|
||||||
constrainResolution: true
|
|
||||||
});
|
|
||||||
expect(view.getConstrainedResolution(1000, 1)).to.be(512);
|
|
||||||
expect(view.getConstrainedResolution(260, 1)).to.be(512);
|
|
||||||
expect(view.getConstrainedResolution(260)).to.be(256);
|
|
||||||
expect(view.getConstrainedResolution(30)).to.be(32);
|
|
||||||
expect(view.getConstrainedResolution(30, -1)).to.be(16);
|
|
||||||
expect(view.getConstrainedResolution(4, -1)).to.be(8);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#adjustRotation()', function() {
|
|
||||||
it('changes view rotation with anchor', function() {
|
|
||||||
const view = new View({
|
|
||||||
resolution: 1,
|
|
||||||
center: [0, 0]
|
|
||||||
});
|
|
||||||
|
|
||||||
view.adjustRotation(Math.PI / 2);
|
|
||||||
expect(view.getRotation()).to.be(Math.PI / 2);
|
|
||||||
expect(view.getCenter()).to.eql([0, 0]);
|
|
||||||
|
|
||||||
view.adjustRotation(-Math.PI);
|
|
||||||
expect(view.getRotation()).to.be(-Math.PI / 2);
|
|
||||||
expect(view.getCenter()).to.eql([0, 0]);
|
|
||||||
|
|
||||||
view.adjustRotation(Math.PI / 3, [50, 0]);
|
|
||||||
expect(view.getRotation()).to.roughlyEqual(-Math.PI / 6, 1e-9);
|
|
||||||
expect(view.getCenter()[0]).to.roughlyEqual(50 * (1 - Math.cos(Math.PI / 3)), 1e-9);
|
|
||||||
expect(view.getCenter()[1]).to.roughlyEqual(-50 * Math.sin(Math.PI / 3), 1e-9);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not change view parameters if rotation is disabled', function() {
|
|
||||||
const view = new View({
|
|
||||||
resolution: 1,
|
|
||||||
enableRotation: false,
|
|
||||||
center: [0, 0]
|
|
||||||
});
|
|
||||||
|
|
||||||
view.adjustRotation(Math.PI / 2);
|
|
||||||
expect(view.getRotation()).to.be(0);
|
|
||||||
expect(view.getCenter()).to.eql([0, 0]);
|
|
||||||
|
|
||||||
view.adjustRotation(-Math.PI * 3, [-50, 0]);
|
|
||||||
expect(view.getRotation()).to.be(0);
|
|
||||||
expect(view.getCenter()).to.eql([0, 0]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#adjustZoom()', function() {
|
|
||||||
|
|
||||||
it('changes view resolution', function() {
|
|
||||||
const view = new View({
|
|
||||||
resolution: 1,
|
|
||||||
resolutions: [4, 2, 1, 0.5, 0.25]
|
|
||||||
});
|
|
||||||
|
|
||||||
view.adjustZoom(1);
|
|
||||||
expect(view.getResolution()).to.be(0.5);
|
|
||||||
|
|
||||||
view.adjustZoom(-1);
|
|
||||||
expect(view.getResolution()).to.be(1);
|
|
||||||
|
|
||||||
view.adjustZoom(2);
|
|
||||||
expect(view.getResolution()).to.be(0.25);
|
|
||||||
|
|
||||||
view.adjustZoom(-2);
|
|
||||||
expect(view.getResolution()).to.be(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('changes view resolution and center relative to the anchor', function() {
|
|
||||||
const view = new View({
|
|
||||||
center: [0, 0],
|
|
||||||
resolution: 1,
|
|
||||||
resolutions: [4, 2, 1, 0.5, 0.25]
|
|
||||||
});
|
|
||||||
|
|
||||||
view.adjustZoom(1, [10, 10]);
|
|
||||||
expect(view.getCenter()).to.eql([5, 5]);
|
|
||||||
|
|
||||||
view.adjustZoom(-1, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([10, 10]);
|
|
||||||
|
|
||||||
view.adjustZoom(2, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
|
||||||
|
|
||||||
view.adjustZoom(-2, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([10, 10]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('changes view resolution and center relative to the anchor, while respecting the extent (center only)', function() {
|
|
||||||
const view = new View({
|
|
||||||
center: [0, 0],
|
|
||||||
extent: [-2.5, -2.5, 2.5, 2.5],
|
|
||||||
constrainOnlyCenter: true,
|
|
||||||
resolution: 1,
|
|
||||||
resolutions: [4, 2, 1, 0.5, 0.25]
|
|
||||||
});
|
|
||||||
|
|
||||||
view.adjustZoom(1, [10, 10]);
|
|
||||||
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
|
||||||
|
|
||||||
view.adjustZoom(-1, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
|
||||||
|
|
||||||
view.adjustZoom(2, [10, 10]);
|
|
||||||
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
|
||||||
|
|
||||||
view.adjustZoom(-2, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([2.5, 2.5]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('changes view resolution and center relative to the anchor, while respecting the extent', function() {
|
|
||||||
const map = new Map({});
|
|
||||||
const view = new View({
|
|
||||||
center: [50, 50],
|
|
||||||
extent: [0, 0, 100, 100],
|
|
||||||
resolution: 1,
|
|
||||||
resolutions: [4, 2, 1, 0.5, 0.25, 0.125]
|
|
||||||
});
|
|
||||||
map.setView(view);
|
|
||||||
|
|
||||||
view.adjustZoom(1, [100, 100]);
|
|
||||||
expect(view.getCenter()).to.eql([75, 75]);
|
|
||||||
|
|
||||||
view.adjustZoom(-1, [75, 75]);
|
|
||||||
expect(view.getCenter()).to.eql([50, 50]);
|
|
||||||
|
|
||||||
view.adjustZoom(2, [100, 100]);
|
|
||||||
expect(view.getCenter()).to.eql([87.5, 87.5]);
|
|
||||||
|
|
||||||
view.adjustZoom(-3, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([50, 50]);
|
|
||||||
expect(view.getResolution()).to.eql(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('changes view resolution and center relative to the anchor, while respecting the extent (rotated)', function() {
|
|
||||||
const map = new Map({});
|
|
||||||
const view = new View({
|
|
||||||
center: [50, 50],
|
|
||||||
extent: [-100, -100, 100, 100],
|
|
||||||
resolution: 1,
|
|
||||||
resolutions: [2, 1, 0.5, 0.25, 0.125],
|
|
||||||
rotation: Math.PI / 4
|
|
||||||
});
|
|
||||||
map.setView(view);
|
|
||||||
const halfSize = 100 * Math.SQRT1_2;
|
|
||||||
|
|
||||||
view.adjustZoom(1, [100, 100]);
|
|
||||||
expect(view.getCenter()).to.eql([100 - halfSize / 2, 100 - halfSize / 2]);
|
|
||||||
|
|
||||||
view.setCenter([0, 50]);
|
|
||||||
view.adjustZoom(-1, [0, 0]);
|
|
||||||
expect(view.getCenter()).to.eql([0, 100 - halfSize]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ol.View.isNoopAnimation()', function() {
|
describe('ol.View.isNoopAnimation()', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user