Openlayers中多边形的聚合

持续三天不断尝试之后获得了一些不为人知的辛酸 orz

关于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;
    }
}

最后附上实现效果图
小比例尺


大比例尺


小比例尺高亮


大比例尺高亮


高亮后聚合


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

推荐阅读更多精彩内容