前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >openlayers中网格聚类的实现

openlayers中网格聚类的实现

作者头像
lzugis
发布2023-06-10 11:20:26
4640
发布2023-06-10 11:20:26
举报

概述

聚类是根据一定的规则将数据进行分类统计,常见的聚类方式有:1、基于行政区划;2、基于空间距离;3、基于业务字段。本文实现了基于固定大小的网格的聚类。

效果

在这里插入图片描述
在这里插入图片描述

实现

1. 数据源

本文的数据源为cesium示例中的全球的机场数据。

2. 实现代码

  1. 网格大小可配置,默认为64;
  2. 根据聚类的数量进行了分级颜色渲染;
代码语言:javascript
复制
class GridCluster {
  constructor(map, data, size = 64, showPoint = true) {
    this.map = map
    this.data = data.map(d => {
      d.coords = ol.proj.fromLonLat([d.lon, d.lat])
      return d
    })
    this.size = size
    this.val = 20037508.34
    this.showPoint = showPoint
    const source = new ol.source.Vector({
      features: []
    });
    const vector = new ol.layer.Vector({
      source: source,
      style: (feat) => {
        const count = feat.get('count')
        let color = `68, 149, 247`
        if(count > 20) {
          color = '165,0,179'
        } else if(count <= 20 && count > 15) {
          color = '255,10,10'
        } else if(count <= 15 &&count > 10) {
          color = '255,138,5'
        }
        else if(count <= 10 &&count > 5) {
          color = '247,176,76'
        }
        const colorPoint = '255,0,0'
        const stroke = new ol.style.Stroke({
          color: `rgba(${color}, 1)`,
          width: 1
        })
        const style = count && count > 0 ? {
          fill: new ol.style.Fill({
            color: `rgba(${color}, 0.35)`
          }),
          stroke: stroke,
          text: new ol.style.Text({
            text: count.toString(),
            font: 'bold 16px sans-serif',
            fill: new ol.style.Fill({
              color: '#000'
            }),
            stroke: new ol.style.Stroke({
              color: `rgba(255,255,255, 1)`,
              width: 1
            })
          })
        } : {
          image: new ol.style.Circle({
            fill: new ol.style.Fill({
              color: `rgba(${colorPoint}, 0.7)`
            }),
            stroke: new ol.style.Stroke({
              color: `rgba(${colorPoint}, 1)`,
              width: 1
            }),
            radius: 2
          }),
        }
        return new ol.style.Style(style)
      }
    });
    map.addLayer(vector)
    this.source = source
    const that = this
    this.map.on('movestart', () => {
      this.source.clear()
    })
    this.map.on('moveend', () => {
      that.addCluster()
    })
    that.addCluster()
  }

  addCluster() {
    const that = this
    const zoom = that.map.getView().getZoom()
    const res = that.map.getView().getResolutionForZoom(zoom) * that.size
    const [x1, y1, x2, y2] = that.map.getView().calculateExtent()
    const count = Math.ceil(this.val * 2 / res)
    let features = []
    const data = that.data.filter(({coords}) => {
      const [x, y] = coords
      return x >= x1 && x <= x2 && y >= y1 && y <= y2
    })
    for(let i = 0; i < count; i++) {
      const xmin = i * res - that.val
      const xmax = (i+1) * res - that.val
      for(let j = 0; j < count; j++) {
        const ymax = that.val - j * res
        const ymin = that.val - (j+1) * res
        const isInExtent = xmin >= x1 && xmin <= x2 && ymin >= y1 && ymin <= y2
          ||  xmax >= x1 && xmax <= x2 && ymin >= y1 && ymin <= y2
          ||  xmin >= x1 && xmin <= x2 && ymax >= y1 && ymax <= y2
          ||  xmax >= x1 && xmax <= x2 && ymax >= y1 && ymax <= y2
        if(isInExtent) {
          const dataFilter = [...data].filter(({coords}) => {
            const [x, y] = coords
            return x >= xmin && x <= xmax && y >= ymin && y <= ymax
          })
          const count = dataFilter.length
          if(count > 1) {
            features.push(new ol.Feature({
              geometry: ol.geom.Polygon.fromExtent([xmin, ymin, xmax, ymax]),
              count: count,
              data: dataFilter
            }))
          }
        }
      }
    }
    that.source.addFeatures(features)
    if(that.showPoint) {
      const features = data.map(d => {
        return new ol.Feature({
          geometry: new ol.geom.Point(d.coords),
          data: d
        })
      })
      that.source.addFeatures(features)
    }
  }
}

fetch('./flights.json').then(res => res.json()).then(res => {
  let {airports} = res
  airports = airports.map(([name, city, country, lon, lat]) => {
    return {name, city, country, lon, lat}
  })
  new GridCluster(map, airports)
})
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 效果
  • 实现
    • 1. 数据源
      • 2. 实现代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档