关于openlayers 做分类聚合操作

以前分类做分类聚合的时候,经常是写多个聚合图层,每个图层是一种分类,最近基于ol封装自己的代码框架时,也好奇的看了一下ol的聚合源码。发现一段有意思的代码。

我们先来看看ol实现聚合的代码:
ol/source/Cluster

  //  聚合的入口
  cluster() {
    if (this.resolution === undefined || !this.source) {
      return;
    }
    const extent = createEmpty();
    const mapDistance = this.distance * this.resolution;
    const features = this.source.getFeatures();

    /** @type {Object<string, true>} */
    const clustered = {};

    for (let i = 0, ii = features.length; i < ii; i++) {
      const feature = features[i];
      if (!(getUid(feature) in clustered)) {
        const geometry = this.geometryFunction(feature);
        if (geometry) {
          const coordinates = geometry.getCoordinates();
          createOrUpdateFromCoordinate(coordinates, extent);
          // 这里根据配置的distance以及当前feature的中心点计算一个矩形边界
          buffer(extent, mapDistance, extent);
		  // 这里筛选所有在这个矩形中的feature
          const neighbors = this.source
            .getFeaturesInExtent(extent)
            .filter(function (neighbor) {
              // 过滤掉已经在其他聚合点中的feature对象
              const uid = getUid(neighbor);
              if (uid in clustered) {
                return false;
              }
              clustered[uid] = true;
              return true;
            });
          this.features.push(this.createCluster(neighbors, extent));
        }
      }
    }
  }

大致的逻辑就是首先从所有要聚合的feature中得到一个聚合中心点,并根据范围生成矩形边框A,然后边框中的四个点就是这次聚合的要素,然后再查找下一个没有参与聚合的中心点,并根据范围生成矩形边框B矩形边框中的左上角因为在A中聚合过了,所以会被过滤掉,所以再知道这个代码逻辑后,我们这边就可以调整ol.source.Cluster中的代码了。
在这里插入图片描述
原理上面已经讲过了,这边就直接上改造后的代码吧

import Cluster from 'ol/source/Cluster'
import { buffer, createEmpty, createOrUpdateFromCoordinate } from 'ol/extent.js';
import { getUid } from 'ol/util.js';
class MyCluster extends Cluster{

  constructor(config){
    super(config)
    // 因为有业务需要,某几个点不加入聚合,所以这里扩展了这一个属性
    this.unClusterFunc = config.unClusterFunc
    // 需要提供类型字段,将会根据类型字段的值,自动进行分类聚合
    this.typeField = config.typeField
  }

  /**
   * 分组聚合
   */
  groupCluster(feature,clustered,extent,mapDistance){
    var geometry = this.geometryFunction(feature);
    if (geometry) {
        var coordinates = geometry.getCoordinates();
        createOrUpdateFromCoordinate(coordinates, extent);
        buffer(extent, mapDistance, extent);
        var neighbors = this.source.getFeaturesInExtent(extent);
        // 存在两个以上的点聚合
        if(neighbors.length > 1 && this.typeField){
          // 这次聚合按照当前中心点feature这一种类型进行
          let properties = feature.get('properties') || feature.getProperties()
          neighbors = neighbors.filter(neighbor=>{
            const pointProperties = neighbor.get('properties') || neighbor.getProperties()
            return pointProperties[this.typeField] === properties[this.typeField]
          })
        }
        // 先删除不需要聚合的点
        if(this.unClusterFunc){
          const unCluster = neighbors.filter(neighbor=>{
            return this.unClusterFunc(neighbor)
          })
          // 因为不需要聚合,所以这些点就直接单个展示,记录下这些要素
          unCluster.forEach(neighbor=>{
            var uid = getUid(neighbor);
            if (!(uid in clustered)) {
                clustered[uid] = true;
            }
            this.features.push(this.createCluster([neighbor],extent));
          })
          // 筛选除去不需要聚合的点后的几个点
          neighbors = neighbors.filter(neighbor=>{
            return !this.unClusterFunc(neighbor)
          })
        }
        
        // 需要聚合的点
        neighbors = neighbors.filter(function (neighbor) {
            var uid = getUid(neighbor);
            if (!(uid in clustered)) {
                clustered[uid] = true;
                return true;
            }
            else {
                return false;
            }
        });
        // 经过上面的操作后,可能会出现没有要聚合的点了,所以这里加一下判断
        if(neighbors.length > 0){
          this.features.push(this.createCluster(neighbors,extent));
        }
    }
  }

  /**
   * 覆盖了原生的聚合方法
   * @returns 
   */
  cluster(){
    if (this.resolution === undefined || !this.source) {
        return;
    }
    var extent = createEmpty();
    var mapDistance = this.distance * this.resolution;
    var features = this.source.getFeatures();
    /**
     * @type {!Object<string, boolean>}
     */
    var clustered = {};
    for (var i = 0, ii = features.length; i < ii; i++) {
        var feature = features[i];
        if (!(getUid(feature) in clustered)) {
          this.groupCluster(feature,clustered,extent,mapDistance)
        }
        
    }
  }
}
export default MyCluster
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值