说说地图中的聚类

概述

虽然Openlayers4会有自带的聚类效果,但是有些时候是不能满足我们的业务场景的,本文结合一些业务场景,讲讲地图中的聚类展示。

需求

在级别比较小的时候聚类展示数据,当级别大于一定的级别的时候讲地图可视域内的所有点不做聚类全部展示出来。

效果

实现

在实现的时候,自己写了一个很简单的扩展myclusterlayer,代码如下:

var myClusterLayer = function (options) {
    var self = this;
    var defaults = {
        map: null,
        clusterField: "",
        zooms: [4, 8, 12],
        distance: 256,
        data: [],
        style: null
    };

    //将default和options合并
    self.options = $.extend({}, defaults, options);

    self.proj = self.options.map.getView().getProjection();

    self.vectorSource = new ol.source.Vector({
        features: []
    });
    self.vectorLayer = new ol.layer.Vector({
        source: self.vectorSource,
        style:self.options.style
    });

    self.clusterData = [];

    self._clusterTest = function (data, dataCluster) {
        var _flag = false;

        var _cField = self.options.clusterField;
        if(_cField!=""){
            _flag = data[_cField] === dataCluster[_cField];
        }else{
            var _dataCoord = self._getCoordinate(data.lon, data.lat),
                _cdataCoord = self._getCoordinate(dataCluster.lon, dataCluster.lat);
            var _dataScrCoord = self.options.map.getPixelFromCoordinate(_dataCoord),
                _cdataScrCoord = self.options.map.getPixelFromCoordinate(_cdataCoord);

            var _distance = Math.sqrt(
                Math.pow((_dataScrCoord[0] - _cdataScrCoord[0]), 2) +
                Math.pow((_dataScrCoord[1] - _cdataScrCoord[1]), 2)
            );
            _flag = _distance<=self.options.distance;
        }

        var _zoom = self.options.map.getView().getZoom(),
            _maxZoom = self.options.zooms[self.options.zooms.length - 1];
        if(_zoom>_maxZoom) _flag = false;
        return _flag;
    };

    self._getCoordinate = function (lon, lat) {
        return ol.proj.transform([parseFloat(lon), parseFloat(lat)],
            "EPSG:4326",
            self.proj
        );
    };

    self._add2CluserData = function (index, data) {
        self.clusterData[index].cluster.push(data);
    };

    self._clusterCreate = function (data) {
        self.clusterData.push({
            data: data,
            cluster: []
        });
    };

    self._showCluster = function () {
        self.vectorSource.clear();
        var _features = [];
        for(var i=0,len=self.clusterData.length;i<len;i++){
            var _cdata = self.clusterData[i];
            var _coord = self._getCoordinate(_cdata.data.lon, _cdata.data.lat);
            var _feature = new ol.Feature({
                geometry: new ol.geom.Point(_coord),
                attribute: _cdata
            });
            if(_cdata.cluster.length===0) _feature.attr = _feature.data;
            _features.push(_feature);
        }
        self.vectorSource.addFeatures(_features);
    };

    self._clusterFeatures = function () {
        self.clusterData = [];
        var _viewExtent = self.options.map.getView().calculateExtent();
        var _viewGeom = new ol.geom.Polygon.fromExtent(_viewExtent);
        for(var i=0, ilen=self.options.data.length;i<ilen;i++) {
            var _data = self.options.data[i];
            var _coord = self._getCoordinate(_data.lon, _data.lat);
            if(_viewGeom.intersectsCoordinate(_coord)) {
                var _clustered = false;
                for (var j = 0, jlen = self.clusterData.length; j < jlen; j++) {
                    var _cdata = self.clusterData[j];
                    if (self._clusterTest(_data, _cdata.data)) {
                        self._add2CluserData(j, _data);
                        _clustered = true;
                        break;
                    }
                }

                if (!_clustered) {
                    self._clusterCreate(_data);
                }
            }
        }

        self.vectorSource.clear();
        self._showCluster();
    };

    self.init = function () {
        self._clusterFeatures();
        self.options.map.on("moveend", function () {
            self._clusterFeatures();
        });
    };
    self.init();

    return self.vectorLayer;
};

