使用REST API添加DeckGL图层
演示如何使用DeckGL和ArcGIS REST API查询添加要素图层;
<!DOCTYPE html>
<html lang="en">
<head>
<title>使用REST API添加DeckGL图层</title>
<meta property="og:description" content="演示如何使用DeckGL和ArcGIS REST API查询添加要素图层" />
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl@5.5.0/dist/maplibre-gl.js'></script>
<script src='https://unpkg.com/deck.gl@^8.8.0/dist.min.js'></script>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
// 用MapLibre初始化地图
const map = new maplibregl.Map({
container: 'map',
style:
'https://demotiles.maplibre.org/styles/osm-bright-gl-style/style.json',
center: [-88.05599295464829, 41.7138747959222],
zoom: 10
});
// 从ArcGIS Feature服务获取数据
async function loadFeatureLayer() {
// 芝加哥西部的分队
const url =
'https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Chicago_Fire_Precincts_2022/FeatureServer/0/query?where=1%3D1&outFields=*&geometryPrecision=6&outSR=4326&f=pgeojson';
const response = await fetch(url);
return await response.json();
}
// 创建一个DeckGL ScatterplotLayer用于覆盖maplibre-gl
function renderDeckLayer(data) {
// 参考:https://deck.gl/docs/api-reference/layers/geojson-layer
const geoJsonLayer = new deck.GeoJsonLayer({
id: 'firePrecinctArcGis',
data,
opacity: 0.8,
lineJointRounded: true,
stroked: true,
filled: true,
extruded: false,
wireframe: true,
lineWidthMinPixels: 2,
getLineColor: [255, 0, 0],
getFillColor: (d) => {
// 覆盖区域 1 = red, 2 = blue, 3 = green, 4 = navy, 5 = yellow, etc.
const area = d.properties.AREA;
if (area === 1) return [255, 0, 0, 100];
if (area === 2) return [0, 0, 255, 100];
if (area === 3) return [0, 255, 0, 100];
if (area === 4) return [0, 0, 139, 100];
if (area === 5) return [255, 255, 0, 100];
// 使用随机颜色
return [
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
100
];
},
// 当悬停在多边形上时,显示工具提示
pickable: true,
autoHighlight: true,
onHover: (info, event) => {
// 如果用户悬停在要素上,则显示工具提示
const el = document.getElementById('tooltip');
if (info.object) {
const properties = info.object.properties;
const tooltip = `
<div>
<p>覆盖区域: ${properties.AREA}</p>
<p>分队: ${properties.BN}</p>
</div>
`;
el.innerHTML = tooltip;
el.style.display = 'block';
el.style.left = `${info.x}px`;
el.style.top = `${info.y}px`;
} else {
// 如果用户没有悬停在任何要素上,隐藏工具提示
el.style.display = 'none';
}
}
});
// 创建一个DeckGL重叠到地图上
const deckgl = new deck.Deck({
canvas: 'deck-canvas',
width: '100%',
height: '100%',
initialViewState: {
longitude: map.getCenter().lng,
latitude: map.getCenter().lat,
zoom: map.getZoom(),
bearing: map.getBearing(),
pitch: map.getPitch()
},
controller: false,
onViewStateChange: ({viewState}) => {
const {lng, lat} = new maplibregl.LngLat(
viewState.longitude,
viewState.latitude
);
// 保持地图和DeckGL图层同步
map.jumpTo({
center: [lng, lat],
zoom: viewState.zoom,
bearing: viewState.bearing,
pitch: viewState.pitch
});
},
layers: [geoJsonLayer]
});
// 将地图移动和DeckGL图层同步
map.on('move', () => {
const {lng, lat} = map.getCenter();
deckgl.setProps({
viewState: {
longitude: lng,
latitude: lat,
zoom: map.getZoom(),
bearing: map.getBearing(),
pitch: map.getPitch()
}
});
});
}
// 添加工具提示元素到DOM
const tooltip = document.createElement('div');
tooltip.id = 'tooltip';
tooltip.style.position = 'absolute';
tooltip.style.zIndex = 1;
tooltip.style.pointerEvents = 'none';
tooltip.style.backgroundColor = 'white';
tooltip.style.padding = '5px';
tooltip.style.borderRadius = '5px';
tooltip.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.2)';
tooltip.style.display = 'none';
document.body.appendChild(tooltip);
// 添加DeckGL画布到地图
const deckCanvas = document.createElement('canvas');
deckCanvas.id = 'deck-canvas';
deckCanvas.style.pointerEvents = 'none';
deckCanvas.style.position = 'absolute';
deckCanvas.style.bottom = '0';
deckCanvas.style.left = '0';
deckCanvas.style.width = '100%';
deckCanvas.style.height = '100%';
// 将DeckGL画布添加到地图容器,这样它就位于GL画布之上
map.getContainer().appendChild(deckCanvas);
map.on('load', async () => {
// 加载图层数据
const data = await loadFeatureLayer();
renderDeckLayer(data);
});
</script>
</body>
</html>