View / add support for viewport extent constraint

This introduces a breaking change:

The `extent` view option now constrains the whole viewport and not just the
view center.
The option `constrainOnlyCenter` was added to keep the previous behaviour.

Constraining the whole viewport and not only the view center means
that the center and resolution constraints must be applied with a knowledge of
the viewport size.
This commit is contained in:
Olivier Guyot
2019-01-14 13:36:20 +01:00
parent e52fab636c
commit 1f379a06a4
8 changed files with 128 additions and 28 deletions

View File

@@ -3,34 +3,47 @@
*/
import {linearFindNearest} from './array.js';
import {clamp} from './math.js';
import {getHeight, getWidth} from './extent';
/**
* @typedef {function((number|undefined), number, number): (number|undefined)} Type
* @typedef {function((number|undefined), number, number, import("./size.js").Size, boolean=): (number|undefined)} Type
*/
/**
* @param {Array<number>} resolutions Resolutions.
* @param {import("./extent.js").Extent=} opt_maxExtent Maximum allowed extent.
* @return {Type} Zoom function.
*/
export function createSnapToResolutions(resolutions) {
export function createSnapToResolutions(resolutions, opt_maxExtent) {
return (
/**
* @param {number|undefined} resolution Resolution.
* @param {number} delta Delta.
* @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, delta, direction, opt_isMoving) {
function(resolution, delta, direction, size, opt_isMoving) {
if (resolution !== undefined) {
let cappedRes = resolution;
// apply constraint related to max extent
if (opt_maxExtent) {
const xResolution = getWidth(opt_maxExtent) / size[0];
const yResolution = getHeight(opt_maxExtent) / size[1];
cappedRes = Math.min(cappedRes, Math.min(xResolution, yResolution));
}
// during interacting or animating, allow intermediary values
if (opt_isMoving) {
// TODO: actually take delta and direction into account
return resolution;
return Math.min(resolution, cappedRes);
}
let z = linearFindNearest(resolutions, resolution, direction);
let z = linearFindNearest(resolutions, cappedRes, direction);
z = clamp(z + delta, 0, resolutions.length - 1);
const index = Math.floor(z);
if (z != index && index < resolutions.length - 1) {
@@ -51,27 +64,39 @@ export function createSnapToResolutions(resolutions) {
* @param {number} power Power.
* @param {number} maxResolution Maximum resolution.
* @param {number=} opt_maxLevel Maximum level.
* @param {import("./extent.js").Extent=} opt_maxExtent Maximum allowed extent.
* @return {Type} Zoom function.
*/
export function createSnapToPower(power, maxResolution, opt_maxLevel) {
export function createSnapToPower(power, maxResolution, opt_maxLevel, opt_maxExtent) {
return (
/**
* @param {number|undefined} resolution Resolution.
* @param {number} delta Delta.
* @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, delta, direction, opt_isMoving) {
function(resolution, delta, direction, size, opt_isMoving) {
if (resolution !== undefined) {
let cappedRes = resolution;
// apply constraint related to max extent
if (opt_maxExtent) {
const xResolution = getWidth(opt_maxExtent) / size[0];
const yResolution = getHeight(opt_maxExtent) / size[1];
cappedRes = Math.min(cappedRes, Math.min(xResolution, yResolution));
}
// during interacting or animating, allow intermediary values
if (opt_isMoving) {
// TODO: actually take delta and direction into account
return resolution;
return Math.min(resolution, cappedRes);
}
const offset = -direction / 2 + 0.5;
const oldLevel = Math.floor(
Math.log(maxResolution / resolution) / Math.log(power) + offset);
Math.log(maxResolution / cappedRes) / Math.log(power) + offset);
let newLevel = Math.max(oldLevel + delta, 0);
if (opt_maxLevel !== undefined) {
newLevel = Math.min(newLevel, opt_maxLevel);