Bootstrap

arcgis for js点击聚合要素查询其包含的所有要素

功能说明

上一篇讲了实现聚合效果, 但是点击聚合效果无法获取到该聚合点包含的所有点信息

这一篇是对如何实现该功能的案例

在这里插入图片描述

实现

各属性说明需要自行去官网查阅

官网案例

聚合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 = 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>

;