OpenLayer4实现自定义地图聚类图层

前言:一直感觉不论OL还是arcgis 这个地图聚类是真的丑,实在让人看不下去,反观leaflet插件的的聚合效果那叫一个好看,个人感觉好看多了去了,那么把这个聚合效果用到OL上面去啊,这个是一个很好玩的事,本篇文章用到了自定义的聚类的扩展图层,感谢@牛老师源代码启发,在此基础上进行进一步的封装。

先来张效果图:

这张照片整的感觉都变形很多。其实一点没变形

一、自定义扩展图层下载(github)

ol.layer.myClusterLayer =function(options){varself =this;self.styleFunc =function(feat){varattribute = feat.get("attribute");varcount = attribute.cluster.length;if(count <1) {varname = attribute.data.name;returnnewol.style.Style({image:newol.style.Icon(/** @type {olx.style.IconOptions} */({anchor: [0.5,60],anchorOrigin:'top-right',anchorXUnits:'fraction',anchorYUnits:'pixels',offsetOrigin:'top-right',offset: [0,1],//偏移量设置scale:0.7,//图标缩放比例opacity:0.75,//透明度src:'data/marker-icon.png'//图标的url})),text:newol.style.Text({text: name,fill:newol.style.Fill({color:'#000000'}),textAlign:"left",offsetX:5,textBaseline:"middle"})        })    }else{var_smallCorlor;var_bigCorlor;if(count <100) {if(count >50) {                _smallCorlor ="#f0cd41";                _bigCorlor ="#f5de8b";            }else{                _smallCorlor ="#94d769";                _bigCorlor ="#cde7b1";            }        }else{            _smallCorlor ='#f1964d';            _bigCorlor ="#f9bda2";        }        count++;        count = count.toString();varsmallRadius = count.length *10;        smallRadius = smallRadius <10?12: smallRadius ;varbigRadius = smallRadius +5;return[newol.style.Style({image:newol.style.Circle({radius: bigRadius,fill:newol.style.Fill({color: _bigCorlor                    })                }),            }),newol.style.Style({image:newol.style.Circle({radius: smallRadius,fill:newol.style.Fill({color: _smallCorlor                    })                }),text:newol.style.Text({text: count,fill:newol.style.Fill({color:'#620022'}),textAlign:"center",textBaseline:"middle"})            }),        ]    }}vardefaults = {map:null,clusterField:"",zooms: [2,4,8,12],distance:256,data: [],style: self.styleFunc,};//将default和options合并self.options = {map: options.map,clusterField: options.clusterField,zooms: (options.zooms.length >0? options.zooms : defaults.zooms),distance: (options.distance >0? options.distance : defaults.distance),data: options.data,style:(options.style!=null?options.style:defaults.style)}self.proj = self.options.map.getView().getProjection();self.vectorSource =newol.source.Vector({features: []});self.vectorLayer =newol.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){returnol.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(vari =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 =newol.Feature({geometry:newol.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 =newol.geom.Polygon.fromExtent(_viewExtent);for(vari =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)) {//当前点是否聚合,默认是falsevar_clustered =false;for(varj =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();returnself.vectorLayer;};ol.inherits(ol.layer.myClusterLayer, ol.layer.Vector);

下载地址:点我下载

二、demo示例

myClusterLayer图层参数option

map是就当前地图容器

clusterField 该参数是,是否属性聚合,如果赋值仅需要赋属性字段名即可

distance是聚合的距离(屏幕上距离)

data 是数据

style是样式(不填就有默认样式)

{                    map:map,                    clusterField:"",                    zooms:[12],                    distance:100,                    data:result,                    style:null}

clusterbody,#map{border:0px;margin:0px;padding:0px;width:100%;height:100%;font-size:13px;overflow: hidden;        }varmap;functioninit(){varprojection =newol.proj.Projection({code:'EPSG:4326',units:'degrees'});functiongetNavmapLayer(){returnnewol.layer.Tile({source:newol.source.XYZ({url:'http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8'//7,8}),projection: projection                });            }varnavlayer = getNavmapLayer();            map =newol.Map({controls: ol.control.defaults({attribution:false}),target:'map',layers: [navlayer],view:newol.View({projection: projection,center: [116.456,40.251],zoom:4})            });            $.get("data/data.json",function(result){varmycluster =newol.layer.myClusterLayer({map: map,clusterField:"",zooms: [12],distance:100,data: result,style:null});                map.addLayer(mycluster);            })        }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345