fix: replace OSM tiles with ArcGIS for China network compatibility

- Switch primary tile provider from OpenStreetMap (blocked in China)
  to ArcGIS World Street Map (certified working)
- Add fallback chain: ArcGIS -> ArcGIS Gray -> OSM
- Auto-detect tile failures and fall back to next provider
- Clean up init sequence for reliable map rendering

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TianXuan Developer
2026-07-22 23:02:17 +08:00
parent eaf6cb4e67
commit 67013cf29b
@@ -664,10 +664,29 @@ function renderClusterCards(clusters) {
}
/* ── Step 4: Map & Visualization ──────────────────────── */
// Tile providers in priority order — ArcGIS works in China
const TILE_PROVIDERS = [
{
name: 'ArcGIS',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
attr: 'Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ'
},
{
name: 'ArcGIS Gray',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}',
attr: 'Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ'
},
{
name: 'OSM',
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
attr: '&copy; OpenStreetMap contributors'
},
];
function initMap() {
const container = document.getElementById('saMap');
if (SA.map) {
// Ensure container is visible and properly sized
container.style.height = '550px';
setTimeout(() => {
SA.map.invalidateSize();
@@ -675,7 +694,6 @@ function initMap() {
}, 200);
return;
}
// Wait for container to be visible, then init map
setTimeout(() => {
container.style.height = '550px';
// Start with global view [0, 0] zoom 2 as required
@@ -684,15 +702,35 @@ function initMap() {
zoom: 2,
worldCopyJump: true,
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors',
maxZoom: 18,
}).addTo(SA.map);
// Try each tile provider in order until one loads
tryTileProvider(0);
setTimeout(() => SA.map.invalidateSize(), 300);
renderMapData();
}, 250);
}
function tryTileProvider(idx) {
if (idx >= TILE_PROVIDERS.length || !SA.map) return;
const provider = TILE_PROVIDERS[idx];
const tileLayer = L.tileLayer(provider.url, {
attribution: provider.attr,
maxZoom: 18,
});
tileLayer.addTo(SA.map);
// Detect if tiles fail to load, try next provider
let tileError = false;
tileLayer.on('tileerror', () => {
if (!tileError) {
tileError = true;
console.warn('Tile provider failed:', provider.name);
SA.map.removeLayer(tileLayer);
tryTileProvider(idx + 1);
}
});
SA._tileLayer = tileLayer;
}
function renderMapData() {
if (!SA.map) return;