OpenLayers實(shí)現(xiàn)點(diǎn)要素圖層的聚合顯示的方法
1、前言
在很多情況下,點(diǎn)要素圖層中的要素?cái)?shù)量可能會(huì)成百上千,這時(shí)候如果不做任何處理直接加載到地圖上不僅會(huì)使用戶視覺(jué)體驗(yàn)下降,而且也會(huì)造成地圖界面的卡頓。下面這段代碼創(chuàng)建了1000個(gè)隨機(jī)點(diǎn)進(jìn)行顯示:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<title>OpenLayers</title>
<style>
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link href="libs/ol/ol.css" rel="stylesheet" />
<script src="libs/ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 隨機(jī)創(chuàng)建1000個(gè)要素
var source = new ol.source.Vector();
for (var i = 1; i <= 200; i++) {
var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
// 創(chuàng)建圖層
var layer = new ol.layer.Vector({
source: source,
style: function (feature, resolution) {
var style = new ol.style.Style({
image: new ol.style.Icon({
src: 'img/location.png'
})
})
return style;
}
});
// 創(chuàng)建地圖
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10,
minZoom: 5,
maxZoom: 14
})
});
</script>
</body>
</html>
運(yùn)行結(jié)果如下圖所示:

這么多點(diǎn)擠在一起,是不是感覺(jué)很惡心?一般來(lái)說(shuō),如果一個(gè)點(diǎn)要素圖層中的點(diǎn)數(shù)量很多,我們就會(huì)采取圖層聚合的方式對(duì)其進(jìn)行處理。但需要注意:圖層聚合只對(duì)點(diǎn)要素圖層有效,對(duì)線和面圖層無(wú)效。
2、點(diǎn)要素圖層的聚合
在openlayers中,圖層聚合的一般步驟如下:
- 創(chuàng)建要素
- 創(chuàng)建數(shù)據(jù)源添加要素
- 創(chuàng)建聚合數(shù)據(jù)源,設(shè)置聚合的距離
- 創(chuàng)建圖層,將數(shù)據(jù)源設(shè)置為聚合數(shù)據(jù)源
- 創(chuàng)建地圖,添加聚合圖層
圖層聚合代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<title>OpenLayers</title>
<style>
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link href="libs/ol/ol.css" rel="stylesheet" />
<script src="libs/ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 隨機(jī)創(chuàng)建1000個(gè)要素
var source = new ol.source.Vector();
for (var i = 1; i <= 200; i++) {
var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
// 聚合
var cluster = new ol.source.Cluster({
source: source,
distance: 100
})
// 創(chuàng)建圖層
var layer = new ol.layer.Vector({
source: cluster,
style: function (feature, resolution) {
var size = feature.get('features').length;
var style = new ol.style.Style({
image: new ol.style.Circle({
radius: 30,
stroke: new ol.style.Stroke({
color: 'white'
}),
fill: new ol.style.Fill({
color: 'blue'
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: 'white'
})
})
})
return style;
}
});
// 創(chuàng)建地圖
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10,
minZoom: 5,
maxZoom: 14
})
});
</script>
</body>
</html>
運(yùn)行結(jié)果如下圖所示:

3、聚合特殊處理一
上面的代碼雖然實(shí)現(xiàn)了點(diǎn)要素圖層的聚合,但其實(shí)存在著一個(gè)問(wèn)題:地圖縮放層級(jí)最大時(shí)仍然保持著聚合效果,如下圖所示:

一般來(lái)說(shuō),當(dāng)某處只有一個(gè)點(diǎn)時(shí)就應(yīng)該取消聚合效果,這時(shí)候我們就需要在style: function (feature, resolution)這個(gè)回調(diào)函數(shù)里做文章了,代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<title>OpenLayers</title>
<style>
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link href="libs/ol/ol.css" rel="stylesheet" />
<script src="libs/ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 隨機(jī)創(chuàng)建1000個(gè)要素
var source = new ol.source.Vector();
for (var i = 1; i <= 200; i++) {
var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
// 聚合
var cluster = new ol.source.Cluster({
source: source,
distance: 100
})
// 創(chuàng)建圖層
var layer = new ol.layer.Vector({
source: cluster,
style: function (feature, resolution) {
var size = feature.get('features').length;
if (size == 1) {
return new ol.style.Style({
image: new ol.style.Icon({
src: 'img/location.png'
})
})
}
else {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 30,
stroke: new ol.style.Stroke({
color: 'white'
}),
fill: new ol.style.Fill({
color: 'blue'
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: 'white'
})
})
})
}
}
});
// 創(chuàng)建地圖
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10,
minZoom: 5,
maxZoom: 14
})
});
</script>
</body>
</html>
運(yùn)行結(jié)果如下圖所示:

