zoukankan      html  css  js  c++  java
  • OpenLayer4实现自定义地图聚类图层

    前言:一直感觉不论OL还是arcgis 这个地图聚类是真的丑,实在让人看不下去,反观leaflet插件的的聚合效果那叫一个好看,个人感觉好看多了去了,那么把这个聚合效果用到OL上面去啊,这个是一个很好玩的事,本篇文章用到了自定义的聚类的扩展图层,感谢@牛老师源代码启发,在此基础上进行进一步的封装。

    先来张效果图:

    这张照片整的感觉都变形很多。其实一点没变形

    一、自定义扩展图层下载(github)

    
    
    ol.layer.myClusterLayer = function (options) {
    
    var self = this;
    self.styleFunc = function (feat) {
        var attribute = feat.get("attribute");
        var count = attribute.cluster.length;
        if (count < 1) {
            var name = attribute.data.name;
            return new ol.style.Style({
                image: new ol.style.Icon(/** @type {olx.style.IconOptions} */({
                    anchor: [0.5, 60],
                    anchorOrigin: 'top-right',
                    anchorXUnits: 'fraction',
                    anchorYUnits: 'pixels',
                    offsetOrigin: 'top-right',
                    offset: [0, 1],//偏移量设置
                    scale: 0.7,  //图标缩放比例
                    opacity: 0.75,  //透明度
                    src: 'data/marker-icon.png'//图标的url
                })),
                text: new ol.style.Text({
                    text: name,
                    fill: new ol.style.Fill({
                        color: '#000000'
                    }),
                    textAlign: "left",
                    offsetX: 5,
                    textBaseline: "middle"
                })
            })
        } else {
            var _smallCorlor;
            var _bigCorlor;
            if (count < 100) {
                if (count > 50) {
                    _smallCorlor = "#f0cd41";
                    _bigCorlor = "#f5de8b";
                }
                else {
                    _smallCorlor = "#94d769";
                    _bigCorlor = "#cde7b1";
                }
            }
            else {
                _smallCorlor = '#f1964d';
                _bigCorlor = "#f9bda2";
            }
            count++;
            count = count.toString();
            var smallRadius = count.length * 10;
            smallRadius = smallRadius < 10 ? 12 : smallRadius ;
            var bigRadius = smallRadius + 5;
            return [
                new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: bigRadius,
                        fill: new ol.style.Fill({
                            color: _bigCorlor
                        })
                    }),
                }),
                new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: smallRadius,
                        fill: new ol.style.Fill({
                            color: _smallCorlor
                        })
                    }),
                    text: new ol.style.Text({
                        text: count,
                        fill: new ol.style.Fill({
                            color: '#620022'
                        }),
                        textAlign: "center",
                        textBaseline: "middle"
                    })
                }),
            ]
        }
    }
    var defaults = {
        map: null,
        clusterField: "",
        zooms: [2, 4, 8, 12],
        distance: 256,
        data: [],
        style: self.styleFunc,
    };
    //将default和options合并
    self.options = {
        map: options.map,
        clusterField: options.clusterField,
        zooms: (options.zooms.length > 0 ? options.zooms : defaults.zooms),
        distance: (options.distance > 0 ? options.distance : defaults.distance),
        data: options.data,
        style:(options.style!=null?options.style:defaults.style)
    }
    
    self.proj = self.options.map.getView().getProjection();
    
    self.vectorSource = new ol.source.Vector({
        features: []
    });
    self.vectorLayer = new ol.layer.Vector({
        source: self.vectorSource,
        style: self.options.style
    });
    self.clusterData = [];
    //判断该点是否聚合
    self._clusterTest = function (data, dataCluster) {
        var _flag = false;
    
        var _cField = self.options.clusterField;
        if (_cField != "") {
            _flag = data[_cField] === dataCluster[_cField];
        } else {
            //将地理坐标转换成屏幕坐标,进行距离判断
            var _dataCoord = self._getCoordinate(data.lon, data.lat),
                _cdataCoord = self._getCoordinate(dataCluster.lon, dataCluster.lat);
            var _dataScrCoord = self.options.map.getPixelFromCoordinate(_dataCoord),
                _cdataScrCoord = self.options.map.getPixelFromCoordinate(_cdataCoord);
    
            var _distance = Math.sqrt(
                Math.pow((_dataScrCoord[0] - _cdataScrCoord[0]), 2) +
                Math.pow((_dataScrCoord[1] - _cdataScrCoord[1]), 2)
            );
            _flag = _distance <= self.options.distance;
        }
        //如果超过最大的缩放级别,数据全部展示
        var _zoom = self.options.map.getView().getZoom(),
            _maxZoom = self.options.zooms[self.options.zooms.length - 1];
        if (_zoom > _maxZoom) _flag = false;
        return _flag;
    };
    //坐标转换
    self._getCoordinate = function (lon, lat) {
        return ol.proj.transform([parseFloat(lon), parseFloat(lat)],
            "EPSG:4326",
            self.proj
        );
    };
    //添加数据到聚合图
    self._add2CluserData = function (index, data) {
        self.clusterData[index].cluster.push(data);
    };
    
    self._clusterCreate = function (data) {
        self.clusterData.push({
            data: data,
            cluster: []
        });
    };
    //展示数据
    self._showCluster = function () {
        self.vectorSource.clear();
        var _features = [];
        for (var i = 0, len = self.clusterData.length; i < len; i++) {
            var _cdata = self.clusterData[i];
            var _coord = self._getCoordinate(_cdata.data.lon, _cdata.data.lat);
            var _feature = new ol.Feature({
                geometry: new ol.geom.Point(_coord),
                attribute: _cdata
            });
            //如果聚合点里面没有数据就显示该点数据
            if (_cdata.cluster.length === 0) _feature.attr = _feature.data;
            _features.push(_feature);
        }
        self.vectorSource.addFeatures(_features);
    };
    
    self._clusterFeatures = function () {
        self.clusterData = [];
        //可视域处理
        var _viewExtent = self.options.map.getView().calculateExtent();
        //声明一个矩形,范围就是屏幕的四至
        var _viewGeom = new ol.geom.Polygon.fromExtent(_viewExtent);
        for (var i = 0, ilen = self.options.data.length; i < ilen; i++) {
            var _data = self.options.data[i];
            var _coord = self._getCoordinate(_data.lon, _data.lat);
            if (_viewGeom.intersectsCoordinate(_coord)) {
                //当前点是否聚合,默认是false
                var _clustered = false;
                for (var j = 0, jlen = self.clusterData.length; j < jlen; j++) {
                    var _cdata = self.clusterData[j];
                    if (self._clusterTest(_data, _cdata.data)) {
                        self._add2CluserData(j, _data);
                        _clustered = true;
                        break;
                    }
                }
                if (!_clustered) {
                    self._clusterCreate(_data);
                }
            }
        }
        self.vectorSource.clear();
        self._showCluster();
    };
    self.init = function () {
        self._clusterFeatures();
        self.options.map.on("moveend", function () {
            self._clusterFeatures();
        });
    };
    self.init();
    
    return self.vectorLayer;
    
    };
    
    ol.inherits(ol.layer.myClusterLayer, ol.layer.Vector);
    

    下载地址:点我下载

    二、demo示例

    myClusterLayer图层参数option

    • map是就当前地图容器
       
    • clusterField 该参数是,是否属性聚合,如果赋值仅需要赋属性字段名即可
    • distance是聚合的距离(屏幕上距离)
    • data 是数据
    • style是样式(不填就有默认样式)
                      {
                        map: map,
                        clusterField: "",
                        zooms: [12],
                        distance: 100,
                        data: result,
                        style:null
                      }
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>cluster</title>
        <link rel="stylesheet" href="https://openlayers.org/en/v4.5.0/css/ol.css" type="text/css">
        <style type="text/css">
            body, #map {
                border: 0px;
                margin: 0px;
                padding: 0px;
                 100%;
                height: 100%;
                font-size: 13px;
                overflow: hidden;
            }
        </style>
        <script src="https://openlayers.org/en/v4.5.0/build/ol.js"></script>
        <script src="../../Scripts/jquery/jquery-3.1.1.min.js"></script>
        <script type="text/javascript" src="js/ClusterLayer-ol.js"></script>
        <script type="text/javascript">
            var map;
            function init() {         
                var projection = new ol.proj.Projection({
                    code: 'EPSG:4326',
                    units: 'degrees'
                });
                function getNavmapLayer() {
                    return new ol.layer.Tile({
                        source: new ol.source.XYZ({
                            url: 'http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8'//7,8
                        }),
                        projection: projection
                    });
                }
                var navlayer = getNavmapLayer();
                map = new ol.Map({
                    controls: ol.control.defaults({
                        attribution: false
                    }),
                    target: 'map',
                    layers: [navlayer],
                    view: new ol.View({
                        projection: projection,
                        center: [116.456, 40.251],
                        zoom: 4
                    })
                });
                $.get("data/data.json", function (result) {
                    var mycluster = new ol.layer.myClusterLayer({
                        map: map,
                        clusterField: "",
                        zooms: [12],
                        distance: 100,
                        data: result,
                        style:null
                    });
                    map.addLayer(mycluster);
                })
            }
        </script>
    </head>
    <body onLoad="init()">
    <div id="map">
    </div>
    </body>
    </html>
  • 相关阅读:
    使用Redis实现分布式锁
    SpringBoot 定时任务的使用
    HTTP请求调试软件 Postman
    ElasticSearch的安装
    全文搜索 简介
    SpringBoot整合Redis
    Git 操作远程仓库(Github)
    Git的使用
    Git 简介、下载安装、配置
    Vue 商城的一些小demo(后台添加商品、前台购物车、本地存储的使用)
  • 原文地址:https://www.cnblogs.com/tuboshu/p/10752311.html
Copyright © 2011-2022 走看看