需求描述
在地图上实现一个点位的图层展示,但是有的时候地图上的点位非常多,而且有些经纬度非常接近,导致地图上的点位展示非常密集,这个时候,如果直接在地图上展示所有点位就会降低用户的视觉体验,而且也容易卡顿,如下图所示:
解决思路
针对以上这种情况的的出现,OpenLayers给出了一个解决办法——聚类。
通常情况,我们在给地图添加图层时,会new一个VectorSource作为数据源,而聚类实际上就是把new的VectorSource作为聚类地一个属性source,再去new一个Cluster作为图层的数据源。
具体实现
点位保持聚类展示
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import View from 'ol/View';
import {
Circle as CircleStyle,
Fill,
Stroke,
Style,
Text,
} from 'ol/style';
import {Cluster, OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {boundingExtent} from 'ol/extent';
const distanceInput = document.getElementById('distance');
const minDistanceInput = document.getElementById('min-distance');
//模拟一些地图上的点位
const count = 20000;
const features = new Array(count);
const e = 4500000;
for (let i = 0; i < count; ++i) {
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
features[i] = new Feature(new Point(coordinates));
}
//设置地图的数据源
const source = new VectorSource({
features: features,
});
//把数据源转化成聚类模式下的数据源
const clusterSource = new Cluster({
distance: 100,
source: source,
});
const styleCache = {};
const clusters = new VectorLayer({
source: clusterSource,
style = function (feature) {
//size表示在聚类的点位上展示集合的点位数量
let size = feature.get('features').length;
let style = new Style({
image: new Circle({
radius: 15,
fill: new Fill({
color: 'orange',
}),
}),
text: new Text({
text: size.toString(),
font: 'normal 12px Arial',
fill: new Fill({
color: '#000',
}),
}),
});
return style;
};
});
const raster = new TileLayer({
source: new OSM(),
});
const map = new Map({
layers: [raster, clusters],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});
点位在聚类只有一个点时展示后端返回的图标
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import View from 'ol/View';
import {
Circle as CircleStyle,
Fill,
Stroke,
Style,
Text,
} from 'ol/style';
import {Cluster, OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {boundingExtent} from 'ol/extent';
const distanceInput = document.getElementById('distance');
const minDistanceInput = document.getElementById('min-distance');
//模拟一些地图上的点位
const count = 20000;
const features = new Array(count);
const e = 4500000;
for (let i = 0; i < count; ++i) {
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
features[i] = new Feature(new Point(coordinates));
}
//设置地图的数据源
const source = new VectorSource({
features: features,
});
//把数据源转化成聚类模式下的数据源
const clusterSource = new Cluster({
distance: 100,
source: source,
});
const styleCache = {};
const clusters = new VectorLayer({
source: clusterSource,
style = function (feature) {
//size表示在聚类的点位上展示集合的点位数量
let size = feature.get('features').length;
let style;
// 此刻的判断就是实现需求的关键点,当聚类只有一个点时,即size=1,显示后端返回的图标,多个点时显示聚类
if (size == 1) {
//由于聚类不同于普通点位图层,一个f中有很多点位,所以必须要遍历f去拿到单个的f
feature.get('features').forEach((value, index) => {
style = new Style({
image: new Icon({
src: value.get('obj').industry_type_icon,
}),
});
});
} else {
style = new Style({
image: new Circle({
radius: 15,
fill: new Fill({
color: 'orange',
}),
}),
text: new Text({
text: size.toString(),
font: 'normal 12px Arial',
fill: new Fill({
color: '#000',
}),
}),
});
}
return style;
};
});
const raster = new TileLayer({
source: new OSM(),
});
const map = new Map({
layers: [raster, clusters],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});