openlayers6 点聚合

在地图上点位显示过多,会造成页面卡顿、点位重叠看不清信息,模拟实现人员聚合,单人显示名称,多人聚合显示人数。

Cluster详解

在OpenLayers中,点聚合是一种常见的需求,可以通过集成第三方库ol-cluster来实现。聚合的原理是将距离较近的点位合并为一个点,并计算合并后点位的属性值。当一个点被添加进来时,会检查该点与已有聚合点的距离是否在指定的聚合距离之内,如果是,则将该点加入到该聚合点中,同时更新聚合点的属性值(例如点数等)。如果该点与已有聚合点的距离都超出聚合距离,则将该点作为新的聚合点,加入到聚合源中。
在渲染时,对于聚合后的点,可以根据聚合点的属性值设置不同的样式,以区别于普通的点位。我这里就是通过设置两种不同的聚合样式来体现多人和单人。也可以理解为将聚合数量大于1和等于1分别设置样式。
在这里插入图片描述

安装ol-cluster库:

npm install ol-cluster

实现聚合的步骤:

  1. 将点位数据通过ol/Featureol/geom/Point按坐标生成对应的feature,
  2. 通过ol/source/Vector创建集群点矢量数据源。
  3. 使用ol/source/Cluster创建集群数据源。
  4. 创建一个集群点矢量图层ol/layer/Vector,并设置集群点样式ol/style/Style
  5. 将集群点图层添加到Map上。

集群点按坐标生成对应feature

for (let i = 0; i < pointArr.length; i++) {
    const item = pointArr[i];
    let feature = new Feature({
        geometry: new Point(new Proj.fromLonLat(item.position)),
        name: item.name,
        type: 'point'
    });
}

创建集群点矢量数据源

const source = new VectorSource();

// 将集群点feature添加到集群点资源source中
source.addFeature(feature);

创建集群数据源

distance是设置的聚合距离,单位 像素。在这个范围内的点就会聚合在一起。设置为0时,所有点位都不聚合,即可达到不聚合的效果。
在聚合时,OpenLayers会计算每个点在屏幕上的像素位置,并根据像素位置计算聚合距离。因此,聚合距离不是以地理距离的方式计算的,而是以屏幕上的像素距离为基础。聚合距离的大小取决于地图缩放级别、地图分辨率和聚合距离参数的值。

// 创建集群资源
const clusterSource = new Cluster({
    distance: 50,
    source: source // 集群点矢量数据源
});

创建集群矢量图层

// 集群点图层
let clusters = new VectorLayer({
    source: clusterSource,
    style: (feature) => {
        return setClusterStyle(feature);
    }
});
map.addLayer(clusters);

设置集群点样式

设置了聚合数据等于1和大于1的样式,区分了单人和多人,等于1也可为不聚合样式。
等于1时展示人员姓名,聚合时展示聚合人数。

// 集群点样式
function setClusterStyle(feature) {
    // feature.get('features')这一步得到的是feature所在的集群的feature数组
    const features = feature.get('features');
    const name = feature.values_.features[0].values_.name; // 获取feature名称
    const size = features.length;
    let style;
    if (size > 1) {
        // 聚合样式
        style = new Style({
            image: new Icon({
                scale: 0.5,
                src: clusterImg,
                anchor: [0.5, 1]
            }),
            text: new Text({
                text: size.toString(), // 数字需要toString()转换
                fill: new Fill({
                    color: '#FFFFFF'
                }),
                backgroundFill: new Fill({
                    color: '#555555'
                }),
                padding: [2, 2, 0, 4],
                offsetY: -48,
                scale: 1.4
            })
        });
    } else {
        // 单点,不聚合样式
        style = new Style({
            image: new Icon({
                scale: 0.5,
                src: pointImg,
                anchor: [0.5, 1]
            }),
            text: new Text({
                text: name, // 数字需要toString()转换
                fill: new Fill({
                    color: '#FFFFFF'
                }),
                backgroundFill: new Fill({
                    color: '#555555'
                }),
                padding: [2, 2, 0, 4],
                offsetY: -48,
                scale: 1.4
            })
        });
    }
    return style;
}

完整示例代码

// openlayers点聚合
import React, { useState, useEffect } from 'react';
import { Map, View, Feature } from 'ol';// 地图Collection
import * as Proj from 'ol/proj'; // 转化
import { XYZ, Vector as VectorSource, Cluster } from 'ol/source'; // 资源
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'; // 图层
import { Point } from 'ol/geom';
import { Style, Icon, Fill, Text } from 'ol/style'; // 样式
const clusterImg = require('@/static/image/more.png');
const pointImg = require('@/static/image/one.png');

