| | |
| | | */ |
| | | export const getAutoScaleBySites = (sites: any[]) => { |
| | | if (!Array.isArray(sites) || sites.length === 0) return null; |
| | | if (sites.length === 1) return 16; |
| | | const validSites = sites |
| | | .map((site) => ({ |
| | | latitude: Number(site?.latitude), |
| | | longitude: Number(site?.longitude) |
| | | })) |
| | | .filter((site) => Number.isFinite(site.latitude) && Number.isFinite(site.longitude)); // 过滤无效坐标点位 |
| | | if (validSites.length === 0) return null; |
| | | if (validSites.length === 1) return 16; |
| | | |
| | | const resolveScaleByDiagonal = (diagonalMeters: number) => { |
| | | if (diagonalMeters > 12000) return 11; |
| | | if (diagonalMeters > 8000) return 12; |
| | | if (diagonalMeters > 5000) return 13; |
| | | if (diagonalMeters > 3000) return 14; |
| | | if (diagonalMeters > 1500) return 15; |
| | | if (diagonalMeters > 800) return 16; |
| | | return 17; |
| | | }; // 统一距离到缩放等级的映射规则 |
| | | |
| | | const nearbyCounts = validSites.map((targetSite, targetIndex) => { |
| | | return validSites.reduce((count, compareSite, compareIndex) => { |
| | | if (targetIndex === compareIndex) return count; // 密度统计不包含自身 |
| | | const meters = getDistance(targetSite.latitude, targetSite.longitude, compareSite.latitude, compareSite.longitude); |
| | | return meters <= 1000 ? count + 1 : count; |
| | | }, 0); |
| | | }); // 每个点位在 1km 半径内的“邻居点”数量 |
| | | const maxNearbyCount = Math.max(...nearbyCounts); |
| | | |
| | | // 高密度区:1km 内点位 > 5(按邻居数统计),固定精细视角。 |
| | | if (maxNearbyCount > 5) return 17; |
| | | |
| | | // 低密度区:1km 内点位 < 2,自动缩小到至少可见 3 个点位。 |
| | | if (maxNearbyCount < 2 && validSites.length >= 3) { |
| | | const radiusNeedForThreePoints = validSites.reduce((maxRadius, baseSite) => { |
| | | const neighborDistances = validSites |
| | | .filter((site) => site !== baseSite) |
| | | .map((site) => getDistance(baseSite.latitude, baseSite.longitude, site.latitude, site.longitude)) |
| | | .sort((a, b) => a - b); |
| | | const radius = neighborDistances[1]; // 包含 2 个邻居时即可在屏幕中达到 3 个点位 |
| | | if (!Number.isFinite(radius)) return maxRadius; |
| | | return Math.max(maxRadius, radius); |
| | | }, 0); // 取最大半径,确保低密度点位也能满足“至少 3 点可见” |
| | | if (radiusNeedForThreePoints > 0) { |
| | | return resolveScaleByDiagonal(radiusNeedForThreePoints * 2); |
| | | } |
| | | } |
| | | |
| | | let minLat = Number.POSITIVE_INFINITY; |
| | | let maxLat = Number.NEGATIVE_INFINITY; |
| | | let minLng = Number.POSITIVE_INFINITY; |
| | | let maxLng = Number.NEGATIVE_INFINITY; |
| | | sites.forEach((site) => { |
| | | const lat = Number(site?.latitude); |
| | | const lng = Number(site?.longitude); |
| | | if (!Number.isFinite(lat) || !Number.isFinite(lng)) return; |
| | | if (lat < minLat) minLat = lat; |
| | | if (lat > maxLat) maxLat = lat; |
| | | if (lng < minLng) minLng = lng; |
| | | if (lng > maxLng) maxLng = lng; |
| | | validSites.forEach((site) => { |
| | | if (site.latitude < minLat) minLat = site.latitude; |
| | | if (site.latitude > maxLat) maxLat = site.latitude; |
| | | if (site.longitude < minLng) minLng = site.longitude; |
| | | if (site.longitude > maxLng) maxLng = site.longitude; |
| | | }); |
| | | if (!Number.isFinite(minLat) || !Number.isFinite(maxLat) || !Number.isFinite(minLng) || !Number.isFinite(maxLng)) { |
| | | return null; |
| | | } |
| | | const diagonalMeters = getDistance(minLat, minLng, maxLat, maxLng); |
| | | if (diagonalMeters > 12000) return 11; |
| | | if (diagonalMeters > 8000) return 12; |
| | | if (diagonalMeters > 5000) return 13; |
| | | if (diagonalMeters > 3000) return 14; |
| | | if (diagonalMeters > 1500) return 15; |
| | | if (diagonalMeters > 800) return 16; |
| | | return 17; |
| | | return resolveScaleByDiagonal(diagonalMeters); |
| | | }; |
| | | |
| | | /** |