标记聚合
标记聚合是一种地图可视化技术,可以将地图上密集分布的标记点进行聚合显示。当地图缩小时,相近的标记点会合并成一个聚合点,显示该区域内标记点的数量;当地图放大时,聚合点会分散成单个标记点。这种效果可以有效避免标记点重叠,提升地图的可读性。
示例
代码实现
vue
<template>
<div class="h-screen">
<div id="map" class="w-full h-full"></div>
</div>
</template>
<script setup>
import { onMounted } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import { fromLonLat } from "ol/proj";
import Cluster from "ol/source/Cluster";
import { Circle, Fill, Stroke, Style, Text } from "ol/style";
onMounted(() => {
// 创建地图
const map = new Map({
target: "map",
view: new View({
center: fromLonLat([117.33083, 39.094899]), // 天津
zoom: 4,
}),
});
// 添加天地图图层
const tdtLayer = new TileLayer({
source: new XYZ({
url: "http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
}),
});
map.addLayer(tdtLayer);
// 标记点数据
const locations = [
{ lat: 23.1291, lng: 113.2644, name: "广东省" },
{ lat: 34.757, lng: 113.6249, name: "河南省" },
{ lat: 26.8154, lng: 106.3315, name: "贵州省" },
{ lat: 39.0949, lng: 117.3308, name: "天津" },
{ lat: 29.6469, lng: 91.1322, name: "西藏" },
{ lat: 43.666, lng: 126.1924, name: "吉林" },
{ lat: 36.62, lng: 95.66, name: "青海" },
{ lat: 20.044, lng: 110.1999, name: "海南" },
{ lat: 31.2304, lng: 121.4737, name: "上海" },
{ lat: 43.793, lng: 87.6, name: "新疆" },
{ lat: 38.469, lng: 106.2782, name: "宁夏" },
{ lat: 40.8183, lng: 111.6704, name: "内蒙古" },
{ lat: 39.9042, lng: 116.4074, name: "北京" },
{ lat: 41.8057, lng: 123.4315, name: "辽宁" },
{ lat: 29.563, lng: 106.55, name: "重庆" },
{ lat: 36.0583, lng: 102.4572, name: "甘肃" },
{ lat: 37.8734, lng: 112.562, name: "山西" },
{ lat: 34.3293, lng: 108.9402, name: "陕西" },
{ lat: 29.1042, lng: 115.8221, name: "江西" },
{ lat: 30.5928, lng: 114.3055, name: "湖北" },
{ lat: 30.2741, lng: 120.1551, name: "浙江" },
{ lat: 24.882, lng: 102.8329, name: "云南" },
{ lat: 31.82, lng: 117.2272, name: "安徽" },
{ lat: 27.6104, lng: 112.9834, name: "湖南" },
{ lat: 23.1242, lng: 108.32, name: "广西" },
{ lat: 32.0603, lng: 118.7969, name: "江苏" },
{ lat: 26.5783, lng: 106.7135, name: "贵州" },
{ lat: 38.4161, lng: 115.4839, name: "河北" },
];
// 创建矢量要素
const features = locations.map((location) => {
return new Feature({
geometry: new Point(fromLonLat([location.lng, location.lat])),
name: location.name,
});
});
// 创建矢量源
const source = new VectorSource({
features: features,
});
// 创建聚合源
const clusterSource = new Cluster({
distance: 40,
source: source,
});
// 创建聚合图层样式
const styleCache = {};
const clusters = new VectorLayer({
source: clusterSource,
style: function (feature) {
const size = feature.get("features").length;
let style = styleCache[size];
if (!style) {
style = new Style({
image: new Circle({
radius: 10 + Math.min(size, 20),
fill: new Fill({
color: "rgba(255, 153, 0, 0.8)",
}),
stroke: new Stroke({
color: "#fff",
width: 2,
}),
}),
text: new Text({
text: size.toString(),
fill: new Fill({
color: "#fff",
}),
}),
});
styleCache[size] = style;
}
return style;
},
});
map.addLayer(clusters);
// 添加点击事件
map.on("click", function (e) {
clusters.getFeatures(e.pixel).then(function (clickedFeatures) {
if (clickedFeatures.length) {
const features = clickedFeatures[0].get("features");
if (features.length === 1) {
const coords = features[0].getGeometry().getCoordinates();
map.getView().animate({
center: coords,
zoom: map.getView().getZoom() + 2,
duration: 500,
});
} else {
map.getView().animate({
center: clickedFeatures[0].getGeometry().getCoordinates(),
zoom: map.getView().getZoom() + 2,
duration: 500,
});
}
}
});
});
});
</script>
<style scoped>
.h-screen {
height: 24rem;
}
</style>