如何在Leaflet中通过经纬度获取海拔(不使用Google Elevation)
Leaflet 无Google Elevation获取海拔的可行方案
以下是几个无需依赖Google Elevation的可行方案,可实现你需要的点击地图获取对应经纬度海拔的功能:
1. 免费开源:OpenTopoData API
OpenTopoData提供免费的全球海拔查询接口,支持单点/批量经纬度查询,非商用场景无需API密钥,数据精度可选(如srtm30m、eudem25m等)。
示例代码
// 经纬度转海拔的异步函数 async function getElevation(lat, lng) { try { const res = await fetch(`https://api.opentopodata.org/v1/eudem25m?locations=${lat},${lng}`); const data = await res.json(); return data.results[0]?.elevation || null; } catch (err) { console.error('海拔查询失败:', err); return null; } } // 绑定Leaflet地图点击事件 map.on('click', async (e) => { const { lat, lng } = e.latlng; const elevation = await getElevation(lat, lng); const popupContent = elevation !== null ? `海拔:${elevation.toFixed(2)} 米` : '无法获取海拔数据'; L.popup() .setLatLng(e.latlng) .setContent(popupContent) .openOn(map); });
2. 离线/本地部署:NASA SRTM瓦片服务
如果需要避免依赖外部API,可下载NASA的SRTM海拔瓦片,搭建本地瓦片服务后直接解析像素值获取海拔,完全免费且离线可用。
实现步骤&代码
- 从USGS渠道下载SRTM瓦片数据,或使用预生成的瓦片集
- 用
tileserver-gl等工具搭建本地瓦片服务(示例地址:http://localhost:8080/srtm/{z}/{x}/{y}.png) - 解析瓦片像素值转换为海拔:
function getElevationFromLocalTile(lat, lng) { return new Promise((resolve, reject) => { const zoom = map.getZoom(); const tileSize = map.getTileSize(); const point = map.project(L.latLng(lat, lng), zoom); const tileX = Math.floor(point.x / tileSize.x); const tileY = Math.floor(point.y / tileSize.y); const offsetX = Math.floor(point.x % tileSize.x); const offsetY = Math.floor(point.y % tileSize.y); const img = new Image(); img.crossOrigin = 'anonymous'; img.src = `http://localhost:8080/srtm/${zoom}/${tileX}/${tileY}.png`; img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = tileSize.x; canvas.height = tileSize.y; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); const pixel = ctx.getImageData(offsetX, offsetY, 1, 1).data; // SRTM瓦片RGB转海拔公式,需匹配你的瓦片生成规则 const elevation = (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) - 10000; resolve(elevation); }; img.onerror = () => reject('瓦片加载失败'); }); } // 地图点击事件调用 map.on('click', async (e) => { try { const elevation = await getElevationFromLocalTile(e.latlng.lat, e.latlng.lng); L.popup() .setLatLng(e.latlng) .setContent(`海拔:${elevation.toFixed(2)} 米`) .openOn(map); } catch (err) { L.popup() .setLatLng(e.latlng) .setContent('无法获取海拔数据') .openOn(map); } });
3. 高精度选项:Mapbox Elevation API
如果可以接受非Google的商业免费API,Mapbox提供高精度的海拔数据,免费额度足够个人项目使用,需注册获取免费API密钥。
示例代码
// 替换为你的Mapbox免费API密钥 const MAPBOX_KEY = '你的Mapbox密钥'; async function getElevationByMapbox(lat, lng) { try { const zoom = map.getZoom(); const point = map.project(L.latLng(lat, lng), zoom); const tileX = Math.floor(point.x / 256); const tileY = Math.floor(point.y / 256); const res = await fetch(`https://api.mapbox.com/v4/mapbox.terrain-rgb/${zoom}/${tileX}/${tileY}.pngraw?access_token=${MAPBOX_KEY}`); const buffer = await res.arrayBuffer(); const data = new Uint8Array(buffer); const x = Math.floor(point.x % 256); const y = Math.floor(point.y % 256); const idx = (y * 256 + x) * 4; const r = data[idx]; const g = data[idx + 1]; const b = data[idx + 2]; // Mapbox地形瓦片的海拔转换公式 const elevation = (r * 256 * 256 + g * 256 + b) * 0.1 - 10000; return elevation; } catch (err) { console.error('海拔查询失败:', err); return null; } } // 绑定地图点击事件 map.on('click', async (e) => { const elevation = await getElevationByMapbox(e.latlng.lat, e.latlng.lng); const popupContent = elevation !== null ? `海拔:${elevation.toFixed(2)} 米` : '无法获取海拔数据'; L.popup() .setLatLng(e.latlng) .setContent(popupContent) .openOn(map); });
内容的提问来源于stack exchange,提问作者refa
相关产品推荐
相关产品推荐

