关于OpenLayers的Cluster
ol.source.Cluster
ol利用这个js对象实现对地图上feature进行聚合展示的控制,所有的features需要被放在一个feature数组中作为ol.source.Vector中features属性进行载入。
下面就是官方针对Cluster的API文档:
new ol.source.Cluster(options)
options: Constructor options.
Name | Type | Description |
---|---|---|
attributions | ol.AttributionLike | Attributions. |
distance | number | Minimum distance in pixels between clusters. Default is 20. |
extent | ol.Extent | Extent. |
geometryFunction | function | Function that takes an ol.Feature as argument and returns an ol.geom.Point as cluster calculation point for the feature. When a feature should not be considered for clustering, the function should return null. The default, which works when the underyling source contains point features only, is function(feature) {return feature.getGeometry();} See ol.geom.Polygon#getInteriorPoint for a way to get a cluster calculation point for polygons. |
format | ol.format.Feature | Format. |
logo | string | Logo. |
projection | ol.ProjectionLike | Projection. |
source | ol.source.Vector | Source. Required. |
wrapX | boolean | WrapX. Default is true |
之所以把这个贴出来是为了让大家了解一个事情,那就是如果在Openlayers的官方API文档中找你想要的东西,恐怕应该是一件需要碰运气的事情。并不是说他们的文档写的不够全面和完善,但当你想要从这种API文档中快速的找到一些能够立即实现你想要的开发效果的东西,那恐怕你得把他当前API所涉及到的所有js对象的API都看一遍才行了(事实上我就是这么做的)。本文的目的只是让有GIS js开发基础的人能够快速的用openlayers实现多边形聚合效果,因为在网上搜了很久都没有类似的贴,所以才决定记录下来,希望有可能帮助到遇到类似情况的人吧。
实现多边形聚合效果
在网上翻了很多关于ol实现聚合的贴,基本上都是照本宣科搞几个ol.geom.Point随便弄一弄,然而我遇到的需求是我可能会get两百个左右的ol.geom.Polygon,按照官网给的例子,根本行不通啊喂,报的错也让我很崩溃,说我的操作有问题。马德我一个塞尔达可以单挑人马活下来的人说我操作有问题我摔。
愤怒的我立即打开F12开始不断的试错,试图证明我操作的问题是ol本身的问题引起的,后来API中的一个option让我产生了想法,就是上面的那个geometryFunction,这个function可以将feature获取到并且返回一个Point作为feature本身的聚合坐标,只要不妨碍进行聚合的计算,即使返回极点他也不拦着你,不过一般的Polygon都有一个getInteriorPoint方法可以获取多边形的内点,所以在geometryFunction中可以做到返回多边形内点坐标(那么问题就来了,内点是哪个点呢,其实我也不知道,原谅我调试的时候没有多去试试)。
代码中把geometryFunction属性加上,写一个新的方法去获取多边形内点并返回。
var geometryFunc = function (feature) {
return feature.getGeometry().getInteriorPoint();
}
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Cluster({
distance: distance, //调用方法时候输入的聚合距离
source: new ol.source.Vector({ features: features }), //获取到的feature数组
geometryFunction: geometryFunc //获取多边形内点的方法
})
});
然后保存刷新页面,查询一下,最后发现聚合效果正常运转,我的操作终于没问题了。
但是放大以后,我勒个擦,这些小圆圈是什么鬼,我的多边形呢?
于是陷入了第二波痛苦。
直到在官方demo里面看到一个这样的example:
Earthquake Cluster
然后打开了通往新世界的大门。
在ol.layer.Vector中有一个style属性,用来将获取到的feature和resolution进行处理,如下:
var maxFeatureCount, vector;
// 计算当前resolution下feature之间的距离以形成聚合图形的基础信息
function calculateClusterInfo(resolution) {
maxFeatureCount = 0;
var features = vector.getSource().getFeatures();
var feature, radius;
for (var i = features.length - 1; i >= 0; --i) {
feature = features[i];
var originalFeatures = feature.get('features');
var extent = ol.extent.createEmpty();
var j, jj;
for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
ol.extent.extend(extent, originalFeatures[j].getGeometry().getExtent());
}
maxFeatureCount = Math.max(maxFeatureCount, jj);
radius = 0.25 * (ol.extent.getWidth(extent) + ol.extent.getHeight(extent)) /resolution;
feature.set('radius', radius);
}
}
var currentResolution;
function styleFunction(feature, resolution) {
if (resolution != currentResolution) {
// 根据resolution处理图形聚合状态
calculateClusterInfo(resolution);
currentResolution = resolution;
}
var style;
var size = feature.get('features').length;
if (size > 1) {
// 聚合图形样式,自动获取对应半径,调整颜色深度
style = new ol.style.Style({
image: new ol.style.Circle({
radius: feature.get('radius'),
fill: new ol.style.Fill({
color: [255, 153, 0, Math.min(0.8, 0.4 + (size / maxFeatureCount))]
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: textFill,
stroke: textStroke
})
});
} else {
var originalFeature = feature.get('features')[0];
// 单个图形样式处理方法
style = createPolygonStyle(originalFeature);
}
return style;
}
vector = new ol.layer.Vector({
source: new ol.source.Cluster({
distance: 40,
source: new ol.source.Vector({
//获取到的feature数组
feature: features
})
}),
style: styleFunction
});
这个方法首先对返回的resolution进行了判断,如果地图进行了缩放,则重新计算图面上点与点之间的距离以规划聚合图形的半径,然后对其返回对应单独的图形样式。
接下来就要单独讲讲上面单个图形样式处理方法的部分,由于在我的需求中,对每个图形还单独增加了点击效果,聚合图形不考虑在内,但凡出现没有在聚合范围内的Polygon,都要求能够点击并且高亮展示,所以上文的createPolygonStyle方法还需进行进一步的处理;首先在全局变量中需要添加一个highLightFeatureId用于记录哪个Polygon是需要高亮的,然后在styleFunction回调的时候对需要高亮的图形样式进行调整,代码如下:
var createPolygonStyle = function (feature) {
if (_highlightfeatureId == feature.attributes.id) {
// 高亮样式
var style = new ol.style.Style({
geometry: feature.getGeometry(),
fill: new ol.style.Fill({
color: 'rgba(204,102,102,0.8)'
}),
stroke: new ol.style.Stroke({
color: '#CC3333',
width: 3
}),
image: new ol.style.Circle({
stroke: new ol.style.Stroke({
color: 'rgb(204,102,102)',
width: 1
}),
radius: 6,
fill: new ol.style.Fill({
color: [255, 255, 255, 0.6]
})
}),
text: new ol.style.Text({
text: feature.text,
textAlign: "center",
textBaseline: 'middle',
font: "14px serif",
fill: new ol.style.Fill({ color: "#FFFFFF" }),
stroke: new ol.style.Stroke({ color: "#000000", width: 3 })
})
});
return style;
} else {
// 普通多边形的样式
var style = new ol.style.Style({
geometry: feature.getGeometry(),
fill: new ol.style.Fill({
color: 'rgba(0,204,204,0.2)'
}),
stroke: new ol.style.Stroke({
lineDash: [20, 20],
color: '#0099CC',
width: 1
}),
image: new ol.style.Circle({
stroke: new ol.style.Stroke({
color: 'rgb(0,204,204)',
width: 1
}),
radius: 6,
fill: new ol.style.Fill({
color: [255, 255, 255, 0.6]
})
}),
text: new ol.style.Text({
text: feature.text,
textAlign: "center",
textBaseline: 'middle',
font: "14px serif",
fill: new ol.style.Fill({ color: "#FFFFFF" }),
stroke: new ol.style.Stroke({ color: "#000000", width: 3 })
})
});
return style;
}
}
最后附上实现效果图
小比例尺
大比例尺
小比例尺高亮
大比例尺高亮
高亮后聚合
作者:MMMOOO
链接:https://www.jianshu.com/p/330b45f1c9ac
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。