需求
用户点击行政区划等操作后,从后台获取区域内的点位数据,在地图上聚合显示。用户手动取消聚合,点位直接渲染在地图上。
实现过程
- 使用后台返回的点位数据,通过
new ol.source.Vector({features})
创建矢量数据源。 - 使用
new ol.source.Cluster({source})
创建聚合标注数据源,source
参数设置为上一步创建的矢量数据源。 - 最后创建一个矢量图层
new ol.layer.Vector({source})
,source
参数设置为上一步创建的聚合标注数据源,再将矢量图层添加到地图上即可。 - 取消聚合可以通过两种方式实现。
- 方式一:通过设置两种不同的聚合样式:聚合数量大于1的样式和聚合数量等于1的样式。将聚合数量等于1的样式设置成点位的样式,来模拟不聚合的点位展示效果。
- 方式二:通过隐藏和显示图层实现。默认将点位图层也添加到地图上,在需要显示的时机,将聚合图层隐藏,显示点位图层。
- 可通过source.setDistance(number)设置聚合的像素,设置为0时,所有点位都不聚合,即可达到不聚合的效果。
知识点
-
new ol.style.Circle({radius, stroke, fill})
创建一个圆形样式,可设置半径,描边颜色和填充颜色。 -
new ol.style.Text({text,fill,scale})
,创建一个字体,可设置字体内容,颜色和缩放比例。 -
map.getView().animate({center, zoom})
可跳转到指定的经纬度和显示层级。 - 聚合点的
feature
有一个features
属性,是一个存放着这个聚合下面的所有feature
的数组,可通过feature.get('features')
获得。 -
new ol.source.Cluster({distance, source})
创建聚合标注数据源,通过source
设置聚合的资源。通过distance
设置聚合的距离。比如distance
设置为150
,表示如果2个点位之间的距离小于150px
,即聚合成1个聚合点②。 -
new ol.layer.Vector({style})
的style
参数可以是一个回调函数,函数的第一个参数是feature
,可根据feature
的不同,return
不同的样式。 -
clusterLayer.getSource().setDistance(number)
可在初始化聚合图层结束后,再次设置聚合距离,设置为0
可实现不聚合的效果。 -
feature.get('features').length
聚合点feature
的features
属性的length
是此聚合点下点位的数量。 -
map.getView().getZoom()
可获得当前地图的展示层级,有小数点。 -
layers.setVisible(true/false)
可设置图层的显示和隐藏。 - 通过
map.on('moveend', () => {}
可以监听地图移动事件,在地图平移和缩放结束后会触发此事件回调函数。可通过层级的变化,区分是平移还是缩放。 -
'#' + parseInt(Math.random() * 0xffffff).toString(16).padStart(6, '0')
可随机生成16进制颜色值。 - 在测试切换两种不同的实现不聚合的方式时,在地图层级小的时候,比如5级,切换后会感觉两种方式的点位不同。但如果将地图逐步放大,再次进行切换的时候,就不会有差异。最后发现是在聚合图层和直接渲染点位的图层中,重叠点位的处理不同,在聚合模式下,这个监控在上面,但是在直接渲染点位的图层中,这个监控却在下面。在地图层级小的时候,点位都聚集在了一起,重叠的数据非常多,导致切换时大量的点位层级变化,觉得异常。但当地图不断放大后,点位直接不重叠了,这时切换就感觉不到点位有什么变化了。
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <title>点位聚合</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } :root { --top-height: 50px; } html, body, #app, .app-map { height: 100%; height: 100%; } .app-btns { position: fixed; right: 10px; top: 10px; background-color: #fff; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5); width: 210px; padding: 25px; text-align: center; border-radius: 5px; display: flex; flex-direction: column; z-index: 2; } .app-btns button { font-size: 18px; border: none; padding: 12px 10px; border-radius: 4px; color: #fff; background-color: #409eff; border-color: #409eff; cursor: pointer; border: 1px solid #dcdfe6; margin-bottom: 5px; } .app-btns button:hover { background: #66b1ff; border-color: #66b1ff; } .app-btns button.active { background-color: #07c160; } hr { margin: 20px 0; } .zoom { position: fixed; right: 10px; b