功能说明
上一篇讲了实现聚合效果, 但是点击聚合效果无法获取到该聚合点包含的所有点信息
这一篇是对如何实现该功能的案例
实现
各属性说明需要自行去官网查阅
没空说废话了, 加班到12点,得休息了, 直接运行代码看效果就行, 相关重点和注意事项都在代码注释里
该案例效果非实际项目效果, 提取出来的更通俗易懂
案例效果:
<!DOCTYPE html>
<html lang="zn">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
margin: 0;
}
#mapview {
position: absolute;
width: 100%;
height: 100%;
}
* {
margin: 0;
padding: 0;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.23/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.23/"></script>
</head>
<body>
<div id="mapview"></div>
<script>
require([
'esri/Map',
'esri/views/MapView',
'esri/layers/FeatureLayer',
'esri/Graphic'
], function (Map, MapView, FeatureLayer, Graphic) {
// 初始化底图
window.map = new Map({
basemap: 'dark-gray-vector'
})
// 创建2维视图
let view = new MapView({
container: 'mapview',
map: map,
zoom: 11,
center: [104.783916597735, 32.55699155692144] // 设置地图的初始化中心点坐标
})
// 生成100个随机点
var points = generateRandomPointsInPolygon(
[
[
[104.64487088240317, 32.66500681729125],
[104.91060269392625, 32.6635616904849],
[104.88210690535206, 32.54642886312837],
[104.68812954939528, 32.54787588095771]
]
],
100
)
// 创建聚合点
const features = points.map((point, index) => ({
geometry: {
type: 'point',
x: point[0],
y: point[1]
},
attributes: {
ObjectID: Math.random(),
name: `点${index + 1}`
}
}))
if (!features.length) {
return
}
console.log(features)
const featureLayer = new FeatureLayer({
source: features,
title: '生态因子点位图层',
objectIdField: 'ObjectID',
fields: [{ name: 'name', type: 'string' }],
outFields: ['*'],
popupTemplate: {
title: '{name}'
},
// 渲染成简单圆点
renderer: {
type: 'simple',
symbol: {
type: 'simple-marker',
color: 'red',
size: '10px',
outline: {
width: 1,
color: '#fff'
}
}
},
// 渲染额外的文本图形
labelingInfo: [
{
symbol: {
type: 'text',
color: '#fff',
// haloSize: 1,
// haloColor: '#fff',
backgroundColor: 'rgba(27,140,155,0.7)',
// xoffset: -22,
yoffset: 15,
horizontalAlignment: 'center',
font: { family: 'sans-serif', size: 8 }
},
labelPlacement: 'center-center',
labelExpressionInfo: { expression: '$feature.name' }
}
],
// 处理聚合
featureReduction: {
type: 'cluster',
clusterRadius: '40px',
clusterMinSize: '20px',
clusterMaxSize: '30px',
maxScale: 10000,
// 聚合的内置弹窗
popupTemplate: {
title: '包含 {cluster_count} 个点位.',
fieldInfos: [
{ fieldName: 'cluster_count', format: { places: 0, digitSeparator: true } }
]
},
// popupEnabled: false,
// 额外的文本图形
labelingInfo: [
{
deconflictionStrategy: 'none',
labelExpressionInfo: {
title: '数量',
expression: 'Text("聚合点:" + $feature.cluster_count + "个", "#,###")'
},
symbol: {
type: 'text',
color: '#ff0000',
haloSize: 1,
haloColor: '#fff',
// backgroundColor: 'rgba(27,140,155,0.7)',
// xoffset: -11.5,
// yoffset: 8,
horizontalAlignment: 'left',
font: { family: 'sans-serif', size: 12 }
},
labelPlacement: 'above-center'
}
]
}
})
map.add(featureLayer)
// 重点
view.whenLayerView(featureLayer).then(layerView => {
// 添加点击
view.on('click', async event => {
const { longitude, latitude } = event.mapPoint
// console.log('>>> 点击的坐标: ')
console.log(`${longitude}, ${latitude}`)
// 匹配元素
const { results } = await view.hitTest(event)
// 没有匹配到元素退出
if (!results?.length) {
return
}
// 取第一个元素, 如果要处理多个元素, 自行遍历
const { graphic, layer } = results[0]
// 判断该元素是否为聚合点
if (graphic.isAggregate === true) {
const aggregateId = graphic.getObjectId() // 聚合ID
// const aggregateId = graphic.attributes.aggregateId // 同上一样
// 判断对应图层, 可以根据需要去掉
if (graphic?.layer === featureLayer) {
// 创建查询对象
/**
* 重点, 一定要从layerView创建, 而不是featureLayer创建
* 我在这里踩了个大坑, 哎
*/
const query = layerView.createQuery()
query.aggregateIds = [aggregateId]
// 这里同样, 一定要从layerView查询, 而不是featureLayer查询
const { features } = await layerView.queryFeatures(query)
console.log('>>>>>>>> 聚合的要素', features)
alert('聚合的要素为:' + features.map(item => item.attributes.name).join(','))
}
}
})
})
// 生成随机点
function generateRandomPointsInPolygon(polygonCoords, number) {
// 判断是否在图形内
function isPointInsidePolygon(point, polygonCoords) {
let crossings = 0
for (let i = 0, j = polygonCoords[0].length - 1; i < polygonCoords[0].length; j = i++) {
const xi = polygonCoords[0][i][0]
const yi = polygonCoords[0][i][1]
const xj = polygonCoords[0][j][0]
const yj = polygonCoords[0][j][1]
if (
((yi <= point[1] && point[1] < yj) || (yj <= point[1] && point[1] < yi)) &&
point[0] < ((xj - xi) * (point[1] - yi)) / (yj - yi) + xi
) {
crossings++
}
}
return crossings % 2 !== 0
}
// 存储生成的随机点
let randomPoints = []
// 获取多边形的最小和最大经纬度范围
let minLat = polygonCoords[0][0][1]
let maxLat = polygonCoords[0][0][1]
let minLng = polygonCoords[0][0][0]
let maxLng = polygonCoords[0][0][0]
for (let i = 0; i < polygonCoords[0].length; i++) {
const lat = polygonCoords[0][i][1]
const lng = polygonCoords[0][i][0]
if (lat < minLat) {
minLat = lat
}
if (lat > maxLat) {
maxLat = lat
}
if (lng < minLng) {
minLng = lng
}
if (lng > maxLng) {
maxLng = lng
}
}
for (let i = 0; i < number; i++) {
let isPointInside = false
let randomPoint
// 不断尝试生成随机点,直到点在多边形内
while (!isPointInside) {
// 在多边形的经纬度范围内随机生成一个点
const randomLat = minLat + (maxLat - minLat) * Math.random()
const randomLng = minLng + (maxLng - minLng) * Math.random()
randomPoint = [randomLng, randomLat]
// 使用射线法判断点是否在多边形内
isPointInside = isPointInsidePolygon(randomPoint, polygonCoords)
}
randomPoints.push(randomPoint)
}
return randomPoints
}
})
</script>
</body>
</html>