Map: dark backdrop + reliable tile caching

Two fixes to the dark map + offline tiles:
- Dark backdrop: body.dark-map also darkens .leaflet-container (was #ddd), so
  the light Leaflet background no longer flashes bright between/behind tiles
  while zooming or where a tile is missing.
- Tile caching: createTile fetched the display <img> from the URL but cached
  via a SEPARATE fetch — on a flaky mobile link that second request often
  failed, so tiles showed but were never cached and re-zooming re-fetched them.
  Now one fetch caches and displays from the same blob, so every shown tile is
  cached. CSP already allows connect-src to the OSM tile host.

Verified on device: container bg rgb(27,31,36) under dark map; IndexedDB tile
cache populated.
This commit is contained in:
4aiman 2026-09-09 13:46:22 +03:00
commit 9798f152d8
2 changed files with 26 additions and 19 deletions

View file

@ -1149,6 +1149,9 @@ select {
/* Dark map: invert ONLY the tile layer (overlays — track, route, roads, puck — keep
their colours). User-tuned filter on OSM standard tiles. Applies to every Leaflet map. */
body.dark-map .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(1.5); }
/* Darken the map backdrop too, else the light Leaflet container (#ddd) flashes bright
between/behind tiles while zooming or where a tile is missing. */
body.dark-map .leaflet-container { background: #1b1f24; }
/* Always-on compass needle: red half = North, grey = South. Rotates to point to real north.
Top-RIGHT (zoom controls are top-left), below the status-bar safe area. */
/* Position/direction puck (SVG divIcon) — no default leaflet-div-icon box. */

View file

@ -130,29 +130,33 @@ TileCache.createLayer = function() {
createTile: function(coords, done) {
const tile = document.createElement("img");
const key = `${coords.z}/${coords.x}/${coords.y}`;
const url = `https://a.tile.openstreetmap.org/${key}.png`;
const show = (blob) => { tile.src = URL.createObjectURL(blob); done(null, tile); };
// Fetch ONCE: cache and display from the same response. The old code loaded the
// display <img> from the URL and cached via a SEPARATE fetch — on a flaky mobile
// link that second request often failed, so tiles showed but were never cached,
// and re-zooming re-fetched them. One fetch → every shown tile is also cached.
const fetchAndCache = () => {
fetch(url).then(async resp => {
if (!resp.ok) throw new Error("http " + resp.status);
const blob = await resp.blob();
putTile(key, blob).catch(() => {});
show(blob);
}).catch(() => {
// fetch blocked/failed → last resort plain <img> (no caching)
tile.src = url;
tile.onload = () => done(null, tile);
tile.onerror = () => done(null, tile);
});
};
getTile(key).then(blob => {
if (blob) {
tile.src = URL.createObjectURL(blob);
done(null, tile);
} else if (TileCache.offlineMode) {
// Offline: show empty tile
done(null, tile);
} else {
// Fetch from network
tile.crossOrigin = "";
tile.src = `https://a.tile.openstreetmap.org/${key}.png`;
tile.onload = () => {
fetch(tile.src).then(r => r.blob()).then(b => putTile(key, b)).catch(() => {});
done(null, tile);
};
tile.onerror = () => done(null, tile);
}
if (blob) { show(blob); }
else if (TileCache.offlineMode) { done(null, tile); } // offline + not cached → empty
else { fetchAndCache(); }
}).catch(() => {
if (TileCache.offlineMode) { done(null, tile); return; }
tile.src = `https://a.tile.openstreetmap.org/${key}.png`;
tile.onload = () => done(null, tile);
tile.onerror = () => done(null, tile);
fetchAndCache();
});
return tile;