使用addProtocol转换特性属性
使用自定义协议将属性转换为矢量瓦片;
<!DOCTYPE html>
<html lang="en">
<head>
<title>使用addProtocol转换特性属性</title>
<meta property="og:description" content="使用自定义协议将属性转换为矢量瓦片" />
<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>
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<div class="map-overlay top">
<div class="map-overlay-inner">
<h2>转换点击的大都市区域 (MSA) 人口</h2>
<p>点击任意区域以查看细节(人口数据来自<a href="https://www.census.gov/programs-surveys/metro-micro.html">美国人口普查局</a>)</p>
<div id="status">点击地图上的区域以查看人口</div>
</div>
</div>
<style>
.map-overlay {
position: absolute;
bottom: 0;
left: 0;
background: rgba(255, 255, 255, 0.8);
margin-right: 20px;
margin-top: 20px;
font-family: Arial, sans-serif;
overflow: auto;
border-radius: 3px;
}
.map-overlay-inner {
padding: 10px;
margin-bottom: 10px;
}
.map-overlay-inner h2 {
margin: 0 0 5px;
}
#status {
font-weight: bold;
margin-top: 10px;
}
a {
text-decoration: none;
color: #007bff;
}
</style>
<script>
// 本地更新处理器,将在我们的自定义协议中使用
function transformPropertiesProcessor(url, resourceType, responseCallback) {
// 从 transform: 协议中创建实际的URL
const actualUrl = url.replace('transform:', '');
fetch(actualUrl)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP错误!状态:${response.status}`);
}
return response.arrayBuffer();
})
.then((data) => {
// 调用MapLibre的回调处理器但传入一个转换函数
responseCallback(null, data, null, null, (feature) => {
// 对Feature对象进行处理以转换属性
if (feature.properties && feature.properties.POP) {
// 将人口值转换为数字
const pop = parseInt(feature.properties.POP);
// 删除原始的POP属性
delete feature.properties.POP;
// 创建友好的人口属性,格式化为千分位
feature.properties.formattedPop = pop.toLocaleString();
// 创建人口说明文本
feature.properties.popDescription = `${feature.properties.NAME} MSA 人口: ${pop.toLocaleString()}`;
}
return feature;
});
})
.catch((error) => {
console.error('获取资源时出错:', error);
responseCallback(error);
});
// 返回一个取消函数
return { cancel: () => {} };
}
// 注册transform协议
maplibregl.addProtocol('transform', transformPropertiesProcessor);
// 创建地图
const map = new maplibregl.Map({
container: 'map',
zoom: 3,
center: [-99, 38],
style: 'https://demotiles.maplibre.org/style.json'
});
const statusDiv = document.getElementById('status');
map.on('load', () => {
// 添加数据源,但现在使用我们的自定义协议转换属性
map.addSource('msa-population', {
type: 'vector',
tiles: [
'transform:https://maplibre.org/maplibre-gl-js/docs/assets/msa-population/{z}/{x}/{y}.pbf'
],
maxzoom: 5
});
// 添加MSA填充图层
map.addLayer({
id: 'msa-fill',
type: 'fill',
source: 'msa-population',
'source-layer': 'msa',
paint: {
'fill-color': [
'interpolate',
['linear'],
['to-number', ['get', 'POP']],
10000, '#ffffcc',
100000, '#c7e9b4',
500000, '#7fcdbb',
1000000, '#41b6c4',
5000000, '#2c7fb8',
10000000, '#253494'
],
'fill-opacity': 0.6
}
});
// 添加MSA边界线
map.addLayer({
id: 'msa-line',
type: 'line',
source: 'msa-population',
'source-layer': 'msa',
paint: {
'line-color': '#555',
'line-width': 1
}
});
// 显示指针悬停在MSA上
map.on('mouseenter', 'msa-fill', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'msa-fill', () => {
map.getCanvas().style.cursor = '';
});
// 设置点击交互以显示转换后的属性
map.on('click', 'msa-fill', (e) => {
if (e.features.length > 0) {
const feature = e.features[0];
// 使用转换后的popDescription属性
statusDiv.textContent = feature.properties.popDescription;
}
});
});
</script>
</body>
</html>