diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index b03d2f346a..b6efd1b675 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -4,6 +4,24 @@ #### 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 The `inherits` function that was used to inherit the prototype methods from one constructor into another has been removed. diff --git a/examples/interaction-options.html b/examples/interaction-options.html index 8c07ee8505..b0be6f0d4b 100644 --- a/examples/interaction-options.html +++ b/examples/interaction-options.html @@ -4,16 +4,11 @@ title: Interaction Options shortdesc: Shows interaction options for custom scroll and zoom behavior. docs: > This example uses a custom `ol/interaction/defaults` configuration: - - * 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 - 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 - 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`. + 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 + 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 + with a `tabindex` attribute set. tags: "trackpad, mousewheel, zoom, scroll, interaction, fractional" ---
diff --git a/examples/pinch-zoom.html b/examples/pinch-zoom.html index ab61eef6fc..e955ad7dac 100644 --- a/examples/pinch-zoom.html +++ b/examples/pinch-zoom.html @@ -5,7 +5,7 @@ shortdesc: Restrict pinch zooming to integer zoom levels. docs: > 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 - constrainResolution: true when constructing the interaction. + constrainResolution: true when constructing the view. tags: "pinch, zoom, interaction" ---
diff --git a/src/ol/View.js b/src/ol/View.js index 2bfe5d9592..6a73338a3d 100644 --- a/src/ol/View.js +++ b/src/ol/View.js @@ -94,12 +94,12 @@ import {createMinMaxResolution} from './resolutionconstraint'; * used. The `constrainRotation` option has no effect if `enableRotation` is * `false`. * @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 - * @property {boolean} [constrainOnlyCenter] If true, the extent - * constraint will only apply to the center and not the whole view. - * @property {boolean} [smoothExtentConstraint] If true, the extent - * constraint will be applied smoothly, i. e. allow the view to go slightly outside - * of the given `extent`. Default is true. + * view, in other words, nothing outside of this extent can be visible on the map. + * @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 * the resolution constraint. It is used together with `minResolution` (or * `maxZoom`) and `zoomFactor`. If unspecified it is calculated in such a way @@ -120,12 +120,12 @@ import {createMinMaxResolution} from './resolutionconstraint'; * resolution constraint. It is used together with `maxZoom` (or * `minResolution`) and `zoomFactor`. Note that if `maxResolution` is also * provided, it is given precedence over `minZoom`. - * @property {boolean} [constrainResolution] If true, the view will always + * @property {boolean} [constrainResolution=false] If true, the view will always * animate to the closest zoom level after an interaction; false means - * intermediary zoom levels are allowed. Default is false. - * @property {boolean} [smoothResolutionConstraint] If true, the resolution + * 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. Default is true. + * the given resolution or zoom bounds. * @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] The * projection. The default is Spherical Mercator. * @property {number} [resolution] The initial resolution for the view. The @@ -139,10 +139,9 @@ import {createMinMaxResolution} from './resolutionconstraint'; * @property {number} [rotation=0] The initial rotation for the view in radians * (positive rotation clockwise, 0 means North). * @property {number} [zoom] Only used if `resolution` is not defined. Zoom - * level used to calculate the initial resolution for the view. The initial - * resolution is determined using the {@link #constrainResolution} method. - * @property {number} [zoomFactor=2] The zoom factor used to determine the - * resolution constraint. + * level used to calculate the initial resolution for the view. + * @property {number} [zoomFactor=2] The zoom factor used to compute the + * corresponding resolution. */ @@ -156,7 +155,7 @@ import {createMinMaxResolution} from './resolutionconstraint'; * 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 * the animation. - * @property {import("./coordinate.js").Coordinate} [anchor] Optional anchor to remained fixed + * @property {import("./coordinate.js").Coordinate} [anchor] Optional anchor to remain fixed * during a rotation or resolution animation. * @property {number} [duration=1000] The duration of the animation in milliseconds. * @property {function(number):number} [easing] The easing function used @@ -197,7 +196,12 @@ const DEFAULT_MIN_ZOOM = 0; * and `rotation`. Each state has a corresponding getter and setter, e.g. * `getCenter` and `setCenter` for the `center` state. * - * An View has a `projection`. The projection determines the + * The `zoom` state is actually not saved on the view: all computations + * 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 * resolution (projection units per pixel). The default projection is * Spherical Mercator (EPSG:3857). @@ -205,28 +209,19 @@ const DEFAULT_MIN_ZOOM = 0; * ### The constraints * * `setCenter`, `setResolution` and `setRotation` can be used to change the - * states of the view. Any value can be passed to the setters. And the value - * that is passed to a setter will effectively be the value set in the view, - * and returned by the corresponding getter. + * states of the view, but any constraint defined in the constructor will + * be applied along the way. * - * But a View object also has a *resolution constraint*, a - * *rotation constraint* and a *center constraint*. + * A View object can have a *resolution constraint*, a *rotation constraint* + * and a *center constraint*. * - * As said above, no constraints are applied when the setters are used to set - * new states for the view. Applying constraints is done explicitly through - * the use of the `constrain*` functions (`constrainResolution` and - * `constrainRotation` and `constrainCenter`). - * - * The main users of the constraints are the interactions and the - * 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 *resolution constraint* typically restricts min/max values and + * 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. By default, the view + * only has a min/max restriction and allow intermediary zoom levels when + * pinch-zooming for example. * * The *rotation constraint* snaps to specific angles. It is determined * by the following options: `enableRotation` and `constrainRotation`. @@ -234,9 +229,31 @@ const DEFAULT_MIN_ZOOM = 0; * horizontal. * * The *center constraint* is determined by the `extent` option. By - * default the center is not constrained at all. + * default the view center is not constrained at all. * - * @api + * ### 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 */ class View extends BaseObject { @@ -926,9 +943,9 @@ class View extends BaseObject { } /** - * Get the current zoom level. If you configured your view with a resolutions - * array (this is rare), this method may return non-integer zoom levels (so - * the zoom level is not safe to use as an index into a resolutions array). + * Get the current zoom level. This method may return non-integer zoom levels + * if the view does not constrain the resolution, or if an interaction or + * animation is underway. * @return {number|undefined} Zoom. * @api */ @@ -1115,7 +1132,7 @@ class View extends BaseObject { } /** - * Adds relative coordinates to the center of the view. + * Adds relative coordinates to the center of the view. Any extent constraint will apply. * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add. * @api */ @@ -1125,7 +1142,8 @@ class View extends BaseObject { } /** - * Multiply the view resolution by a ratio, optionally using an anchor. + * 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 @@ -1145,7 +1163,8 @@ class View extends BaseObject { } /** - * Adds a value to the view zoom level, optionally using an anchor. + * 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 @@ -1155,7 +1174,8 @@ class View extends BaseObject { } /** - * Adds a value to the view rotation, optionally using an 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. * @observable @@ -1172,7 +1192,7 @@ class View extends BaseObject { } /** - * Set the center of the current view. + * Set the center of the current view. Any extent constraint will apply. * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view. * @observable * @api @@ -1194,7 +1214,7 @@ class View extends BaseObject { } /** - * Set the resolution for this view. + * Set the resolution for this view. Any resolution constraint will apply. * @param {number|undefined} resolution The resolution of the view. * @observable * @api @@ -1205,7 +1225,7 @@ class View extends BaseObject { } /** - * Set the rotation for this view using an anchor. + * Set the rotation for this view. Any rotation constraint will apply. * @param {number} rotation The rotation of the view in radians. * @observable * @api @@ -1216,7 +1236,7 @@ class View extends BaseObject { } /** - * Zoom to a specific zoom level using an anchor + * Zoom to a specific zoom level. Any resolution constrain will apply. * @param {number} zoom Zoom level. * @api */ @@ -1261,7 +1281,6 @@ class View extends BaseObject { * This is typically done on interaction end. * @param {number=} opt_duration The animation duration in ms. * @param {number=} opt_resolutionDirection Which direction to zoom. - * @observable * @private */ resolveConstraints_(opt_duration, opt_resolutionDirection) { @@ -1301,7 +1320,8 @@ class View extends BaseObject { } /** - * Notify the View that an interaction has ended. + * 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. * @api