feat: Centralize map tile management via Settings manager

- Add Settings.registerMap() to register maps for tile updates
- Add Settings.createTileLayer() to create tile layers from settings
- Update _updateMapTiles() to use registered maps
- Expose all maps to window object for settings manager access
- All dashboards now use Settings manager when available
- Tile provider changes in settings now apply immediately to all maps
- Use Fastly CDN for CARTO tiles (more reliable)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-01-29 10:00:25 +00:00
parent 87cd10194f
commit ec22823e59
6 changed files with 133 additions and 39 deletions
+61 -12
View File
@@ -20,13 +20,13 @@ const Settings = {
subdomains: 'abc'
},
cartodb_dark: {
url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2',
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
url: 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png',
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
subdomains: 'abcd'
},
cartodb_light: {
url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
url: 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png',
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
subdomains: 'abcd'
},
esri_world: {
@@ -36,6 +36,9 @@ const Settings = {
}
},
// Registry of maps that can be updated
_registeredMaps: [],
// Current settings cache
_cache: {},
@@ -178,7 +181,44 @@ const Settings = {
};
}
return this.tileProviders[provider] || this.tileProviders.openstreetmap;
return this.tileProviders[provider] || this.tileProviders.cartodb_dark;
},
/**
* Register a map to receive tile updates when settings change
* @param {L.Map} map - Leaflet map instance
*/
registerMap(map) {
if (map && typeof map.eachLayer === 'function' && !this._registeredMaps.includes(map)) {
this._registeredMaps.push(map);
}
},
/**
* Unregister a map
* @param {L.Map} map - Leaflet map instance
*/
unregisterMap(map) {
const idx = this._registeredMaps.indexOf(map);
if (idx > -1) {
this._registeredMaps.splice(idx, 1);
}
},
/**
* Create a tile layer using current settings
* @returns {L.TileLayer} Configured tile layer
*/
createTileLayer() {
const config = this.getTileConfig();
const options = {
attribution: config.attribution,
maxZoom: 19
};
if (config.subdomains) {
options.subdomains = config.subdomains;
}
return L.tileLayer(config.url, options);
},
/**
@@ -277,22 +317,30 @@ const Settings = {
},
/**
* Update map tiles if a map exists
* Update map tiles on all known maps
*/
_updateMapTiles() {
// Look for common map variable names
const maps = [
// Combine registered maps with common window map variables
const windowMaps = [
window.map,
window.leafletMap,
window.aprsMap,
window.adsbMap
window.adsbMap,
window.radarMap,
window.vesselMap,
window.groundMap,
window.groundTrackMap,
window.meshMap
].filter(m => m && typeof m.eachLayer === 'function');
if (maps.length === 0) return;
// Combine with registered maps, removing duplicates
const allMaps = [...new Set([...this._registeredMaps, ...windowMaps])];
if (allMaps.length === 0) return;
const config = this.getTileConfig();
maps.forEach(map => {
allMaps.forEach(map => {
// Remove existing tile layers
map.eachLayer(layer => {
if (layer instanceof L.TileLayer) {
@@ -302,7 +350,8 @@ const Settings = {
// Add new tile layer
const options = {
attribution: config.attribution
attribution: config.attribution,
maxZoom: 19
};
if (config.subdomains) {
options.subdomains = config.subdomains;
+12 -5
View File
@@ -92,12 +92,19 @@ const Meshtastic = (function() {
const defaultLon = -98.5795;
meshMap = L.map('meshMap').setView([defaultLat, defaultLon], 4);
window.meshMap = meshMap;
// Dark themed map tiles
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(meshMap);
// Use settings manager for tile layer (allows runtime changes)
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(meshMap);
Settings.registerMap(meshMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(meshMap);
}
// Handle resize
setTimeout(() => {
+12 -4
View File
@@ -2340,10 +2340,18 @@ sudo make install</code>
maxZoom: 15
});
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(radarMap);
// Use settings manager for tile layer (allows runtime changes)
window.radarMap = radarMap;
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(radarMap);
Settings.registerMap(radarMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(radarMap);
}
// Draw range rings after map is ready
setTimeout(() => drawRangeRings(), 100);
+12 -5
View File
@@ -390,11 +390,18 @@
zoomControl: true
});
// Dark themed map tiles
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(vesselMap);
// Use settings manager for tile layer (allows runtime changes)
window.vesselMap = vesselMap;
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(vesselMap);
Settings.registerMap(vesselMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(vesselMap);
}
// Add observer marker
observerMarker = L.circleMarker([observerLocation.lat, observerLocation.lon], {
+24 -9
View File
@@ -7590,12 +7590,19 @@
const initialZoom = (aprsUserLocation.lat || gpsLastPosition?.latitude) ? 8 : 4;
aprsMap = L.map('aprsMap').setView([initialLat, initialLon], initialZoom);
window.aprsMap = aprsMap;
// Dark themed map tiles
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(aprsMap);
// Use settings manager for tile layer (allows runtime changes)
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(aprsMap);
Settings.registerMap(aprsMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(aprsMap);
}
// Add user marker if GPS position is already available
if (gpsConnected && gpsLastPosition && gpsLastPosition.latitude && gpsLastPosition.longitude) {
@@ -8494,11 +8501,19 @@
zoomControl: true,
attributionControl: false
});
window.groundTrackMap = groundTrackMap;
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(groundTrackMap);
// Use settings manager for tile layer (allows runtime changes)
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(groundTrackMap);
Settings.registerMap(groundTrackMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(groundTrackMap);
}
// Add observer marker
const lat = parseFloat(document.getElementById('obsLat').value) || 51.5;
+12 -4
View File
@@ -416,10 +416,18 @@
worldCopyJump: true
});
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png?v=2', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19
}).addTo(groundMap);
// Use settings manager for tile layer (allows runtime changes)
window.groundMap = groundMap;
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(groundMap);
Settings.registerMap(groundMap);
} else {
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OSM</a> &copy; <a href="https://carto.com/">CARTO</a>',
maxZoom: 19,
subdomains: 'abcd'
}).addTo(groundMap);
}
}
function getLocation() {