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

说说地图中的聚类

作者头像
牛老师讲GIS
发布2018-10-23 10:46:23
5960
发布2018-10-23 10:46:23
举报
文章被收录于专栏:跟牛老师一起学WEBGIS

概述

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

需求

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

效果

实现

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

代码语言:javascript
复制
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:展示聚类结果;

调用代码如下:

代码语言:javascript
复制
                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"
                    })
                })
            }
        }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018年06月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

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