功能说明
上一篇讲了实现聚合效果, 但是点击聚合效果无法获取到该聚合点包含的所有点信息
这一篇是对如何实现该功能的案例
实现
各属性说明需要自行去官网查阅
官网案例
聚合API
没空说废话了, 加班到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 = 0for (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 = falselet 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>