“This is the third day of my participation in the November Gwen Challenge. See details of the event: The last Gwen Challenge 2021”.
One, foreword
Due to the recent needs of the project, I need to use OpenLayers in the VUE project to develop GIS map. The article on OpenLayers is not too big on the Internet, so I take this opportunity to share some of my experience in the actual use of the project.
This series will share some of the feature points implemented over the course of the project. Past Catalogue:
-
Vue +OpenLayers Project Practice (I) : Basic drawing and clicking pop-ups
-
Vue +OpenLayers Project Practice (2) : Switching between multiple maps
In the actual project, we often need to batch to draw on the map coordinates, tag, if mark too much, will inevitably cause rendering time is too long, and a series of problems, and at the time of the relatively small zoom is unfavorable to check, so the official API provides a Cluster: Cluster, this paper is the use of simple talk about the process.
You can refer to the official example
Second, concrete implementation
First, analyze the functions we need to achieve:
- Draw a large number of coordinate points;
- Set the cluster, through zooming can display different cluster UI;
- Click the cluster point to enlarge the display;
- Other optimization;
1. Draw coordinate points
Just a few adjacent points are used here for demonstration purposes, changing the previous home.vue code
/ / data to add
data() {
return{...markerLayer: null.// Coordinate marker layer
markerSource: null.// Coordinate data source
};
},
Copy the code
Encapsulate the point data and VectorSource, add getPoints method and setMarkerSource method:
// demonstrate the direct static return coordinate array, the actual project can be changed to interface to get data
getPoints() {
return[[108.945951.34.465262],
[109.04724.34.262504],
[108.580321.34.076162],
[110.458983.35.071209],
[105.734862.35.49272]]; },setMarkerSource() {
let _style = new Style({
image: new sCircle({
radius: 10.stroke: new Stroke({
color: "#fff",}).fill: new Fill({
color: "#3399CC",})})});let _points = this.getPoints();
let _features = _points.reduce((list, item) = > {
let _feature = new Feature({
geometry: new Point(olProj.fromLonLat(item)),
});
_feature.setStyle(_style);
list.push(_feature);
returnlist; } []);this.markerSource = new VectorSource({
features: _features,
});
}
Copy the code
Modify the previous setMarker method:
setMarker() {
this.setMarkerSource();
this.markerLayer = new VectorLayer({
source: this.markerSource,
});
this.openMap.addLayer(this.markerLayer);
}
Copy the code
At this point, five coordinate points have been successfully drawn on the map
2. Set the cluster
Here we add the Cluster, first changing the previous setMarkerSource method
setMarkerSource(){...this.markerSource = new Cluster({
distance: 100.source: new VectorSource({
features: _features,
}),
});
}
Copy the code
After refreshing, you can see that the aggregation function has been implemented, but the previous point style is missing. We need to adjust the point style. Create a new style method setClusterStyle:
setClusterStyle() {
const styleCache = {};
const _style = (feature) = > {
const size = feature.get("features").length;
let style = styleCache[size];
if(! style) { style =new Style({
image: new sCircle({
radius: 10.stroke: new Stroke({
color: "#fff",}).fill: new Fill({
color: "#3399CC",})}),text: new Text({
text: size.toString(),
fill: new Fill({
color: "#fff",})})}); styleCache[size] = style; }return style;
};
return _style;
},
Copy the code
This takes the form of a closure that caches size. Now modify the setMarker method to add a style and remove the style Settings from the setMarkerSource method:
setMarker() {
this.setMarkerSource();
let _style = this.setClusterStyle();
this.markerLayer = new VectorLayer({
source: this.markerSource,
style: _style,
});
this.openMap.addLayer(this.markerLayer);
}
Copy the code
Ok, the style has been added successfully, but here we want the non-converged dots not to show numbers and the style to be different from the converged dots. Modify the code:
setClusterStyle() {
const styleCache = {};
const _style = (feature) = > {
const size = feature.get("features").length;
let style = styleCache[size];
if(! style) {if (size > 1) {
style = new Style({
image: new sCircle({
radius: 20.stroke: new Stroke({
color: "#fff",}).fill: new Fill({
color: "#3399CC",})}),text: new Text({
text: size.toString(),
fill: new Fill({
color: "#fff",})})}); }else {
style = new Style({
image: new sCircle({
radius: 15.stroke: new Stroke({
color: "#fff",}).fill: new Fill({
color: "#e9b626",})})}); } styleCache[size] = style; }return style;
};
return _style;
}
Copy the code
Size is used directly to determine whether it is an aggregate, and then different styles are set separately.
Set (“key”,”value”,” Boolean “) when creating a feature at each point. Then judge the Settings by item.get(“key”), and you can study them by yourself.
3. Cluster click events
OK, next we need to zoom in when clicking on the aggregation point and modify the previous click event singleclick
singleclick() {
/ / click
this.openMap.on("singleclick".(e) = > {
this.markerLayer.getFeatures(e.pixel).then((clickedFeatures) = > {
if (clickedFeatures.length) {
const features = clickedFeatures[0].get("features");
if (features.length > 1) {
const extent = boundingExtent(
features.map((r) = > r.getGeometry().getCoordinates())
);
this.openMap
.getView()
.fit(extent, { duration: 1000.padding: [200.200.200.200]}); }else {
this.shopPopup = true;
// Set the popover position
let coordinates = features[0].getGeometry().getCoordinates();
this.popup.setPosition(coordinates); }}else {
this.shopPopup = false; }}); }); },Copy the code
A new class boundingExtent is referenced here, which is an array of coordinates obtained by features.map((r) => r.getGeometry().getCoordinates()) and then scaled by fit(). That is, zoom to maximize the display of all points inside the aggregate, while keeping 200 padding at the edge.
Instead of aggregating the point point click to show the popover that we had before.
4. Other optimizations
At this point, we find that when we click on the show popover and zoom, the popover does not disappear, the effect is not ideal, so we need to listen to zoom and hide the popover. Add listener change:resolution on getView()
resolutionChange() {
// Listen for scaling
this.openMap.getView().on("change:resolution".(e) = > {
console.log(e);
this.shopPopup = false;
});
}
Copy the code
The last
Gitee address
Thank you for reading
It would be a great honor if I could help you.
In the future, more functions will be updated, as well as some problems encountered in the project, interested partners can click favorites/follow.