本篇介绍一下使用openlayers 要素聚合(cluster),icon聚合
1 需求
- 要素聚合(cluster),icon聚合
2 分析
使用cluster这个source
4 实现
<template>
<div id="map" class="map"></div>
<div class="toolbar">
<div>距离</div>
<el-slider
v-model="distance"
:min="1"
:max="300"
:step="1"
@change="handleChangeDistance"
></el-slider>
<div>最小距离</div>
<el-slider
v-model="minDistance"
:min="1"
:max="300"
:step="1"
@change="handleChangeMinDistance"
></el-slider>
</div>
</template>
<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { Point } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { get } from 'ol/proj';
import { XYZ, Cluster, Vector as VectorSource } from 'ol/source';
import { Fill, Stroke, Circle, Style, Text } from 'ol/style';
const projection = get('EPSG:4326');
const layerTypeMap = {
vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
image: ['img', 'cia'], // [影像底图, 影像注记]
terrain: ['ter', 'cta'] // [地形晕渲, 地形注记]
};
const styleCache = {};
const map = shallowRef();
const clusterSource = shallowRef();
const distance = ref(1);
const minDistance = ref(1);
const count = 1000;
const features = new Array(count);
for (let i = 0; i < count; ++i) {
const coordinates = [Math.random() + 120, Math.random() + 30];
features[i] = new Feature(new Point(coordinates));
}
onMounted(() => {
initMap('image');
});
const initMap = (layerType = 'image') => {
const key = '替换为天地图key';
// c: 经纬度投影 w: 墨卡托投影
const matrixSet = 'c';
clusterSource.value = new Cluster({
distance: distance.value,
minDistance: minDistance.value,
source: new VectorSource({
features: features
})
});
map.value = new Map({
target: 'map',
view: new View({
center: [116.406393, 39.909006],
projection: projection,
zoom: 5,
maxZoom: 17,
minZoom: 1
}),
layers: [
// 底图
new TileLayer({
source: new XYZ({
url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][0]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
projection
})
}),
// 注记
new TileLayer({
source: new XYZ({
url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][1]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
projection
})
}),
new VectorLayer({
source: clusterSource.value,
style: styleFunc
})
]
});
};
const styleFunc = feature => {
console.log('feature',feature)
// 获取聚合数量(当source为cluster时,feature上会有一个features树形,数组,包括聚合的所有feature)
const size = feature.get('features').length;
// 缓存样式
let style = styleCache[size];
if (!style) {
style = new Style({
image: new Circle({
radius: 10,
stroke: new Stroke({
color: '#fff'
}),
fill: new Fill({
color: 'rgba(228, 147, 87,0.8)'
})
}),
text: new Text({
text: size.toString(),
fill: new Fill({
color: '#fff'
})
})
});
styleCache[size] = style;
}
return style;
};
const handleChangeDistance = () => {
clusterSource.value.setDistance(distance.value);
};
const handleChangeMinDistance = () => {
clusterSource.value.setMinDistance(minDistance.value);
};
</script>
<style scoped lang="scss">
.map {
width: 100%;
height: 100%;
}
.toolbar {
position: absolute;
top: 20px;
left: 100px;
width: 500px;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
.el-slider {
margin-right: 50px;
}
div {
width: 100px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>