From 142424960dc02f740400099cbebadcc33c7c14ab Mon Sep 17 00:00:00 2001 From: Lars Maxfield <83759569+larsmaxfield@users.noreply.github.com> Date: Mon, 26 Aug 2024 16:52:35 +0200 Subject: [PATCH 01/17] Temporary ignore local data --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bb99e96551..25b3847b47 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ npm-debug.log /.vs/ .*.swp junit.xml + +/test/data From b3eb99c2459b3a84a7761939cbbc62ca83fdc606 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Mon, 26 Aug 2024 17:19:37 +0200 Subject: [PATCH 02/17] Allow underzooming when renderWorldCopies = false whereby minZoom dictates the zoom-out limit --- src/geo/transform.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index b5cae07634..1c77d58d3d 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -787,7 +787,7 @@ export class Transform { let scaleX = 0; const {x: screenWidth, y: screenHeight} = this.size; - if (this.latRange) { + if (this.latRange && this._renderWorldCopies) { const latRange = this.latRange; minY = mercatorYfromLat(latRange[1]) * worldSize; maxY = mercatorYfromLat(latRange[0]) * worldSize; @@ -795,7 +795,7 @@ export class Transform { if (shouldZoomIn) scaleY = screenHeight / (maxY - minY); } - if (lngRange) { + if (lngRange && this._renderWorldCopies) { minX = wrap( mercatorXfromLng(lngRange[0]) * worldSize, 0, @@ -820,16 +820,20 @@ export class Transform { if (scale) { // zoom in to exclude all beyond the given lng/lat ranges - const newPoint = new Point( - scaleX ? (maxX + minX) / 2 : originalX, - scaleY ? (maxY + minY) / 2 : originalY); + const pointX = !this._renderWorldCopies + ? originalX + : scaleX ? (maxX + minX) / 2 : originalX; + const pointY = !this._renderWorldCopies + ? originalY + : scaleY ? (maxY + minY) / 2 : originalY; + const newPoint = new Point(pointX, pointY); result.center = this.unproject.call({worldSize}, newPoint).wrap(); result.zoom += this.scaleZoom(scale); return result; } if (this.latRange) { - const h2 = screenHeight / 2; + const h2 = !this._renderWorldCopies ? 1e-10 : screenHeight / 2; if (originalY - h2 < minY) modifiedY = minY + h2; if (originalY + h2 > maxY) modifiedY = maxY - h2; } @@ -840,7 +844,7 @@ export class Transform { if (this._renderWorldCopies) { wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2); } - const w2 = screenWidth / 2; + const w2 = !this._renderWorldCopies ? 1e-10 : screenWidth / 2; if (wrappedX - w2 < minX) modifiedX = minX + w2; if (wrappedX + w2 > maxX) modifiedX = maxX - w2; From 87ce80cae17b23b75210eaca9a637c952d233071 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Mon, 26 Aug 2024 19:20:18 +0200 Subject: [PATCH 03/17] Respect bounds for underzooming --- src/geo/transform.ts | 49 +++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index 1c77d58d3d..67b9d60096 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -785,9 +785,38 @@ export class Transform { let maxX = worldSize; let scaleY = 0; let scaleX = 0; - const {x: screenWidth, y: screenHeight} = this.size; + let {x: screenWidth, y: screenHeight} = this.size; + + // With single-copy world, users can "underzoom" the world to see it entirely. + if (!this._renderWorldCopies) { + // `boundsRatio` is the percentage of the bounds one can exceed when + // panning and/or zooming, where a bound is measured from viewport + // edge to viewport center. + // The default is boundsRatio=0.5, which means on a wide viewport + // one can pan and zoom out until the world's top and bottom edges + // reach halfway (50%) between the viewport center and its top and + // bottom edges. + // + // viewport + // _______________________________ + // |viewport : } boundsRatio| + // | -———————————- | + // | |world: | | + // | | : | | + // | | * | | + // | | | | + // | -———————————- | + // |_____________________________| + // + // If boundsRatio=0.0, one can pan and zoom out just until the world + // edges touch the edge of the viewport. + // If boundsRatio=1.0, one can pan and zoom out until the world + // edges touch the center of the viewport. + const boundsRatio = 0.5; + screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight) + } - if (this.latRange && this._renderWorldCopies) { + if (this.latRange) { const latRange = this.latRange; minY = mercatorYfromLat(latRange[1]) * worldSize; maxY = mercatorYfromLat(latRange[0]) * worldSize; @@ -795,7 +824,7 @@ export class Transform { if (shouldZoomIn) scaleY = screenHeight / (maxY - minY); } - if (lngRange && this._renderWorldCopies) { + if (lngRange) { minX = wrap( mercatorXfromLng(lngRange[0]) * worldSize, 0, @@ -820,20 +849,16 @@ export class Transform { if (scale) { // zoom in to exclude all beyond the given lng/lat ranges - const pointX = !this._renderWorldCopies - ? originalX - : scaleX ? (maxX + minX) / 2 : originalX; - const pointY = !this._renderWorldCopies - ? originalY - : scaleY ? (maxY + minY) / 2 : originalY; - const newPoint = new Point(pointX, pointY); + const newPoint = new Point( + scaleX ? (maxX + minX) / 2 : originalX, + scaleY ? (maxY + minY) / 2 : originalY); result.center = this.unproject.call({worldSize}, newPoint).wrap(); result.zoom += this.scaleZoom(scale); return result; } if (this.latRange) { - const h2 = !this._renderWorldCopies ? 1e-10 : screenHeight / 2; + const h2 = screenHeight / 2; if (originalY - h2 < minY) modifiedY = minY + h2; if (originalY + h2 > maxY) modifiedY = maxY - h2; } @@ -844,7 +869,7 @@ export class Transform { if (this._renderWorldCopies) { wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2); } - const w2 = !this._renderWorldCopies ? 1e-10 : screenWidth / 2; + const w2 = screenWidth / 2; if (wrappedX - w2 < minX) modifiedX = minX + w2; if (wrappedX + w2 > maxX) modifiedX = maxX - w2; From 70c8d2683d59b1402065f90ccad48361b676b58a Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Mon, 26 Aug 2024 20:26:14 +0200 Subject: [PATCH 04/17] Comment explanation of underzoom mechanic --- src/geo/transform.ts | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index 67b9d60096..b048ac8da1 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -787,17 +787,12 @@ export class Transform { let scaleX = 0; let {x: screenWidth, y: screenHeight} = this.size; - // With single-copy world, users can "underzoom" the world to see it entirely. + // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. + // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `boundsRatio`. + // `minZoom` is obeyed in all cases. if (!this._renderWorldCopies) { - // `boundsRatio` is the percentage of the bounds one can exceed when - // panning and/or zooming, where a bound is measured from viewport - // edge to viewport center. - // The default is boundsRatio=0.5, which means on a wide viewport - // one can pan and zoom out until the world's top and bottom edges - // reach halfway (50%) between the viewport center and its top and - // bottom edges. - // - // viewport + // `boundsRatio` is the percentage of the bounds a user can exceed when panning and/or zooming, where a bound is measured from viewport edge to viewport center. + // The default is boundsRatio=0.5, which on a wide viewport means a user can pan and zoom out until the world's top and bottom edges are halfway between the viewport center and its top and bottom edges. // _______________________________ // |viewport : } boundsRatio| // | -———————————- | @@ -807,13 +802,8 @@ export class Transform { // | | | | // | -———————————- | // |_____________________________| - // - // If boundsRatio=0.0, one can pan and zoom out just until the world - // edges touch the edge of the viewport. - // If boundsRatio=1.0, one can pan and zoom out until the world - // edges touch the center of the viewport. const boundsRatio = 0.5; - screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight) + screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight); } if (this.latRange) { From 309873d1db00925c145858f0df0e2b777b99b22e Mon Sep 17 00:00:00 2001 From: Lars Maxfield <83759569+larsmaxfield@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:38:39 +0200 Subject: [PATCH 05/17] Remove temporary /data in .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 25b3847b47..bb99e96551 100644 --- a/.gitignore +++ b/.gitignore @@ -39,5 +39,3 @@ npm-debug.log /.vs/ .*.swp junit.xml - -/test/data From 24f74acb3a7f1bb7992dd78fea51824fa6468bc9 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Tue, 27 Aug 2024 21:21:12 +0200 Subject: [PATCH 06/17] Temporary ignore test/data --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bb99e96551..52f273ad2a 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ npm-debug.log /.vs/ .*.swp junit.xml + +test/data From 8b71f9f194982a68518083c2480c49dc2db0720c Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Tue, 27 Aug 2024 21:22:03 +0200 Subject: [PATCH 07/17] In-progress: New underzoom design with two settings for zoom and pan --- src/geo/transform.ts | 79 ++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index b048ac8da1..a6dcb7b6ff 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -787,31 +787,38 @@ export class Transform { let scaleX = 0; let {x: screenWidth, y: screenHeight} = this.size; - // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. - // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `boundsRatio`. - // `minZoom` is obeyed in all cases. - if (!this._renderWorldCopies) { - // `boundsRatio` is the percentage of the bounds a user can exceed when panning and/or zooming, where a bound is measured from viewport edge to viewport center. - // The default is boundsRatio=0.5, which on a wide viewport means a user can pan and zoom out until the world's top and bottom edges are halfway between the viewport center and its top and bottom edges. - // _______________________________ - // |viewport : } boundsRatio| - // | -———————————- | - // | |world: | | - // | | : | | - // | | * | | - // | | | | - // | -———————————- | - // |_____________________________| - const boundsRatio = 0.5; - screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight); - } + // // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. + // // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `boundsRatio`. + // // `minZoom` is obeyed in all cases. + // if (!this._renderWorldCopies) { + // // `boundsRatio` is the percentage of the bounds a user can exceed when panning and/or zooming, where a bound is measured from viewport edge to viewport center. + // // The default is boundsRatio=0.5, which on a wide viewport means a user can pan and zoom out until the world's top and bottom edges are halfway between the viewport center and its top and bottom edges. + // // _______________________________ + // // |viewport : } boundsRatio| + // // | -———————————- | + // // | |world: | | + // // | | : | | + // // | | * | | + // // | | | | + // // | -———————————- | + // // |_____________________________| + // // const boundsRatio = 2.0; // 2.0 is "let the bottom bound pull up 2x viewport bottom to center" + // const boundsRatio = 2.0; // 1.0 is "let the bottom bound pull up 1x viewport bottomn to center" + // // screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight); + // screenWidth = (1.0 - boundsRatio) * screenWidth; + // screenHeight = (1.0 - boundsRatio) * screenHeight; + // } + + const userUnderzoomScale = 0.9; // Range 1.0 to 0.5 + const underzoomScale = + !this._renderWorldCopies ? userUnderzoomScale : 1.0; if (this.latRange) { const latRange = this.latRange; minY = mercatorYfromLat(latRange[1]) * worldSize; maxY = mercatorYfromLat(latRange[0]) * worldSize; - const shouldZoomIn = maxY - minY < screenHeight; - if (shouldZoomIn) scaleY = screenHeight / (maxY - minY); + const shouldZoomIn = maxY - minY < (underzoomScale*screenHeight); + if (shouldZoomIn) scaleY = underzoomScale*screenHeight / (maxY - minY); } if (lngRange) { @@ -828,27 +835,40 @@ export class Transform { if (maxX < minX) maxX += worldSize; - const shouldZoomIn = maxX - minX < screenWidth; - if (shouldZoomIn) scaleX = screenWidth / (maxX - minX); + const shouldZoomIn = maxX - minX < (underzoomScale*screenWidth); + if (shouldZoomIn) scaleX = underzoomScale*screenWidth / (maxX - minX); } const {x: originalX, y: originalY} = this.project.call({worldSize}, lngLat); let modifiedX, modifiedY; - const scale = Math.max(scaleX || 0, scaleY || 0); + const scale = + this._renderWorldCopies ? Math.max(scaleX || 0, scaleY || 0) : Math.min(scaleX || 0, scaleY || 0); if (scale) { // zoom in to exclude all beyond the given lng/lat ranges const newPoint = new Point( scaleX ? (maxX + minX) / 2 : originalX, scaleY ? (maxY + minY) / 2 : originalY); - result.center = this.unproject.call({worldSize}, newPoint).wrap(); + // TODO: For single-copy world when bounds are more limiting than zoom (for example, overpanRatio=0.0), + // this function should indeed assign set a new point. I think that needs to be the nearest valid edge point. + if (this._renderWorldCopies) result.center = this.unproject.call({worldSize}, newPoint).wrap(); result.zoom += this.scaleZoom(scale); return result; } - + + // Panning up and down in latitude is externally limited by project() with MAX_VALID_LATITUDE. + // Specifically, this limits panning of the world top bound to no farther down than the center of the viewport; + // the world bottom bound is limited to no farther up than the center of the viewport. + // Due to the complexity and consequence of altering project() or MAX_VALID_LATITUDE, we'll simply limit + // the overpanRatio to 1.0. + let userOverpanRatio = 0.1; // If 0.0, you may not overpan the bounds; if 1.0, you may overpan the bounds to 100% to the center + const overpanRatio = clamp(userOverpanRatio, 0.0, 1.0); + const panScale = + !this._renderWorldCopies ? (1.0 - overpanRatio) : 1.0; + if (this.latRange) { - const h2 = screenHeight / 2; + const h2 = panScale * screenHeight / 2; if (originalY - h2 < minY) modifiedY = minY + h2; if (originalY + h2 > maxY) modifiedY = maxY - h2; } @@ -858,8 +878,8 @@ export class Transform { let wrappedX = originalX; if (this._renderWorldCopies) { wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2); - } - const w2 = screenWidth / 2; + } + const w2 = panScale * screenWidth / 2; if (wrappedX - w2 < minX) modifiedX = minX + w2; if (wrappedX + w2 > maxX) modifiedX = maxX - w2; @@ -868,7 +888,8 @@ export class Transform { // pan the map if the screen goes off the range if (modifiedX !== undefined || modifiedY !== undefined) { const newPoint = new Point(modifiedX ?? originalX, modifiedY ?? originalY); - result.center = this.unproject.call({worldSize}, newPoint).wrap(); + result.center = this.unproject.call({worldSize}, newPoint); + if (this._renderWorldCopies) result.center = result.center.wrap(); } return result; From b40a54eb6a8fd4560520bc498708f4ad325fe677 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Tue, 27 Aug 2024 21:22:36 +0200 Subject: [PATCH 08/17] Temporary (?) underzoom examples --- test/examples/underzoom-tall.html | 124 +++++++++++++++++++++++++ test/examples/underzoom-unbounded.html | 64 +++++++++++++ test/examples/underzoom-wide.html | 124 +++++++++++++++++++++++++ 3 files changed, 312 insertions(+) create mode 100644 test/examples/underzoom-tall.html create mode 100644 test/examples/underzoom-unbounded.html create mode 100644 test/examples/underzoom-wide.html diff --git a/test/examples/underzoom-tall.html b/test/examples/underzoom-tall.html new file mode 100644 index 0000000000..2261a2eba3 --- /dev/null +++ b/test/examples/underzoom-tall.html @@ -0,0 +1,124 @@ + + + + Tall-bounded render world copies + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/test/examples/underzoom-unbounded.html b/test/examples/underzoom-unbounded.html new file mode 100644 index 0000000000..a70f20cb11 --- /dev/null +++ b/test/examples/underzoom-unbounded.html @@ -0,0 +1,64 @@ + + + + Render world copies + + + + + + + + + + +
+ + + + + diff --git a/test/examples/underzoom-wide.html b/test/examples/underzoom-wide.html new file mode 100644 index 0000000000..4ff2e5bbf3 --- /dev/null +++ b/test/examples/underzoom-wide.html @@ -0,0 +1,124 @@ + + + + Wide-bounded render world copies + + + + + + + + + +
+ + + + \ No newline at end of file From 5a86b4cedd6613121ecb444aeb095f9fc38a347d Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Wed, 18 Sep 2024 19:31:04 +0200 Subject: [PATCH 09/17] Redo underzoom design with user variables underzoomScale and overpanRatio --- src/geo/transform.ts | 78 +++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index a6dcb7b6ff..f6eff6cc7b 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -787,31 +787,25 @@ export class Transform { let scaleX = 0; let {x: screenWidth, y: screenHeight} = this.size; - // // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. - // // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `boundsRatio`. - // // `minZoom` is obeyed in all cases. - // if (!this._renderWorldCopies) { - // // `boundsRatio` is the percentage of the bounds a user can exceed when panning and/or zooming, where a bound is measured from viewport edge to viewport center. - // // The default is boundsRatio=0.5, which on a wide viewport means a user can pan and zoom out until the world's top and bottom edges are halfway between the viewport center and its top and bottom edges. - // // _______________________________ - // // |viewport : } boundsRatio| - // // | -———————————- | - // // | |world: | | - // // | | : | | - // // | | * | | - // // | | | | - // // | -———————————- | - // // |_____________________________| - // // const boundsRatio = 2.0; // 2.0 is "let the bottom bound pull up 2x viewport bottom to center" - // const boundsRatio = 2.0; // 1.0 is "let the bottom bound pull up 1x viewport bottomn to center" - // // screenWidth = screenHeight = (1.0 - boundsRatio) * Math.min(screenWidth, screenHeight); - // screenWidth = (1.0 - boundsRatio) * screenWidth; - // screenHeight = (1.0 - boundsRatio) * screenHeight; - // } - - const userUnderzoomScale = 0.9; // Range 1.0 to 0.5 + // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. + // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `underzoomScale` + // ___________________________ + // |viewport | + // | -———————————- | + // | |world | | + // | | | | + // | | * | | + // | | | | + // | -———————————- | + // |_____________________________| + + const allowUnderzoom = true; + + const userUnderzoomScale = 0.2; // Range 1.0 to 0.5 const underzoomScale = - !this._renderWorldCopies ? userUnderzoomScale : 1.0; + this._renderWorldCopies ? + 1.0 : + userUnderzoomScale; if (this.latRange) { const latRange = this.latRange; @@ -842,33 +836,43 @@ export class Transform { const {x: originalX, y: originalY} = this.project.call({worldSize}, lngLat); let modifiedX, modifiedY; - const scale = - this._renderWorldCopies ? Math.max(scaleX || 0, scaleY || 0) : Math.min(scaleX || 0, scaleY || 0); + const scale = + (this._renderWorldCopies || !allowUnderzoom) ? + Math.max(scaleX || 0, scaleY || 0) : + Math.min(scaleX || 0, scaleY || 0); if (scale) { // zoom in to exclude all beyond the given lng/lat ranges const newPoint = new Point( scaleX ? (maxX + minX) / 2 : originalX, scaleY ? (maxY + minY) / 2 : originalY); - // TODO: For single-copy world when bounds are more limiting than zoom (for example, overpanRatio=0.0), - // this function should indeed assign set a new point. I think that needs to be the nearest valid edge point. if (this._renderWorldCopies) result.center = this.unproject.call({worldSize}, newPoint).wrap(); result.zoom += this.scaleZoom(scale); return result; } // Panning up and down in latitude is externally limited by project() with MAX_VALID_LATITUDE. - // Specifically, this limits panning of the world top bound to no farther down than the center of the viewport; - // the world bottom bound is limited to no farther up than the center of the viewport. + // These limits prevent panning of the world no farther downwards than the center of the viewport, + // and likewise no farther upwards than the center of the viewport. // Due to the complexity and consequence of altering project() or MAX_VALID_LATITUDE, we'll simply limit - // the overpanRatio to 1.0. - let userOverpanRatio = 0.1; // If 0.0, you may not overpan the bounds; if 1.0, you may overpan the bounds to 100% to the center - const overpanRatio = clamp(userOverpanRatio, 0.0, 1.0); - const panScale = - !this._renderWorldCopies ? (1.0 - overpanRatio) : 1.0; + // the overpanRatio to 1.0 to match that external limit. + const userOverpanRatio = 0.0; // If 0.0, you may not overpan the bounds; if 1.0, you may overpan the bounds to 100% to the center + let lngOverpanRatio, latOverpanRatio; + if (this._renderWorldCopies && !allowUnderzoom) { + lngOverpanRatio = 0.0; + latOverpanRatio = 0.0; + } else { + const overpanRatio = clamp(userOverpanRatio, 0.0, 1.0); + const latUnderzoomMinimumPanRatio = 1 - ((maxY - minY) / screenHeight); + const lngUnderzoomMinimumPanRatio = 1 - ((maxX - minX) / screenWidth); + lngOverpanRatio = Math.max(lngUnderzoomMinimumPanRatio, overpanRatio); + latOverpanRatio = Math.max(latUnderzoomMinimumPanRatio, overpanRatio); + } + const lngPanScale = 1.0 - lngOverpanRatio; + const latPanScale = 1.0 - latOverpanRatio; if (this.latRange) { - const h2 = panScale * screenHeight / 2; + const h2 = latPanScale * screenHeight / 2; if (originalY - h2 < minY) modifiedY = minY + h2; if (originalY + h2 > maxY) modifiedY = maxY - h2; } @@ -879,7 +883,7 @@ export class Transform { if (this._renderWorldCopies) { wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2); } - const w2 = panScale * screenWidth / 2; + const w2 = lngPanScale * screenWidth / 2; if (wrappedX - w2 < minX) modifiedX = minX + w2; if (wrappedX + w2 > maxX) modifiedX = maxX - w2; From 0cf3cd2596669ba1b8895f2098d1a90c64f16b84 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Wed, 18 Sep 2024 19:49:14 +0200 Subject: [PATCH 10/17] Set default overpan ratios to 0.0; add `this.` placeholders for user variables --- src/geo/transform.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index cc031bf059..078a56e023 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -800,8 +800,10 @@ export class Transform { // | -———————————- | // |_____________________________| + // this._allowUnderzoom const allowUnderzoom = true; + // this._underzoomScale const userUnderzoomScale = 0.2; // Range 1.0 to 0.5 const underzoomScale = this._renderWorldCopies ? @@ -857,12 +859,11 @@ export class Transform { // and likewise no farther upwards than the center of the viewport. // Due to the complexity and consequence of altering project() or MAX_VALID_LATITUDE, we'll simply limit // the overpanRatio to 1.0 to match that external limit. + // this._overpanScale const userOverpanRatio = 0.0; // If 0.0, you may not overpan the bounds; if 1.0, you may overpan the bounds to 100% to the center - let lngOverpanRatio, latOverpanRatio; - if (this._renderWorldCopies && !allowUnderzoom) { - lngOverpanRatio = 0.0; - latOverpanRatio = 0.0; - } else { + let lngOverpanRatio = 0.0; + let latOverpanRatio = 0.0; + if (!this._renderWorldCopies && allowUnderzoom) { const overpanRatio = clamp(userOverpanRatio, 0.0, 1.0); const latUnderzoomMinimumPanRatio = 1 - ((maxY - minY) / screenHeight); const lngUnderzoomMinimumPanRatio = 1 - ((maxX - minX) / screenWidth); From 9b28b1501a90e4308f979d59c167cbf02487bb71 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Fri, 20 Sep 2024 13:54:43 +0200 Subject: [PATCH 11/17] Change underzoom source to OSM; border line outside the bounds so they don't appear when underzoom off --- test/examples/underzoom-tall.html | 30 ++++++++------ test/examples/underzoom-unbounded.html | 54 +++++++++++++++++++++++--- test/examples/underzoom-wide.html | 24 +++++++----- 3 files changed, 82 insertions(+), 26 deletions(-) diff --git a/test/examples/underzoom-tall.html b/test/examples/underzoom-tall.html index 2261a2eba3..fb2c794cd2 100644 --- a/test/examples/underzoom-tall.html +++ b/test/examples/underzoom-tall.html @@ -37,11 +37,11 @@ @@ -39,14 +51,46 @@ - +
- + + + + + + +
+ + + +
\ No newline at end of file diff --git a/test/examples/underzoom-unbounded.html b/test/examples/underzoom-unbounded.html index 803c5f61fd..2f081a1a68 100644 --- a/test/examples/underzoom-unbounded.html +++ b/test/examples/underzoom-unbounded.html @@ -22,39 +22,67 @@ background-position: 0 0, 0 20px, 20px -20px, -20px 0px; } html, body, #map { height: 100%; } + .listing-group { + font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; + position: absolute; + color: #fff; + background-color: rgb(157, 156, 156); + padding: 10px; + border-radius: 4px; + } + #listing-group-top-left { + top: 10px; + left: 10px; + } + #listing-group-bottom-left { + bottom: 10px; + left: 10px; + } -
- + + + + + + +
+ + + +
diff --git a/test/examples/underzoom-wide.html b/test/examples/underzoom-wide.html index 14264aadb0..e7e2eb158a 100644 --- a/test/examples/underzoom-wide.html +++ b/test/examples/underzoom-wide.html @@ -53,6 +53,8 @@ center: [(west+east)/2, (north+south)/2], maxBounds: bounds, // Sets bounds as max renderWorldCopies: false, + allowUnderzoom: true, + underzoomScale: 0.8, style: { version: 8, sources: { From f843bf1942e5131058842ead0ba539a0aae99ba4 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Fri, 20 Sep 2024 16:47:09 +0200 Subject: [PATCH 14/17] Update tall and wide underzoom examples with interactive inputs --- test/examples/underzoom-tall.html | 26 ++++---- test/examples/underzoom-wide.html | 99 ++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/test/examples/underzoom-tall.html b/test/examples/underzoom-tall.html index 734407941e..44723a2605 100644 --- a/test/examples/underzoom-tall.html +++ b/test/examples/underzoom-tall.html @@ -45,34 +45,31 @@
- - - + +
+ - +
- + + + + + +
+ + + +
+ \ No newline at end of file From e580fca826a791292c36516bf166ec8248bcb870 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Fri, 20 Sep 2024 16:52:00 +0200 Subject: [PATCH 15/17] Accurate underzoom example title and meta --- test/examples/underzoom-tall.html | 4 ++-- test/examples/underzoom-unbounded.html | 4 ++-- test/examples/underzoom-wide.html | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/examples/underzoom-tall.html b/test/examples/underzoom-tall.html index 44723a2605..db1d9bdb1f 100644 --- a/test/examples/underzoom-tall.html +++ b/test/examples/underzoom-tall.html @@ -1,8 +1,8 @@ - Tall-bounded render world copies - + Tall-bounded underzoom + diff --git a/test/examples/underzoom-unbounded.html b/test/examples/underzoom-unbounded.html index 2f081a1a68..7dcf2d96fa 100644 --- a/test/examples/underzoom-unbounded.html +++ b/test/examples/underzoom-unbounded.html @@ -1,8 +1,8 @@ - Render world copies - + Unbounded underzoom + diff --git a/test/examples/underzoom-wide.html b/test/examples/underzoom-wide.html index 5e4d462368..7e9b7ee5e6 100644 --- a/test/examples/underzoom-wide.html +++ b/test/examples/underzoom-wide.html @@ -1,8 +1,8 @@ - Wide-bounded render world copies - + Wide-bounded underzoom + From 08ee7174a0dc40425fd02c05588860e75bfb2772 Mon Sep 17 00:00:00 2001 From: Lars Maxfield Date: Sat, 21 Sep 2024 13:27:10 +0200 Subject: [PATCH 16/17] Rename to underzoom and overpan as percentages; fix lint --- src/geo/transform.ts | 135 ++++++++-------- src/ui/map.ts | 151 ++++++++++++++---- test/examples/underzoom-tall.html | 47 +++--- test/examples/underzoom-wide.html | 47 +++--- ...nderzoom-unbounded.html => underzoom.html} | 47 +++--- 5 files changed, 264 insertions(+), 163 deletions(-) rename test/examples/{underzoom-unbounded.html => underzoom.html} (66%) diff --git a/src/geo/transform.ts b/src/geo/transform.ts index 51ca6a941b..e559117b01 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -50,8 +50,8 @@ export class Transform { _unmodified: boolean; _renderWorldCopies: boolean; _allowUnderzoom: boolean; - _underzoomScale: number; - _overpanRatio: number; + _underzoom: number; + _overpan: number; _minZoom: number; _maxZoom: number; _minPitch: number; @@ -77,15 +77,15 @@ export class Transform { */ nearZ: number; - constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean, allowUnderzoom?: boolean, underzoomScale?: number, overpanRatio?: number) { + constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean, allowUnderzoom?: boolean, underzoom?: number, overpan?: number) { this.tileSize = 512; // constant this._renderWorldCopies = renderWorldCopies === undefined ? true : !!renderWorldCopies; this._minZoom = minZoom || 0; this._maxZoom = maxZoom || 22; this._allowUnderzoom = allowUnderzoom === undefined ? false : !!allowUnderzoom; - this._underzoomScale = underzoomScale || 1.0; - this._overpanRatio = overpanRatio || 0.0; + this._underzoom = underzoom || 100; + this._overpan = overpan || 0; this._minPitch = (minPitch === undefined || minPitch === null) ? 0 : minPitch; this._maxPitch = (maxPitch === undefined || maxPitch === null) ? 60 : maxPitch; @@ -109,7 +109,7 @@ export class Transform { } clone(): Transform { - const clone = new Transform(this._minZoom, this._maxZoom, this._minPitch, this.maxPitch, this._renderWorldCopies, this._allowUnderzoom, this._underzoomScale, this._overpanRatio); + const clone = new Transform(this._minZoom, this._maxZoom, this._minPitch, this.maxPitch, this._renderWorldCopies, this._allowUnderzoom, this._underzoom, this._overpan); clone.apply(this); return clone; } @@ -169,7 +169,7 @@ export class Transform { } this._renderWorldCopies = renderWorldCopies; - + this._constrain(); this._calcMatrices(); } @@ -183,25 +183,25 @@ export class Transform { } this._allowUnderzoom = allowUnderzoom; - + this._constrain(); this._calcMatrices(); } - get underzoomScale(): number { return this._underzoomScale; } - set underzoomScale(scale: number) { - if (this._underzoomScale === scale) return; - this._underzoomScale = scale; - + get underzoom(): number { return this._underzoom; } + set underzoom(underzoom: number) { + if (this._underzoom === underzoom) return; + this._underzoom = underzoom; + this._constrain(); this._calcMatrices(); } - get overpanRatio(): number { return this._overpanRatio; } - set overpanRatio(ratio: number) { - if (this._overpanRatio === ratio) return; - this._overpanRatio = ratio; - + get overpan(): number { return this._overpan; } + set overpan(overpan: number) { + if (this._overpan === overpan) return; + this._overpan = overpan; + this._constrain(); this._calcMatrices(); } @@ -805,6 +805,7 @@ export class Transform { * 1) everything beyond the bounds is excluded * 2) a given lngLat is as near the center as possible * Bounds are those set by maxBounds or North & South "Poles" and, if only 1 globe is displayed, antimeridian. + * Underzooming and overpanning beyond the bounds is done if 1 globe is displayed and allowUnderzoom=true. */ getConstrained(lngLat: LngLat, zoom: number): {center: LngLat; zoom: number} { zoom = clamp(+zoom, this.minZoom, this.maxZoom); @@ -827,37 +828,40 @@ export class Transform { let maxX = worldSize; let scaleY = 0; let scaleX = 0; - let {x: screenWidth, y: screenHeight} = this.size; - - // For a single-world map, a user can "underzoom" the world to see it entirely in the viewport. - // This works by reducing the viewport's appararent size to a square with a side length equal to the smallest viewport dimension, then reduced by a factor `underzoomScale` - // ___________________________ - // |viewport | - // | -———————————- | - // | |world | | - // | | | | - // | | * | | - // | | | | - // | -———————————- | - // |_____________________________| - - // const userAllowUnderzoom = true; - const userAllowUnderzoom = this._allowUnderzoom; - const allowUnderzoom = userAllowUnderzoom; - - // const userUnderzoomScale = 0.8; - const userUnderzoomScale = this._underzoomScale; - const underzoomScale = - (this._renderWorldCopies || !allowUnderzoom) ? - 1.0 : - userUnderzoomScale; + const {x: screenWidth, y: screenHeight} = this.size; + + // For a single-world map, a user can underzoom the world to see it + // entirely in the viewport. This works by reducing the viewport's + // apparent size to a square with a side length equal to the smallest + // viewport dimension scaled by the `underzoom` percentage. + // The user can also overpan the world bounds up to 50% the viewport + // dimensions, limited by the `overpan` percentage. + // _________________________ + // |viewport | + // | | + // | | + // | -———————————- | + // | |map bounds | | + // | | | | + // |·····|···········|<--->| overpan + // | | | | + // | -———————————- | + // |·····<----------->·····| underzoom + // | | + // | | + // |_______________________| + + const underzoom = // 0-1 (percent as normalized factor of viewport minimum dimension) + (!this._renderWorldCopies && this._allowUnderzoom) ? + clamp(this._underzoom, 0, 100) / 100 : + 1.0; if (this.latRange) { const latRange = this.latRange; minY = mercatorYfromLat(latRange[1]) * worldSize; maxY = mercatorYfromLat(latRange[0]) * worldSize; - const shouldZoomIn = maxY - minY < (underzoomScale*screenHeight); - if (shouldZoomIn) scaleY = underzoomScale*screenHeight / (maxY - minY); + const shouldZoomIn = maxY - minY < (underzoom * screenHeight); + if (shouldZoomIn) scaleY = underzoom * screenHeight / (maxY - minY); } if (lngRange) { @@ -874,17 +878,17 @@ export class Transform { if (maxX < minX) maxX += worldSize; - const shouldZoomIn = maxX - minX < (underzoomScale*screenWidth); - if (shouldZoomIn) scaleX = underzoomScale*screenWidth / (maxX - minX); + const shouldZoomIn = maxX - minX < (underzoom * screenWidth); + if (shouldZoomIn) scaleX = underzoom * screenWidth / (maxX - minX); } const {x: originalX, y: originalY} = this.project.call({worldSize}, lngLat); let modifiedX, modifiedY; const scale = - (this._renderWorldCopies || !allowUnderzoom) ? - Math.max(scaleX || 0, scaleY || 0) : - Math.min(scaleX || 0, scaleY || 0); + (!this._renderWorldCopies && this._allowUnderzoom) ? + Math.min(scaleX || 0, scaleY || 0) : + Math.max(scaleX || 0, scaleY || 0); if (scale) { // zoom in to exclude all beyond the given lng/lat ranges @@ -895,26 +899,23 @@ export class Transform { result.zoom += this.scaleZoom(scale); return result; } - + // Panning up and down in latitude is externally limited by project() with MAX_VALID_LATITUDE. - // These limits prevent panning of the world no farther downwards than the center of the viewport, - // and likewise no farther upwards than the center of the viewport. + // This limit prevents panning the top and bottom bounds farther than the center of the viewport. // Due to the complexity and consequence of altering project() or MAX_VALID_LATITUDE, we'll simply limit - // the overpanRatio to 1.0 to match that external limit. - // const userOverpanRatio = 0.0; // If 0.0, you may not overpan the bounds; if 1.0, you may overpan the bounds to 100% to the center - const userOverpanRatio = this._overpanRatio; - let lngOverpanRatio = 0.0; - let latOverpanRatio = 0.0; - if (!this._renderWorldCopies && allowUnderzoom) { - const overpanRatio = clamp(userOverpanRatio, 0.0, 1.0); - const latUnderzoomMinimumPanRatio = 1 - ((maxY - minY) / screenHeight); - const lngUnderzoomMinimumPanRatio = 1 - ((maxX - minX) / screenWidth); - lngOverpanRatio = Math.max(lngUnderzoomMinimumPanRatio, overpanRatio); - latOverpanRatio = Math.max(latUnderzoomMinimumPanRatio, overpanRatio); + // the overpan to 50% the bounds to match that external limit. + let lngOverpan = 0.0; + let latOverpan = 0.0; + if (!this._renderWorldCopies && this._allowUnderzoom) { + const overpan = 2 * clamp(this._overpan, 0, 50) / 100; // 0-1 (percent as a normalized factor from viewport edge to center) + const latUnderzoomMinimumPan = 1.0 - ((maxY - minY) / screenHeight); + const lngUnderzoomMinimumPan = 1.0 - ((maxX - minX) / screenWidth); + lngOverpan = Math.max(lngUnderzoomMinimumPan, overpan); + latOverpan = Math.max(latUnderzoomMinimumPan, overpan); } - const lngPanScale = 1.0 - lngOverpanRatio; - const latPanScale = 1.0 - latOverpanRatio; - + const lngPanScale = 1.0 - lngOverpan; + const latPanScale = 1.0 - latOverpan; + if (this.latRange) { const h2 = latPanScale * screenHeight / 2; if (originalY - h2 < minY) modifiedY = minY + h2; @@ -926,7 +927,7 @@ export class Transform { let wrappedX = originalX; if (this._renderWorldCopies) { wrappedX = wrap(originalX, centerX - worldSize / 2, centerX + worldSize / 2); - } + } const w2 = lngPanScale * screenWidth / 2; if (wrappedX - w2 < minX) modifiedX = minX + w2; diff --git a/src/ui/map.ts b/src/ui/map.ts index d1ba1e635b..38df4807c2 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -233,9 +233,21 @@ export type MapOptions = { * @defaultValue true */ renderWorldCopies?: boolean; + /** + * If `true`, a user may zoom out a single-copy world beyond its bounds until the bounded area is a percent of the viewport size as defined by `underzoom` unless `minZoom` is reached. If `false`, a user may not zoom out beyond the map bounds. + * @defaultValue false + */ allowUnderzoom?: boolean; - underzoomScale?: number; - overpanRatio?: number; + /** + * The allowable underzoom of the map, measured as a percentage of the size of the map's bounds relative to the viewport size (0-100). If `underzoom` is not specified in the constructor options, MapLibre GL JS will default to `100`. `allowUnderzoom` must be set `true` for underzooming to occur. + * @defaultValue 100 + */ + underzoom?: number; + /** + * The allowable overpan of the map, measured as a percentage of how far the map's latitude-longitude bounds may be exceed relative to the viewport's height and width (0-100). If `overpan` is not specified in the constructor options, MapLibre GL JS will default to `0`. `allowUnderzoom` must be set `true` for overpanning to occur. `overpan` is exceeded when necessary for underzooming. + * @defaultValue 0 + */ + overpan?: number; /** * The maximum number of tiles stored in the tile cache for a given source. If omitted, the cache will be dynamically sized based on the current viewport which can be set using `maxTileCacheZoomLevels` constructor options. * @defaultValue null @@ -362,6 +374,14 @@ const defaultMaxPitch = 60; // use this variable to check maxPitch for validity const maxPitchThreshold = 85; +const defaultUnderzoom = 80; +const minUnderzoom = 0; +const maxUnderzoom = 100; + +const defaultOverpan = 0; +const minOverpan = 0; +const maxOverpan = 50; + const defaultOptions: Readonly> = { hash: false, interactive: true, @@ -396,8 +416,8 @@ const defaultOptions: Readonly> = { renderWorldCopies: true, allowUnderzoom: false, - underzoomScale: 1, - overpanRatio: 0, + underzoom: defaultUnderzoom, + overpan: defaultOverpan, maxTileCacheSize: null, maxTileCacheZoomLevels: config.MAX_TILE_CACHE_ZOOM_LEVELS, transformRequest: null, @@ -586,7 +606,7 @@ export class Map extends Camera { throw new Error(`maxPitch must be less than or equal to ${maxPitchThreshold}`); } - const transform = new Transform(resolvedOptions.minZoom, resolvedOptions.maxZoom, resolvedOptions.minPitch, resolvedOptions.maxPitch, resolvedOptions.renderWorldCopies, resolvedOptions.allowUnderzoom, resolvedOptions.underzoomScale, resolvedOptions.overpanRatio); + const transform = new Transform(resolvedOptions.minZoom, resolvedOptions.maxZoom, resolvedOptions.minPitch, resolvedOptions.maxPitch, resolvedOptions.renderWorldCopies, resolvedOptions.allowUnderzoom, resolvedOptions.underzoom, resolvedOptions.overpan); super(transform, {bearingSnap: resolvedOptions.bearingSnap}); this._interactive = resolvedOptions.interactive; @@ -1150,51 +1170,128 @@ export class Map extends Camera { this.transform.renderWorldCopies = renderWorldCopies; return this._update(); } - + /** - * TODO: Write docs + * Returns the state of `allowUnderzoom`. + * If `true`, a user may zoom out a single-copy world beyond its bounds + * until the bounded area is a percent of the viewport size as defined by + * `underzoom` unless `minZoom` is reached. + * If `false`, a user may not zoom out beyond the map bounds. + * + * @returns The allowUnderzoom + * @example + * ```ts + * let worldUnderzoomAllowed = map.getAllowUnderzoom(); + * ``` */ getAllowUnderzoom(): boolean { return this.transform.allowUnderzoom; } + + /** + * Sets the state of `allowUnderzoom`. + * + * @param allowUnderzoom - If `true`, a user may zoom out a single-copy + * world beyond its bounds until the bounded area is a percent of the + * viewport size as defined by `underzoom` unless `minZoom` is reached. + * If `false`, a user may not zoom out beyond the map bounds. + * + * `undefined` is treated as `true`, `null` is treated as `false`. + * @example + * ```ts + * map.setAllowUnderzoom(true); + * ``` + */ setAllowUnderzoom(allowUnderzoom?: boolean | null): Map { this.transform.allowUnderzoom = allowUnderzoom; return this._update(); } /** - * TODO: Write docs - * TODO: Create and use defaults, thresholds, as is done with setMaxPitch + * Returns the map's allowable underzoom percentage. + * + * @returns underzoom + * @example + * ```ts + * let underzoom = map.getUnderzoom(); + * ``` */ - getUnderzoomScale(): number { return this.transform.underzoomScale; } - setUnderzoomScale(underzoomScale?: number | null): Map { + getUnderzoom(): number { return this.transform.underzoom; } - underzoomScale = underzoomScale === null || underzoomScale === undefined ? 1.0 : underzoomScale; + /** + * Sets or clears the map's allowable underzoom percentage. + * + * `allowUnderzoom` must be `true` for underzooming to occur. + * + * If the map is currently zoomed out to a size lower than the new + * underzoom, the map will zoom in to respect the new underzoom. + * + * `minZoom` is always respected, meaning if the map is already at + * `minZoom = 0` but the map is larger than the allowable underzoom size, + * it is not possible to zoom out any further. + * + * A {@link ErrorEvent} event will be fired if underzoom is out of bounds. + * + * @param underzoom - The allowable underzoom percentage to set (0 - 100). + * If `null` or `undefined` is provided, the function removes the current + * underzoom and sets it to the default (80). + * @example + * ```ts + * map.setUnderzoom(25); + * ``` + */ + setUnderzoom(underzoom?: number | null): Map { + + underzoom = underzoom === null || underzoom === undefined ? defaultUnderzoom : underzoom; - if (underzoomScale > 1.0) { - throw new Error(`underzoomScale must be less than or equal to ${1.0}`); - } else if (underzoomScale < 0.0) { - throw new Error(`underzoomScale must be greater than or equal to ${0.0}`); + if (underzoom > maxUnderzoom) { + throw new Error(`underzoom must be less than or equal to ${maxUnderzoom}`); + } else if (underzoom < minUnderzoom) { + throw new Error(`underzoom must be greater than or equal to ${minUnderzoom}`); } - this.transform.underzoomScale = underzoomScale; + this.transform.underzoom = underzoom; return this._update(); } /** - * TODO: Write docs - * TODO: Create and use defaults, thresholds, as is done with setMaxPitch + * Returns the map's allowable overpan percentage. + * + * @returns overpan + * @example + * ```ts + * let overpan = map.getOverpan(); + * ``` + */ + getOverpan(): number { return this.transform.overpan; } + + /** + * Sets or clears the map's allowable overpan percentage. + * + * `allowUnderzoom` must be `true` for overpanning to occur. + * + * If the map is underzoomed such that the bounds must exceed `overpan`, the + * map will allow that. + * + * A {@link ErrorEvent} event will be fired if overpan is out of bounds. + * + * @param overpan - The allowable overpan percentage to set (0 - 50). + * If `null` or `undefined` is provided, the function removes the current + * overpan and sets it to the default (0). + * @example + * ```ts + * map.setOverpan(25); + * ``` */ - getOverpanRatio(): number { return this.transform.overpanRatio; } - setOverpanRatio(overpanRatio?: number | null): Map { + setOverpan(overpan?: number | null): Map { - overpanRatio = overpanRatio === null || overpanRatio === undefined ? 0.0 : overpanRatio; + overpan = overpan === null || overpan === undefined ? defaultOverpan : overpan; - if (overpanRatio > 1.0) { - throw new Error(`overpanRatio must be less than or equal to ${1.0}`); - } else if (overpanRatio < 0.0) { - throw new Error(`overpanRatio must be greater than or equal to ${0.0}`); + if (overpan > maxOverpan) { + throw new Error(`overpan must be less than or equal to ${maxOverpan}`); + } else if (overpan < minOverpan) { + throw new Error(`overpan must be greater than or equal to ${minOverpan}`); } - this.transform.overpanRatio = overpanRatio; + this.transform.overpan = overpan; return this._update(); } diff --git a/test/examples/underzoom-tall.html b/test/examples/underzoom-tall.html index db1d9bdb1f..9c461dc62a 100644 --- a/test/examples/underzoom-tall.html +++ b/test/examples/underzoom-tall.html @@ -1,10 +1,10 @@ - + Tall-bounded underzoom - + - +