OpenLayers realizes the method of aggregate display of point feature layers

OpenLayers realizes the method of aggregate display of point feature layers

1. Introduction

In many cases, the number of features in a point feature layer may be hundreds or thousands. If they are directly loaded onto the map without any processing, not only will the user's visual experience deteriorate, but it will also cause the map interface to freeze. The following code creates 1000 random points for display:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta charset="utf-8" />
    <title>OpenLayers</title>
    <style>
        html, body, #map {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
    <link href="libs/ol/ol.css" rel="stylesheet" />
    <script src="libs/ol/ol.js"></script>
</head>
<body>
    <div id="map"></div>

    <script>
        // Create 1000 random features var source = new ol.source.Vector();
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }

        // Create a layer var layer = new ol.layer.Vector({
            source: source,
            style: function (feature, resolution) {
                var style = new ol.style.Style({
                    image: new ol.style.Icon({
                        src: 'img/location.png'
                    })
                })
                return style;
            }
        });

        // Create a map var map = new ol.Map({
            target: 'map',
            layers:
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                layer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10,
                minZoom: 5,
                maxZoom: 14
            })
        });
    </script>
</body>
</html>

The running results are shown in the figure below:

insert image description here

Doesn’t it feel disgusting to see so many points crowded together? Generally speaking, if there are a large number of points in a point feature layer, we will process it by圖層聚合. But please note:圖層聚合只對點要素圖層有效,對線和面圖層無效.

2. Aggregation of point feature layers

In openlayers , the general steps for layer aggregation are as follows:

  • Create features
  • Create a data source and add features
  • Create an aggregate data source and set the aggregation distance
  • Create a layer and set the data source to the aggregate data source
  • Create a map and add an aggregate layer

The layer aggregation code is as follows:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta charset="utf-8" />
    <title>OpenLayers</title>
    <style>
        html, body, #map {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
    <link href="libs/ol/ol.css" rel="stylesheet" />
    <script src="libs/ol/ol.js"></script>
</head>
<body>
    <div id="map"></div>

    <script>
        // Create 1000 random features var source = new ol.source.Vector();
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }

        // Aggregation var cluster = new ol.source.Cluster({
            source: source,
            distance: 100
        })

        // Create a layer var layer = new ol.layer.Vector({
            source: cluster,
            style: function (feature, resolution) {
                var size = feature.get('features').length;
                var style = new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: 30,
                        stroke: new ol.style.Stroke({
                            color: 'white'
                        }),
                        fill: new ol.style.Fill({
                            color: 'blue'
                        })
                    }),
                    text: new ol.style.Text({
                        text: size.toString(),
                        fill: new ol.style.Fill({
                            color: 'white'
                        })
                    })
                })
                return style;
            }
        });

        // Create a map var map = new ol.Map({
            target: 'map',
            layers:
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                layer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10,
                minZoom: 5,
                maxZoom: 14
            })
        });
    </script>
</body>
</html>

The running results are shown in the figure below:

insert image description here

3. Special treatment of polymerization

Although the above code realizes the aggregation of point feature layers, there is actually a problem:地圖縮放層級最大時仍然保持著聚合效果, as shown in the following figure:

insert image description here

Generally speaking,當某處只有一個點時就應該取消聚合效果. At this time, we need to make some changes in the callback function style: function (feature, resolution) . The code is as follows:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta charset="utf-8" />
    <title>OpenLayers</title>
    <style>
        html, body, #map {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
    <link href="libs/ol/ol.css" rel="stylesheet" />
    <script src="libs/ol/ol.js"></script>
</head>
<body>
    <div id="map"></div>

    <script>
        // Create 1000 random features var source = new ol.source.Vector();
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }

        // Aggregation var cluster = new ol.source.Cluster({
            source: source,
            distance: 100
        })

        // Create a layer var layer = new ol.layer.Vector({
            source: cluster,
            style: function (feature, resolution) {
                var size = feature.get('features').length;
                if (size == 1) {
                    return new ol.style.Style({
                        image: new ol.style.Icon({
                            src: 'img/location.png'
                        })
                    })
                }
                else {
                    return new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 30,
                            stroke: new ol.style.Stroke({
                                color: 'white'
                            }),
                            fill: new ol.style.Fill({
                                color: 'blue'
                            })
                        }),
                        text: new ol.style.Text({
                            text: size.toString(),
                            fill: new ol.style.Fill({
                                color: 'white'
                            })
                        })
                    })
                }
            }
        });

        // Create a map var map = new ol.Map({
            target: 'map',
            layers:
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                layer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10,
                minZoom: 5,
                maxZoom: 14
            })
        });
    </script>
</body>
</html>

The running results are shown in the figure below:

insert image description here

In fact, this effect is very simple to implement. The core code is: var size = feature.get('features').length; If size>1 , it returns the aggregate style, otherwise it returns the image style.

