#MapLibre GL JS加载ArcGis Terrain3D地形#
很惭愧代码基本由Google Gemini生成,生成的原始代码在转换上有些错误,我给了提示它给出了修复代码片段。我将代码片段替换到原始代码去,一切工作正常。仅此而已!我甚至不知道以后没有AI助手我还能不能继续写代码。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>MapLibre GL 加载arcgis terrain3D</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<link href="https://unpkg.com/maplibre-gl@5.16.0/dist/maplibre-gl.css" rel="stylesheet" />
<script src="https://unpkg.com/maplibre-gl@5.16.0/dist/maplibre-gl.js"></script>
<script type="text/javascript" src="https://unpkg.com/lerc@latest/LercDecode.min.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
.controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 1;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
font-family: sans-serif;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="controls">
<strong>MapLibre GL 加载arcgis terrain3D</strong><br>
Google Gemini生成代码
</div>
<script>
const map = new maplibregl.Map({
container: 'map',
// style: 'https://demotiles.maplibre.org/style.json', // 默认底图
style: {
"version": 8,
// "glyphs": "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf",
"sources": {
"source-satellite": {
"type": "raster",
"tiles": ["https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png"],
"tileSize": 256,
"minzoom": 0,
"maxzoom": 20
},
"arcgisTerrainSource": {
"type": "raster-dem",
"tiles": ["arcgis-lerc://server.arcgisonline.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer/tile/{z}/{y}/{x}"],
"tileSize": 256,
"encoding": "mapbox"
}
},
"layers": [
{
"id": "base-layer-satellite",
"type": "raster",
"source": "source-satellite",
"layout": {
"visibility": "visible"
}
}
]
},
center: [113.53658048252841, 37.70555767579111],
zoom: 3
});
map.on('load', () => {
// acgis地形图
Lerc.load().then(()=>{
/**
* 自定义协议:将 ArcGIS LERC 转换为 MapLibre 识别的 DEM 数据
*/
maplibregl.addProtocol('arcgis-lerc', async (params, abortController) => {
const url = params.url.replace('arcgis-lerc://', 'https://');
const t = await fetch(url);
if (t.status == 200) {
const buffer = await t.arrayBuffer();
const decodedData = Lerc.decode(buffer);
const { width, height, pixels } = decodedData;
// MapLibre 的地形要求:
// 1. 数据必须是经过 RGB 编码的图像,或者直接返回解码后的浮点数组(取决于版本)
// 2. 这里我们手动将浮点数转换为 MapLibre 预期的格式
const imageData = new Uint8ClampedArray(width * height * 4);
for (let i = 0; i < pixels[0].length; i++) {
const elevation = pixels[0][i];
// 这里是一个简化的 Mapbox Terrain-RGB 编码逻辑
// 实际上 MapLibre 的某些版本支持更直接的返回,但这里使用通用转换
const value = Math.round((elevation + 10000) * 10);
imageData[i * 4] = (value >> 16) & 255;
imageData[i * 4 + 1] = (value >> 8) & 255;
imageData[i * 4 + 2] = value & 255;
imageData[i * 4 + 3] = 255;
}
const newImg = new ImageData(imageData, width, height);
const imageBitmap = await createImageBitmap(newImg);
return { data: imageBitmap };
// return { data: imageData, width, height };
} else {
throw new Error(`Tile fetch error: ${t.statusText}`);
}
});
map.setTerrain({
source: 'arcgisTerrainSource',
exaggeration: 1.0
});
});
});
</script>
</body>
</html>