From 22475eefc455ccb9b4b1bf23acf2acb9888f57ed Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 29 Mar 2024 14:47:23 +0100 Subject: [PATCH] Properly handle fractional layer minzoom and maxzoom --- src/apply.js | 13 ++++++++----- src/util.js | 13 ++++++------- test/apply.test.js | 28 ++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/apply.js b/src/apply.js index df593edd..3a2131d7 100644 --- a/src/apply.js +++ b/src/apply.js @@ -32,11 +32,11 @@ import {bbox as bboxStrategy} from 'ol/loadingstrategy.js'; import {createXYZ} from 'ol/tilegrid.js'; import { defaultResolutions, - defaultTileGrid, fetchResource, getFilterCache, getFunctionCache, getGlStyle, + getResolutionForZoom, getStyleFunctionKey, getTileJson, getZoomForResolution, @@ -317,7 +317,10 @@ export function applyStyle( tileGrid.getMinZoom() > 0 ) { layer.setMaxResolution( - tileGrid.getResolution(tileGrid.getMinZoom()) + 1e-15, + getResolutionForZoom( + tileGrid.getMinZoom(), + defaultResolutions, + ) + 1e-15, ); } }); @@ -1233,21 +1236,21 @@ export function finalizeLayer( if (minZoom > 0 || sourceMinZoom > 0) { layer.setMaxResolution( Math.min( - defaultTileGrid.getResolution(minZoom), + getResolutionForZoom(minZoom, defaultResolutions), tileGrid.getResolution(sourceMinZoom), ) + 1e-15, ); } if (maxZoom < 24) { layer.setMinResolution( - defaultTileGrid.getResolution(maxZoom) + 1e-15, + getResolutionForZoom(maxZoom, defaultResolutions), ); } } } else { if (minZoom > 0) { layer.setMaxResolution( - defaultTileGrid.getResolution(minZoom) + 1e-15, + getResolutionForZoom(minZoom, defaultResolutions) + 1e-15, ); } } diff --git a/src/util.js b/src/util.js index 4a10bdd3..0e0efef4 100644 --- a/src/util.js +++ b/src/util.js @@ -1,8 +1,6 @@ -import TileGrid from 'ol/tilegrid/TileGrid.js'; import TileState from 'ol/TileState.js'; import {VectorTile} from 'ol'; import {expandUrl} from 'ol/tileurlfunction.js'; -import {get as getProjection} from 'ol/proj.js'; import {getUid} from 'ol/util.js'; import {normalizeSourceUrl, normalizeStyleUrl} from './mapbox.js'; import {toPromise} from 'ol/functions.js'; @@ -75,11 +73,6 @@ export const defaultResolutions = (function () { return resolutions; })(); -export const defaultTileGrid = new TileGrid({ - extent: getProjection('EPSG:3857').getExtent(), - resolutions: defaultResolutions, -}); - /** * @param {number} width Width of the canvas. * @param {number} height Height of the canvas. @@ -108,6 +101,12 @@ export function getZoomForResolution(resolution, resolutions) { return ii - 1; } +export function getResolutionForZoom(zoom, resolutions) { + const base = Math.floor(zoom); + const factor = Math.pow(2, zoom - base); + return resolutions[base] / factor; +} + const pendingRequests = {}; /** * @param {ResourceType} resourceType Type of resource to load. diff --git a/test/apply.test.js b/test/apply.test.js index b76535f5..962ba5aa 100644 --- a/test/apply.test.js +++ b/test/apply.test.js @@ -718,7 +718,31 @@ describe('ol-mapbox-style', function () { defaultResolutions[10] + 1e-15, ); should(map.getLayers().item(0).getMinResolution()).eql( - defaultResolutions[12] + 1e-15, + defaultResolutions[12], + ); + done(); + }) + .catch(function (err) { + done(err); + }); + }); + + it('respects fractional layer minzoom and maxzoom', function (done) { + context.layers[0].minzoom = 10.5; + context.layers[0].maxzoom = 12.5; + apply(target, context) + .then(function (map) { + should(map.getLayers().item(0).getMaxResolution()).greaterThan( + defaultResolutions[11], + ); + should(map.getLayers().item(0).getMaxResolution()).lessThan( + defaultResolutions[10], + ); + should(map.getLayers().item(0).getMinResolution()).greaterThan( + defaultResolutions[13], + ); + should(map.getLayers().item(0).getMinResolution()).lessThan( + defaultResolutions[12], ); done(); }) @@ -893,7 +917,7 @@ describe('ol-mapbox-style', function () { defaultResolutions[7] + 1e-15, ); should(map.getLayers().item(0).getMinResolution()).eql( - defaultResolutions[23] + 1e-15, + defaultResolutions[23], ); done(); })