4. Special treatment of polymerization 2

In the above code, I set the maximum zoom level of the map to 14 , which leads to a problem:當地圖縮放到最大層級時,還有很多點保持著聚合效果. Sometimes users may request當地圖縮放到最大層級時,取消全部聚合效果. If we want to implement this function, we need to listen to the map events. The code is as follows:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta charset="utf-8" />
    <title>OpenLayers</title>
    <style>
        html, body, #map {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
    <link href="libs/ol/ol.css" rel="stylesheet" />
    <script src="libs/ol/ol.js"></script>
</head>
<body>
    <div id="map"></div>

    <script>
        // Create 1000 random features var source = new ol.source.Vector();
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.00 + Math.random(), 30.00 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.01 + Math.random(), 30.01 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.02 + Math.random(), 30.02 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.03 + Math.random(), 30.03 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }
        for (var i = 1; i <= 200; i++) {
            var coordinates = [120.04 + Math.random(), 30.04 + Math.random()];
            var feature = new ol.Feature(new ol.geom.Point(coordinates));
            source.addFeature(feature);
        }

        // Aggregation var cluster = new ol.source.Cluster({
            source: source,
            distance: 100
        })

        // Create a layer var layer = new ol.layer.Vector({
            source: cluster,
            style: function (feature, resolution) {
                var size = feature.get('features').length;
                if (size == 1) {
                    return new ol.style.Style({
                        image: new ol.style.Icon({
                            src: 'img/location.png'
                        })
                    })
                }
                else {
                    return new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 30,
                            stroke: new ol.style.Stroke({
                                color: 'white'
                            }),
                            fill: new ol.style.Fill({
                                color: 'blue'
                            })
                        }),
                        text: new ol.style.Text({
                            text: size.toString(),
                            fill: new ol.style.Fill({
                                color: 'white'
                            })
                        })
                    })
                }
            }
        });

        // Create a map var map = new ol.Map({
            target: 'map',
            layers:
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                layer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10,
                minZoom: 5,
                maxZoom: 14
            })
        });

        // Listen for map resolution change events map.getView().on('change:resolution', function (event) {
            if (map.getView().getZoom() == map.getView().getMaxZoom()) {
                cluster.setDistance(0);
            }
            else {
                cluster.setDistance(100);
            }
        })
    </script>
</body>
</html>

The running results are shown in the figure below:

insert image description here

The implementation of this effect is also very simple. You only need to listen to the resolution change event of the current map. If the current zoom level is already the maximum level, set the aggregation distance to 0 .

5. Conclusion

When there are a large number of elements, we should consider aggregating them, which not only improves the user experience but also avoids interface freezes. In fact, in the above code, I listened to change:resolution event. You can also change it to another event - moveend . The code is as follows:

map.on('moveend', function (event) {
    if (map.getView().getZoom() == map.getView().getMaxZoom()) {
        cluster.setDistance(0);
    }
    else {
        cluster.setDistance(100);
    }
});

The same effect can be achieved by listening to the moveend event, because this event will be triggered regardless of whether the map is zoomed or panned.

This is the end of this article about how to implement aggregate display of point feature layers in OpenLayers. For more content about aggregate display of point feature layers in OpenLayers, please search previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Openlayers+EasyUI Tree dynamically realizes layer control
  • OpenLayers3 implements layer control function
  • OpenLayers implements layer switching control

<<:  Solution to Ubuntu 20.04 Firefox cannot play videos (missing flash plug-in)

>>:  Super detailed MySQL usage specification sharing

Recommend

JavaScript to achieve simple drag effect

This article shares the specific code of JavaScri...

Detailed discussion of several methods for deduplicating JavaScript arrays

Table of contents 1. Set Deduplication 2. Double ...

Example of implementing skeleton screen with Vue

Table of contents Skeleton screen use Vue archite...

Solve the problem of MySql8.0 checking transaction isolation level error

Table of contents MySql8.0 View transaction isola...

Detailed explanation of scp and sftp commands under Linux

Table of contents Preface 1. scp usage 2. Use sft...

js realizes horizontal and vertical sliders

Recently, when I was doing a practice project, I ...

Common methods of Vue componentization: component value transfer and communication

Related knowledge points Passing values ​​from pa...

What is BFC? How to clear floats using CSS pseudo elements

BFC Concept: The block formatting context is an i...

The easiest way to reset mysql root password

My mysql version is MYSQL V5.7.9, please use the ...

NodeJS realizes image text segmentation

This article shares the specific code of NodeJS t...

Centos7.5 installs mysql5.7.24 binary package deployment

1. Environmental preparation: Operating system: C...

Vue implements chat interface

This article example shares the specific code of ...

Detailed description of the use of advanced configuration of Firewalld in Linux

IP masquerading and port forwarding Firewalld sup...