其實(shí)這個(gè)效果實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,核心代碼就是:var size = feature.get('features').length;,如果size>1,則返回聚合樣式,反之則返回圖片樣式。
4、聚合特殊處理二
在上面的代碼中,我把地圖的最大縮放層級(jí)設(shè)置為14,這也就導(dǎo)致了一個(gè)問(wèn)題:當(dāng)?shù)貓D縮放到最大層級(jí)時(shí),還有很多點(diǎn)保持著聚合效果。有時(shí)候用戶可能會(huì)要求:當(dāng)?shù)貓D縮放到最大層級(jí)時(shí),取消全部聚合效果。如果要實(shí)現(xiàn)這個(gè)功能,我們就需要對(duì)地圖事件進(jìn)行監(jiān)聽(tīng)了,代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<title>OpenLayers</title>
<style>
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
<link href="libs/ol/ol.css" rel="stylesheet" />
<script src="libs/ol/ol.js"></script>
</head>
<body>
<div id="map"></div>
<script>
// 隨機(jī)創(chuàng)建1000個(gè)要素
var source = new ol.source.Vector();
for (var i = 1; i <= 200; i++) {
var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
for (var i = 1; i <= 200; i++) {
var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
var feature = new ol.Feature(new ol.geom.Point(coordinates));
source.addFeature(feature);
}
// 聚合
var cluster = new ol.source.Cluster({
source: source,
distance: 100
})
// 創(chuàng)建圖層
var layer = new ol.layer.Vector({
source: cluster,
style: function (feature, resolution) {
var size = feature.get('features').length;
if (size == 1) {
return new ol.style.Style({
image: new ol.style.Icon({
src: 'img/location.png'
})
})
}
else {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 30,
stroke: new ol.style.Stroke({
color: 'white'
}),
fill: new ol.style.Fill({
color: 'blue'
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: 'white'
})
})
})
}
}
});
// 創(chuàng)建地圖
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer
],
view: new ol.View({
projection: 'EPSG:4326',
center: [120, 30],
zoom: 10,
minZoom: 5,
maxZoom: 14
})
});
// 監(jiān)聽(tīng)地圖分辨率改變事件
map.getView().on('change:resolution', function (event) {
if (map.getView().getZoom() == map.getView().getMaxZoom()) {
cluster.setDistance(0);
}
else {
cluster.setDistance(100);
}
})
</script>
</body>
</html>
運(yùn)行結(jié)果如下圖所示:

這個(gè)效果的實(shí)現(xiàn)也很簡(jiǎn)單,只需要監(jiān)聽(tīng)當(dāng)前地圖的分辨率變化事件,如果當(dāng)前縮放層級(jí)已經(jīng)是最大層級(jí),則將聚合的距離設(shè)置為0即可。
5.、結(jié)語(yǔ)
在要素?cái)?shù)量很多的情況下,我們應(yīng)該考慮對(duì)其進(jìn)行聚合處理,這樣不僅提升了用戶的使用感受,而且也可以避免界面卡頓。其實(shí)在上面的代碼中,我對(duì)change:resolution事件進(jìn)行了監(jiān)聽(tīng),你也可以換成另一個(gè)事件——moveend,代碼如下所示:
map.on('moveend', function (event) {
if (map.getView().getZoom() == map.getView().getMaxZoom()) {
cluster.setDistance(0);
}
else {
cluster.setDistance(100);
}
});
對(duì)moveend事件進(jìn)行監(jiān)聽(tīng)也可以實(shí)現(xiàn)相同的效果,因?yàn)闊o(wú)論是地圖的縮放、平移都會(huì)觸發(fā)該事件。
到此這篇關(guān)于OpenLayers實(shí)現(xiàn)點(diǎn)要素圖層的聚合顯示的方法的文章就介紹到這了,更多相關(guān)OpenLayers 點(diǎn)要素圖層的聚合顯示內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Js實(shí)現(xiàn)網(wǎng)頁(yè)鍵盤(pán)控制翻頁(yè)的方法
這篇文章主要介紹了Js實(shí)現(xiàn)網(wǎng)頁(yè)鍵盤(pán)控制翻頁(yè)的方法,較為詳細(xì)的分析了Js實(shí)現(xiàn)網(wǎng)頁(yè)鍵盤(pán)控制翻頁(yè)的原理與具體實(shí)現(xiàn)方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10
慕課網(wǎng)題目之js實(shí)現(xiàn)抽獎(jiǎng)系統(tǒng)功能
這篇文章主要為大家詳細(xì)介紹了慕課網(wǎng)題目之js抽獎(jiǎng)系統(tǒng)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
詳解TypeScript如何正確使用Declare關(guān)鍵字
如果您編寫(xiě) TypeScript 代碼的時(shí)間足夠長(zhǎng),您就已經(jīng)看到過(guò)declare關(guān)鍵字,但它有什么作用,為什么要使用它呢,下面小編就來(lái)和大家簡(jiǎn)單講講2023-08-08
js實(shí)現(xiàn)鍵盤(pán)Enter鍵提交表單的方法
這篇文章主要介紹了js實(shí)現(xiàn)鍵盤(pán)Enter鍵提交表單的方法,涉及javascript鍵盤(pán)事件的相關(guān)操作技巧,需要的朋友可以參考下2015-05-05
JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法,涉及JavaScript事件響應(yīng)、正則匹配及數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-06-06
如何在?xHTML?中驗(yàn)證?noscript+meta?refresh?標(biāo)簽
這篇文章主要介紹了如何在?xHTML?中驗(yàn)證?noscript+meta?refresh?標(biāo)簽,需要的朋友可以參考下2023-03-03

