Openlayers中多边形的聚合

关于OpenLayers的Cluster

ol.source.Cluster

ol利用这个js对象实现对地图上feature进行聚合展示的控制,所有的features需要被放在一个feature数组中作为ol.source.Vector中features属性进行载入。

下面就是官方针对Cluster的API文档:

new ol.source.Cluster(options)

options: Constructor options.

NameTypeDescription
attributionsol.AttributionLikeAttributions.
distancenumberMinimum distance in pixels between clusters. Default is 20.
extentol.ExtentExtent.
geometryFunctionfunctionFunction 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.
formatol.format.FeatureFormat.
logostringLogo.
projectionol.ProjectionLikeProjection.
sourceol.source.VectorSource. Required.
wrapXbooleanWrapX. 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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值