const OpenlayerCluster = () => {
    const [map, setMap] = useState(null); // 地图
    const [view, setView] = useState(null); // 地图视图

    // 集群点样式
    function setClusterStyle(feature) {
        // feature.get('features')这一步得到的是feature所在的集群的feature数组
        const features = feature.get('features');
        const name = feature.values_.features[0].values_.name; // 获取feature名称
        const size = features.length;
        let style;
        if (size > 1) {
            // 聚合样式
            style = new Style({
                image: new Icon({
                    scale: 0.5,
                    src: clusterImg,
                    anchor: [0.5, 1]
                }),
                text: new Text({
                    text: size.toString(), // 数字需要toString()转换
                    fill: new Fill({
                        color: '#FFFFFF'
                    }),
                    backgroundFill: new Fill({
                        color: '#555555'
                    }),
                    padding: [2, 2, 0, 4],
                    offsetY: -48,
                    scale: 1.4
                })
            });
        } else {
            // 单点,不聚合样式
            style = new Style({
                image: new Icon({
                    scale: 0.5,
                    src: pointImg,
                    anchor: [0.5, 1]
                }),
                text: new Text({
                    text: name, // 数字需要toString()转换
                    fill: new Fill({
                        color: '#FFFFFF'
                    }),
                    backgroundFill: new Fill({
                        color: '#555555'
                    }),
                    padding: [2, 2, 0, 4],
                    offsetY: -48,
                    scale: 1.4
                })
            });
        }
        return style;
    }

    useEffect(() => {
        if (map) {
            // 点坐标
            let pointArr = [
                {
                    name: '张三',
                    position: [104.1005229950, 30.6743128087],
                }, {
                    name: '李四',
                    position: [103.9271879196, 30.7462617980],
                }, {
                    name: '王五',
                    position: [103.6227035522, 30.9932085864],
                }, {
                    name: '赵六',
                    position: [103.5752069950, 31.4663367378],
                }, {
                    name: '安娜',
                    position: [103.4307861328, 30.1941019446],
                }, {
                    name: '麻子',
                    position: [106.5885615349, 29.5679608922],
                }, {
                    name: '嘎子',
                    position: [106.4500522614, 29.5811456252],
                }, {
                    name: '翠花',
                    position: [107.7666950226, 29.4161988273],
                }
            ]
            // 集群点资源Source
            let source = new VectorSource();
            // 集群点按坐标生成对应feature
            for (let i = 0; i < pointArr.length; i++) {
                const item = pointArr[i];
                let feature = new Feature({
                    geometry: new Point(new Proj.fromLonLat(item.position)),
                    name: item.name,
                    type: 'point'
                });
                // 将集群点feature添加到集群点资源source中
                source.addFeature(feature);
            }
            // 创建集群资源
            let clusterSource = new Cluster({
                distance: 50,
                source: source
            });

            // 集群点图层
            let clusters = new VectorLayer({
                source: clusterSource,
                style: (feature) => {
                    return setClusterStyle(feature);
                }
            });
            // 将集群点添加到Map
            map.addLayer(clusters);
        }
    }, [map]);


    useEffect(() => {
        // 监听地图视图,创建地图
        if (view) {
            // 使用高德图层
            const tileLayer = new TileLayer({
                source: new XYZ({
                    url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&scl=1&size=1&style=7&x={x}&y={y}&z={z}'
                }),
                name: 'mapLayer'
            });
            // 创建实例
            const _map = new Map({
                target: 'map',
                layers: [tileLayer], // 使用高德图层
                view: view
            });
            setMap(_map);
        }
    }, [view]);

    useEffect(() => {
        // View用于创建2D视图
        const viewObj = new View({
            // 设定中心点,因为默认坐标系为 3587,所以要将我们常用的经纬度坐标系4326 转换为 3587坐标系
            center: Proj.transform([103.9271879196, 30.7462617980], 'EPSG:4326', 'EPSG:3857'),
            zoom: 7
        });
        setView(viewObj);
    }, []);

    return <div id='map' style={{ width: '100%', height: '100%' }}></div>;
}
export default OpenlayerCluster;
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenLayers 是一种用于在 Web 上展示地理信息的开源 JavaScript 库。要实现聚合功能,可以使用 OpenLayers 的扩展库 OpenLayers.Cluster。 首先,确保你已经引入了 OpenLayersOpenLayers.Cluster 的库文件。然后,按照以下步骤进行聚合的设置: 1. 创建一个矢量图层并添加到地图上: ```javascript var vectorLayer = new ol.layer.Vector({ source: new ol.source.Vector(), }); map.addLayer(vectorLayer); ``` 2. 创建一个聚合源,并将其与矢量图层关联: ```javascript var clusterSource = new ol.source.Cluster({ distance: 40, // 聚合的距离阈值,根据需要调整 source: vectorLayer.getSource(), }); ``` 3. 创建一个聚合样式: ```javascript var clusterStyle = new ol.style.Style({ image: new ol.style.Circle({ radius: 10, fill: new ol.style.Fill({ color: '#ff0000', // 聚合的颜色,根据需要调整 }), }), text: new ol.style.Text({ text: '', fill: new ol.style.Fill({ color: '#ffffff', // 聚合文本的颜色,根据需要调整 }), }), }); ``` 4. 创建一个聚合图层并添加到地图上: ```javascript var clusterLayer = new ol.layer.Vector({ source: clusterSource, style: function (feature) { if (feature.get('features').length > 1) { // 设置聚合的样式 clusterStyle.getText().setText(feature.get('features').length.toString()); return clusterStyle; } else { // 设置非聚合的样式 return feature.get('features')[0].getStyle(); } }, }); map.addLayer(clusterLayer); ``` 现在,你的地图上的将会被聚合显示。根据设置的距离阈值,当之间的距离小于该阈值时,它们将被聚合为一个,并显示聚合的数量。 这只是一个简单的示例,你可以根据自己的需求进行更多的样式和交互定制。希望能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值