From 6018888c94855200aef5bab5de3643655d84405a Mon Sep 17 00:00:00 2001 From: Tim Stibbs Date: Sun, 12 Jan 2025 21:01:13 +0000 Subject: [PATCH] Fixing blank tiles when zooming in OS source --- ui/src/js/layers.js | 80 ++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/ui/src/js/layers.js b/ui/src/js/layers.js index f49c608..763e5e9 100644 --- a/ui/src/js/layers.js +++ b/ui/src/js/layers.js @@ -1,37 +1,51 @@ import leaflet from 'VendorWrappers/leaflet.js' import LeafletBing from 'VendorWrappers/bing-layer.js' import constants from './constants.js' +const minOverallZoom = 1 +const maxOverallZoom = 19 + +//because we have a mix of zooms, we have to either change the maxZoom value on the main map whenever we change layer, or we have to set the min and max the same for each layer(/layergroup). The latter is simpler, but means we have to set maxNativeZoom for those sources which can't provide tiles at the max overall zoom level. However, setting detectRetina=true breaks this, as per https://github.com/Leaflet/Leaflet/issues/8850 +//thus, we disable detectRetina in all sources to ensure that the maxNativeZoom property is correctly obeyed :( var defaults = { - key: constants.bingKey + minZoom: minOverallZoom, + maxZoom: maxOverallZoom, + detectRetina: false } -var bingDefaults = leaflet.extend({maxZoom: 18, minZoom: 0, detectRetina: true}, defaults) +var bingDefaults = leaflet.extend({}, defaults, { + key: constants.bingKey, + maxNativeZoom: 18 +}) + +//Bing standard maps +var bingRoads = new LeafletBing(leaflet.extend({}, bingDefaults, {imagerySet: 'RoadOnDemand'})) +var bingHybrid = new LeafletBing(leaflet.extend({}, bingDefaults, {imagerySet: 'AerialWithLabelsOnDemand'})) +var bingAerial = new LeafletBing(leaflet.extend({}, bingDefaults, {imagerySet: 'Aerial'})) //OS var bingOsLayer = new LeafletBing( - leaflet.extend( - { - imagerySet: 'OrdnanceSurvey', - minZoom: 12, - maxZoom: 18, - maxNativeZoom: 17 - }, - defaults - ) + leaflet.extend({}, bingDefaults, { + imagerySet: 'OrdnanceSurvey', + minZoom: 12, + maxNativeZoom: 17 + }) ) //note OS doesn't support retina //fallback layer because the OS maps don't scale well when you zoom out -var bingFallbackLayer = new LeafletBing(leaflet.extend({imagerySet: 'RoadOnDemand', maxZoom: 11, minZoom: 0}, defaults)) //note even though this layer supports retetina, having a group with a mix of retina and non-retina screws up the zooming +var bingFallbackLayer = new LeafletBing( + leaflet.extend({}, bingDefaults, { + imagerySet: 'RoadOnDemand', + maxZoom: 11 + }) +) var bingOsGroup = leaflet.layerGroup([bingOsLayer, bingFallbackLayer]) -//Bing standard maps -var bingRoads = new LeafletBing(leaflet.extend({imagerySet: 'RoadOnDemand'}, bingDefaults)) -var bingHybrid = new LeafletBing(leaflet.extend({imagerySet: 'AerialWithLabelsOnDemand'}, bingDefaults)) -var bingAerial = new LeafletBing(leaflet.extend({imagerySet: 'Aerial'}, bingDefaults)) + //OSM -var osm = new leaflet.TileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - minZoom: 0, - maxZoom: 19, - attribution: 'Map data © OpenStreetMap contributors' -}) +var osm = new leaflet.TileLayer( + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + leaflet.extend({}, defaults, { + attribution: 'Map data © OpenStreetMap contributors' + }) +) var layers = { OS: bingOsGroup, @@ -41,30 +55,6 @@ var layers = { OSM: osm } -function layerZoomExtractor(layers) { - let max = 0 - let min = Number.MAX_SAFE_INTEGER - layers.forEach(layer => { - if (layer.getLayers) { - let {max: subLayersMax, min: subLayersMin} = layerZoomExtractor(layer.getLayers()) - max = Math.max(max, subLayersMax) - min = Math.min(min, subLayersMin) - } - if (layer.options?.maxZoom) { - max = Math.max(max, layer.options.maxZoom) - } - if (layer.options?.maxZoom) { - min = Math.min(min, layer.options.minZoom) - } - }) - return { - max, - min - } -} -//now go back through all layers and compile the overall min and max - this is safer than trying to know it up front and then enforce it on the layers -const {max: maxOverallZoom, min: minOverallZoom} = layerZoomExtractor(Object.values(layers)) - function _listenForLayerChange(layerId, layer, config) { layer.on( 'add',