说明: 1、传递参数

map: ol的map对象; clusterField: 如果是基于属性做聚类的话可设置此参数; zooms: 只用到了最后一个级别,当地图大于最大最后一个值的时候,全部展示; distance:屏幕上的聚类距离; data:聚类的数据; style:样式(组)或者样式函数

2、核心方法

_clusterTest:判断是否满足聚类的条件,满足则执行_add2CluserData,不满足则执行_clusterCreate; _showCluster:展示聚类结果;

调用代码如下:

                var mycluster = new myClusterLayer({
                    map: map,
                    clusterField: "",
                    zooms: [8, 11, 14],
                    distance: 100,
                    data: result,
                    style: styleFunc
                });
                map.addLayer(mycluster);
        function styleFunc(feat) {
            var attribute = feat.get("attribute");
            var count = attribute.cluster.length;
            if(count<1){
                var name = attribute.data.name;
                return new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: 4,
                        fill: new ol.style.Fill({
                            color: 'red'
                        })
                    }),
                    text: new ol.style.Text({
                        text:name,
                        fill: new ol.style.Fill({
                            color: '#000000'
                        }),
                        textAlign:"left",
                        offsetX: 15,
                        textBaseline:"middle"
                    })
                })
            }else{
                var radius = Math.max(8, Math.min(count * 0.75, 20));
                return new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: radius,
                        fill: new ol.style.Fill({
                            color: '#cccccc'
                        }),
                        stroke: new ol.style.Stroke({
                            color: '#ff0000',
                            width: 1.5
                        })
                    }),
                    text: new ol.style.Text({
                        text:count.toString(),
                        fill: new ol.style.Fill({
                            color: '#000000'
                        }),
                        textAlign:"center",
                        textBaseline:"middle"
                    })
                })
            }
        }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OL4结合turf.js实现等值线

    本文分享一个结合turf.js实现前端等值线的生成,并对结果做了圆滑处理,并在OL4中进行展示。

    lzugis
  • Arcgis4js实现链家找房的效果

    买房的各位亲们不知是否留意过链家的"地图找房",这样的功能对于使用者来说,是非常方便的,大家可通过连接(https://bj.lianjia.com/ditu/...

    lzugis
  • openlayers实现在线编辑

    在前面有篇博文讲述了基于Arcgis for js和wkt实现在线数据的采集和编辑功能,在本文讲述如何在openlayers实现类似的功能。上一篇博文的地址为:

    lzugis
  • python项目练习三:万能的XML

    这个项目的名称与其叫做万能的XML不如叫做自动构建网站,根据一份XML文件,生成对应目录结构的网站,不过只有html还是太过于简单了,如果要是可以连带生成css...

    the5fire
  • 神经网络实践之情感分类神经网络实践之情感分类

    最近报名了Udacity的深度学习基石,这是第二周的课程,主要是介绍了运用神经网络进行情感分类,课程中是对英文进行了分类,我这边改为了中文。 首先是中文切词,...

    zhuanxu
  • 1.8亿条海量Txt数据存储MySQL实践

    最近出去旅游了,嗨皮了嗨皮,明天上班,开始做作业,今日将1.8亿数据存储的方式进行总结,欢迎大家拍砖!

    公众号guangcity
  • 分页功能

    py3study
  • CIFAR10数据集实战-ResNet网络构建(中)

    用户6719124
  • 获取 zabbix 挂件数据(widget)

    Zabbix 有非常丰富的 API ,但没有 widget 的 API。 所以获取 widget 的数据需要通过模拟登录爬取网页的形式来做。虽然我们可以用一定的...

    用户1416054
  • 使用以 Tensorflow 为后端的 Keras 构建生成对抗网络的代码示例

    生成式对抗网络(GAN)是近期深度学习领域中最有前景的发展之一。 GAN由Ian Goodfellow于2014年推出,它通过分别训练两个相互竞争和合作的深度网...

    AI研习社

扫码关注云+社区

领取腾讯云代金券