Spaces:
Running
Running
Download admin/js/maps/map-coordinate.js from Tataaicoltd/tools: direct link, hf CLI and curl.
- Browser
- Download file 8.7 kB
-
https://huggingface.co/spaces/Tataaicoltd/tools/resolve/main/admin/js/maps/map-coordinate.js
- Command line
-
hf download hf://spaces/Tataaicoltd/tools/admin/js/maps/map-coordinate.js
-
curl -L -o map-coordinate.js https://huggingface.co/spaces/Tataaicoltd/tools/resolve/main/admin/js/maps/map-coordinate.js
8.7 kB
| // ========================= | |
| // CONFIG map-coordinate.js | |
| // ========================= | |
| // Tile-center interpolation β mα»i tile cΓ³ center lat/lon chΓnh xΓ‘c tα»« | |
| // url_index.txt, dΓΉng lΓ m anchor Δα» tΓnh offset sub-tile β giαΊ£m tα»i Δa sai sα». | |
| // | |
| // Grid: 23 cols Γ 42 rows = 966 tiles, mα»i tile 2400Γ1442 px native. | |
| // url_index.txt format: idx;lat;lon (center cα»§a tile, 1-indexed) | |
| // | |
| // TαΊ‘i sao Γt sai sα» hΖ‘n: | |
| // CΕ©: anchor top-left β offset tΓch lΕ©y 42 hΓ ng β ~0.0015Β° (~165m) | |
| // Mα»i: anchor center tile hiα»n tαΊ‘i (ground-truth) β offset β€ nα»a tile β <5m | |
| const _TC_COLS = 23; | |
| const _TC_ROWS = 42; | |
| const _TC_TW = 2400; // tile width (native px) | |
| const _TC_TH = 1442; // tile height (native px) | |
| // Global-average lat/lon per pixel (dΓΉng Δα» Ζ°α»c lượng tile + fallback) | |
| // lat step β 0.0075633Β°/row Γ· 1442 px β 5.245e-6 Β°/px | |
| // lon step β 0.0128531Β°/col Γ· 2400 px β 5.355e-6 Β°/px | |
| const _AVG_LAT_PP = 5.245e-6; | |
| const _AVG_LON_PP = 5.355e-6; | |
| // _tileCenters[idx] = {lat, lon}, 1-indexed (idx 1..966) | |
| window._tileCenters = null; | |
| // ββ Loader ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.loadTileCenters = async function () { | |
| if (window._tileCenters) return; | |
| try { | |
| const res = await fetch('url_index.txt'); | |
| const text = await res.text(); | |
| const centers = new Array(_TC_COLS * _TC_ROWS + 2); | |
| text.trim().split('\n').forEach(line => { | |
| const p = line.trim().split(';'); | |
| if (p.length < 3) return; | |
| const idx = parseInt(p[0], 10); | |
| const lat = parseFloat(p[1]); | |
| const lon = parseFloat(p[2]); | |
| if (!isNaN(idx) && !isNaN(lat) && !isNaN(lon) && | |
| idx >= 1 && idx <= _TC_COLS * _TC_ROWS) { | |
| centers[idx] = { lat, lon }; | |
| } | |
| }); | |
| window._tileCenters = centers; | |
| console.log('[map-coordinate] Loaded', _TC_COLS * _TC_ROWS, | |
| 'tile centers from url_index.txt'); | |
| } catch (e) { | |
| console.warn('[map-coordinate] Cannot load url_index.txt β using fallback.', e); | |
| } | |
| }; | |
| // BαΊ―t ΔαΊ§u fetch ngay khi script load (fire-and-forget) | |
| window.loadTileCenters(); | |
| // ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** Center {lat,lon} cα»§a tile tαΊ‘i display (row, col) β 0-indexed */ | |
| function _tc(row, col) { | |
| row = Math.max(0, Math.min(_TC_ROWS - 1, row)); | |
| col = Math.max(0, Math.min(_TC_COLS - 1, col)); | |
| return window._tileCenters[row * _TC_COLS + col + 1] || { lat: 0, lon: 0 }; | |
| } | |
| /** | |
| * Lat/lon per pixel cα»₯c bα» cho tile (row, col). | |
| * DΓΉng center-to-center distance cα»§a tiles kα» bΓͺn. | |
| * NαΊΏu tile irregular (cuα»i map), clamp vα» global average. | |
| */ | |
| function _localScale(row, col) { | |
| let latPerPx, lonPerPx; | |
| if (row > 0 && row < _TC_ROWS - 1) { | |
| latPerPx = (_tc(row - 1, col).lat - _tc(row + 1, col).lat) / (2 * _TC_TH); | |
| } else if (row === 0) { | |
| latPerPx = (_tc(0, col).lat - _tc(1, col).lat) / _TC_TH; | |
| } else { | |
| latPerPx = (_tc(_TC_ROWS - 2, col).lat - _tc(_TC_ROWS - 1, col).lat) / _TC_TH; | |
| } | |
| if (col > 0 && col < _TC_COLS - 1) { | |
| lonPerPx = (_tc(row, col + 1).lon - _tc(row, col - 1).lon) / (2 * _TC_TW); | |
| } else if (col === 0) { | |
| lonPerPx = (_tc(row, 1).lon - _tc(row, 0).lon) / _TC_TW; | |
| } else { | |
| lonPerPx = (_tc(row, _TC_COLS - 1).lon - _tc(row, _TC_COLS - 2).lon) / _TC_TW; | |
| } | |
| // Clamp nαΊΏu tile irregular lΓ m scale lα»ch > 3Γ | |
| if (latPerPx < _AVG_LAT_PP * 0.3 || latPerPx > _AVG_LAT_PP * 3) latPerPx = _AVG_LAT_PP; | |
| if (lonPerPx < _AVG_LON_PP * 0.3 || lonPerPx > _AVG_LON_PP * 3) lonPerPx = _AVG_LON_PP; | |
| return { latPerPx, lonPerPx }; | |
| } | |
| // ββ Fallback tuyαΊΏn tΓnh (trΖ°α»c khi url_index.txt load xong) βββββββββββββββββ | |
| const _FB_TL_LAT = 10.947849, _FB_TL_LON = 106.532560; | |
| const _FB_BR_LAT = 10.940261, _FB_BR_LON = 106.545442; | |
| function _fallbackPixelToLatLon(left, top, scale) { | |
| const lonPP = (_FB_BR_LON - _FB_TL_LON) / _TC_TW; | |
| const latPP = (_FB_TL_LAT - _FB_BR_LAT) / _TC_TH; | |
| const nx = (left + 1) / scale, ny = (top + 1) / scale; | |
| return { lat: _FB_TL_LAT - ny * latPP, lon: _FB_TL_LON + nx * lonPP }; | |
| } | |
| function _fallbackLatLonToPixel(lat, lon, scale) { | |
| const lonPP = (_FB_BR_LON - _FB_TL_LON) / _TC_TW; | |
| const latPP = (_FB_TL_LAT - _FB_BR_LAT) / _TC_TH; | |
| return { | |
| left: (((lon - _FB_TL_LON) / lonPP) * scale) - 1, | |
| top: (((_FB_TL_LAT - lat) / latPP) * scale) - 1, | |
| }; | |
| } | |
| // ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // pixelToLatLon | |
| // | |
| // 1. Native px: undo scale + 1px offset | |
| // 2. Floor-divide β xΓ‘c Δα»nh tile nΓ o Δang click (display row/col) | |
| // 3. Anchor = center lat/lon cα»§a tile (ground-truth tα»« url_index.txt) | |
| // 4. Sub-tile offset (native px tα»« center) Γ local scale β delta lat/lon | |
| // ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.pixelToLatLon = function (left, top, scale) { | |
| scale = scale || 1; | |
| if (!window._tileCenters) return _fallbackPixelToLatLon(left, top, scale); | |
| const nx = (left + 1) / scale; | |
| const ny = (top + 1) / scale; | |
| const col = Math.max(0, Math.min(_TC_COLS - 1, Math.floor(nx / _TC_TW))); | |
| const row = Math.max(0, Math.min(_TC_ROWS - 1, Math.floor(ny / _TC_TH))); | |
| const cx = (col + 0.5) * _TC_TW; | |
| const cy = (row + 0.5) * _TC_TH; | |
| const center = _tc(row, col); | |
| const { latPerPx, lonPerPx } = _localScale(row, col); | |
| const dx = nx - cx; // native px, + = ΔΓ΄ng | |
| const dy = ny - cy; // native px, + = nam | |
| return { | |
| lat: center.lat - dy * latPerPx, | |
| lon: center.lon + dx * lonPerPx, | |
| }; | |
| }; | |
| // ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // latLonToPixel | |
| // | |
| // 1. Ζ―α»c lượng display tile tα»« tile #1 center + global-average scale | |
| // 2. TΓ¬m kiαΊΏm 3Γ3 window β tile center gαΊ§n nhαΊ₯t vα»i (lat, lon) | |
| // 3. Anchor + sub-tile offset β scaled pixel | |
| // ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.latLonToPixel = function (lat, lon, scale) { | |
| scale = scale || 1; | |
| if (!window._tileCenters) return _fallbackLatLonToPixel(lat, lon, scale); | |
| // 1. Ζ―α»c lượng tα»« tile #1 center | |
| const c1 = window._tileCenters[1]; | |
| const approxRow = Math.round((c1.lat - lat) / (_AVG_LAT_PP * _TC_TH)); | |
| const approxCol = Math.round((lon - c1.lon) / (_AVG_LON_PP * _TC_TW)); | |
| // 2. TΓ¬m tile center gαΊ§n nhαΊ₯t trong 3Γ3 window | |
| let bestRow = Math.max(0, Math.min(_TC_ROWS - 1, approxRow)); | |
| let bestCol = Math.max(0, Math.min(_TC_COLS - 1, approxCol)); | |
| let bestDist = Infinity; | |
| const rMin = Math.max(0, approxRow - 1), rMax = Math.min(_TC_ROWS - 1, approxRow + 1); | |
| const cMin = Math.max(0, approxCol - 1), cMax = Math.min(_TC_COLS - 1, approxCol + 1); | |
| for (let r = rMin; r <= rMax; r++) { | |
| for (let c = cMin; c <= cMax; c++) { | |
| const t = _tc(r, c); | |
| const d = (lat - t.lat) ** 2 + (lon - t.lon) ** 2; | |
| if (d < bestDist) { bestDist = d; bestRow = r; bestCol = c; } | |
| } | |
| } | |
| // 3. Anchor + sub-tile offset β scaled pixel | |
| const center = _tc(bestRow, bestCol); | |
| const { latPerPx, lonPerPx } = _localScale(bestRow, bestCol); | |
| const dx = (lon - center.lon) / lonPerPx; // native px, + = ΔΓ΄ng | |
| const dy = (center.lat - lat) / latPerPx; // native px, + = nam | |
| const cx = (bestCol + 0.5) * _TC_TW; | |
| const cy = (bestRow + 0.5) * _TC_TH; | |
| return { | |
| left: (cx + dx) * scale - 1, | |
| top: (cy + dy) * scale - 1, | |
| }; | |
| }; |