(1)使用场景:当聚合点位于多个要素的边界的时候,聚合点会根据距离进行聚合,忽略自身的属性,无法达到我们想要的效果。
(2)效果:采用的一种方式是 将聚合点按照不同面要素分为多个要素图层加载。
(3)代码:
HTML、CSS:
<head>
<meta charset="UTF-8" />
<title>Mapboxgl 分图层聚合</title>
<style>
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="../lib/js/geoglobe/mapbox-gl.css" type="text/css" />
<script type="text/javascript" src="../lib/js/geoglobe/mapbox-gl.js"></script>
<script type="text/javascript" src="../lib/js/turf/turf_new.min.js"></script>
<script type="text/javascript" src="../lib/js/interpolation/kriging_noModule.js"></script>
<!-- 行政区划数据 -->
<script src="./data/noName.js"></script>
<!-- 随机点数据 -->
<script src="./data/randomPoint.js"></script>
<body>
<div id="map"></div>
<script src="./js/mapboxCluster.js"></script>
</body>
</head>
JS:
let map; // 地图实例
const colorStops = {
stops: [
[0, '#ffffcc'],
[1, '#a1dab4'],
[2, '#41b6c4'],
[3, '#2c7fb8'],
[4, '#ffffcc'],
[5, '#253494'],
[6, '#fed976'],
[7, '#feb24c'],
[8, '#fd8d3c'],
[9, '#f03b20'],
[10, '#bd0026'],
[11, '#253494'],
[12, '#ffffcc'],
],
property: 'FID',
};
// 地图初始化
function init() {
map = new mapboxgl.Map({
container: 'map',
style: {
version: 8,
sources: {
cartodb: {
tiles: ['http://b.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'],
tileSize: 256,
type: 'raster',
},
},
layers: [
{
id: 'cartodb',
type: 'raster',
source: 'cartodb',
},
],
glyphs: '../../lib/pbf/{fontstack}/{range}.pbf', // 地图字体文件
},
center: [114.44515001943142, 30.649477958235423],
zoom: 8.3,
pitch: 0,
});
// 地图加载
map.on('load', () => {
addStateLayer();
});
}
// 聚合图层加载
function addClusterLayer(id, featureData) {
map.addSource('clusters' + id, {
type: 'geojson',
data: featureData,
cluster: true,
clusterRadius: 50,
});
// 聚合图层
map.addLayer({
id: 'clusters' + id,
type: 'circle',
source: 'clusters' + id,
filter: ['has', 'point_count'],
paint: {
'circle-color': ['step', ['get', 'point_count'], '#51bbd6', 4, '#f1f075', 7, '#f28cb1'],
'circle-radius': ['step', ['get', 'point_count'], 20, 4, 30, 7, 40],
},
});
// 聚合图层上的文字注记
map.addLayer({
id: 'cluster-count' + id,
type: 'symbol',
source: 'clusters' + id,
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['Open Sans Regular', 'Arial Unicode MS Regular'],
'text-size': 12,
},
});
// 单点图层
map.addLayer({
id: 'unclustered-point' + id,
type: 'circle',
source: 'clusters' + id,
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#11b4da',
'circle-radius': 4,
'circle-stroke-width': 1,
'circle-stroke-color': '#fff',
},
});
}
// 添加边界图层
function addStateLayer() {
let noNameFeatures = [];
noName.features.forEach((element) => {
noNameFeatures.push({
type: 'Feature',
properties: element.attributes,
geometry: {
type: 'Polygon',
coordinates: element.geometry.rings,
},
});
});
map.addSource('noName', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: noNameFeatures,
},
});
map.addLayer({
id: 'noName',
source: 'noName',
type: 'fill',
paint: {
'fill-color': colorStops,
'fill-opacity': 0.5,
'fill-outline-color': 'black',
},
});
// 判断 每个面要素中的点要素
var ptsWithin = [];
noNameFeatures.forEach((item) => {
ptsWithin.push(turf.pointsWithinPolygon(randomPoints, item)); // 使用turf.js库
});
// console.log(ptsWithin); // 查看 处理后的点要素
// 每组点要素分别添加聚合图层
ptsWithin.forEach((item, index) => {
addClusterLayer(index, item);
});
}
init();
(4)可能存在的问题:1,图层过多的时候可能不方便管理;2,图层存在叠加,一定程度会导致用户误解。