如何为Mapbox GL JS中queryRenderedFeatures的GeoJSON输出添加高程数据?
给queryRenderedFeatures输出的GeoJSON要素添加高程值
核心思路
先提取GeoJSON中所有的坐标点,批量查询每个点的高程,再将高程值关联回原要素的属性或坐标中。以下是具体实现步骤和代码示例:
1. 提取GeoJSON中的所有坐标点
遍历要素集,根据几何类型(点、线、面)提取所有经纬度坐标,并记录每个坐标对应的要素索引(方便后续关联高程)。
// 提取坐标点并关联要素索引的函数 function extractCoordinates(geoJSON) { const pointWithIndices = []; geoJSON.features.forEach((feat, idx) => { switch (feat.geometry.type) { case 'Point': pointWithIndices.push({ lon: feat.geometry.coordinates[0], lat: feat.geometry.coordinates[1], index: idx }); break; case 'LineString': feat.geometry.coordinates.forEach((coord, coordIdx) => { pointWithIndices.push({ lon: coord[0], lat: coord[1], index: idx, coordIndex: coordIdx }); }); break; case 'Polygon': feat.geometry.coordinates.forEach((ring, ringIdx) => { ring.forEach((coord, coordIdx) => { pointWithIndices.push({ lon: coord[0], lat: coord[1], index: idx, ringIndex: ringIdx, coordIndex: coordIdx }); }); }); break; // 可扩展支持MultiPoint、MultiLineString等类型 } }); return pointWithIndices; }
2. 批量查询高程值
基于你已有的单点高程查询能力,封装批量查询逻辑,控制并发数避免请求过于频繁(防止被API限流)。
// 替换为你实际使用的单点高程查询函数 async function getElevation(lon, lat) { // 示例:调用高程API(请替换成你的实际接口或本地计算逻辑) const res = await fetch(`https://your-elevation-api-endpoint?lon=${lon}&lat=${lat}`); const data = await res.json(); return data.elevation; // 假设返回结果包含elevation字段 } // 批量查询高程,控制并发批次 async function batchGetElevations(points, batchSize = 5) { const results = []; for (let i = 0; i < points.length; i += batchSize) { const batch = points.slice(i, i + batchSize); const batchPromises = batch.map(async (point) => { const elevation = await getElevation(point.lon, point.lat); return {...point, elevation}; }); results.push(...await Promise.all(batchPromises)); // 可选:添加延迟降低请求频率 await new Promise(resolve => setTimeout(resolve, 100)); } return results; }
3. 将高程值写入原GeoJSON
根据之前记录的索引,把高程值写入对应要素的属性中(也可以选择将坐标扩展为[lon, lat, elevation]的三维格式)。
async function addElevationsToGeoJSON(geoJSON) { const points = extractCoordinates(geoJSON); const elevationResults = await batchGetElevations(points); elevationResults.forEach(result => { const targetFeature = geoJSON.features[result.index]; // 点要素:直接在属性中添加高程 if (targetFeature.geometry.type === 'Point') { targetFeature.properties.elevation = result.elevation; } // 线要素:按坐标索引存储高程数组 else if (targetFeature.geometry.type === 'LineString') { if (!targetFeature.properties.elevations) { targetFeature.properties.elevations = new Array(targetFeature.geometry.coordinates.length); } targetFeature.properties.elevations[result.coordIndex] = result.elevation; } // 面要素:按环和坐标索引存储高程 else if (targetFeature.geometry.type === 'Polygon') { if (!targetFeature.properties.elevations) { targetFeature.properties.elevations = new Array(targetFeature.geometry.coordinates.length); } if (!targetFeature.properties.elevations[result.ringIndex]) { targetFeature.properties.elevations[result.ringIndex] = new Array(targetFeature.geometry.coordinates[result.ringIndex].length); } targetFeature.properties.elevations[result.ringIndex][result.coordIndex] = result.elevation; } }); return geoJSON; }
4. 调用示例
// 假设renderedGeoJSON是queryRenderedFeatures返回的结果 const renderedGeoJSON = queryRenderedFeatures(...); addElevationsToGeoJSON(renderedGeoJSON).then(updatedGeoJSON => { console.log("已添加高程的GeoJSON:", updatedGeoJSON); // 保存到文件(Node.js环境) // const fs = require('fs'); // fs.writeFileSync('elevated-features.geojson', JSON.stringify(updatedGeoJSON)); });
注意事项
- 如果使用第三方高程API,务必关注其请求配额和限流规则,必要时降低并发数或增加请求间隔
- 离线场景下,可加载本地DEM数据集进行高程计算,无需依赖网络请求
- 可根据需求调整高程存储方式:比如将点坐标改为三维格式
[lon, lat, elevation],替代属性存储
内容的提问来源于stack exchange,提问作者dan
相关产品推荐
相关产品推荐

