效果图
前言
当地图上的标记点太多,就会造成信息的不直观,以及画面的不美观(过于密集),因此就需要使用点聚合来合并相邻的标记点。(又是咸鱼了一天才搞出来的)
目前这个效果使用了leaflet 搭配PruneCluster实现,官网的api其实挺详细的,但奈何本人英文不过关,网上的资料又少的可怜,着实花了一段时间。官网传送门:github.com/SINTEF-9012…
代码详解
关于leaflet的代码整合放到了github上,传送门:github.com/SaltedFishH…
下载和导入
npm install exports-loader prunecluster
import { PruneCluster, PruneClusterForLeaflet } from "exports-loader?PruneCluster,PruneClusterForLeaflet!prunecluster/dist/PruneCluster.js";
- 这块内容需要注意的是官方提示了有一个方法需要调用,只有调用了它才能进行标记点的点击事件等,并且需要使用setInterval()来调用(目前我还没搞明白为啥)
setInterval(()=> {
leafletView.ProcessView();
}, 500);
- 所要触发标记点的点击事件,需要使用PrepareLeafletMarker,要在外部将标记点自己的独立信息配置好传进去,不然每一次渲染地图都会被最后的配置所覆盖
// 在data中配置好标记点等信息
leafletView.PrepareLeafletMarker = function(leafletMarker, data) {}
- 标记点点击事件因为每一次的缩放都会不断的叠加,要记得删除
leafletMarker.off('click')
详细代码
<template>
<div>
<div id="myMap" class="map-box"></div>
<button class="delete-btns" @click="delMarker">删除</button>
</div>
</template>
<script>
import L from "leaflet";
import Provider from "@/components/chinatmsproviders";
require("leaflet/dist/leaflet.css");
// 引入PruneCluster
import { PruneCluster, PruneClusterForLeaflet } from "exports-loader?PruneCluster,PruneClusterForLeaflet!prunecluster/dist/PruneCluster.js";
export default {
data() {
return {
mapKey: "", //你的key
marker: [],
mapMarker: [],
mapData: [
{ name: "标记1", tips: "这是标记1", lat: 30.16, lng: 120.53 },
{ name: "标记2", tips: "这是标记2", lat: 30.4, lng: 120.26 },
{ name: "标记3", tips: "这是标记3", lat: 30.04, lng: 120.41 },
{ name: "标记4", tips: "这是标记4", lat: 30.03, lng: 120.85 },
{ name: "标记5", tips: "这是标记5", lat: 30.18, lng: 120.45 },
{ name: "标记6", tips: "这是标记6", lat: 30.46, lng: 120.24 },
{ name: "标记7", tips: "这是标记7", lat: 30.45, lng: 120.24 },
{ name: "标记8", tips: "这是标记8", lat: 30.44, lng: 120.24 },
{ name: "标记9", tips: "这是标记9", lat: 30.43, lng: 120.24 },
{ name: "标记10", tips: "这是标记10", lat: 30.42, lng: 120.24 },
{ name: "标记11", tips: "这是标记11", lat: 30.45, lng: 120.25 },
{ name: "标记12", tips: "这是标记12", lat: 30.46, lng: 120.25 }
],
map: null,
leafletView: null,
};
},
mounted() {
Provider(L); // 挂载插件
this.getMap();
},
methods: {
// 删除标记
delMarker(){
this.leafletView.RemoveMarkers() // 全部清空,指定清空传入标记点信息
},
getMap() {
let myCenter = new L.LatLng(30.16, 120.53); // 中心点
let map = L.map("myMap", {
center: myCenter,
zoom: 9
});
L.tileLayer.chinaProvider("TianDiTu.Normal.Map", {
maxZoom: 18,
minZoom: 5,
key: this.mapKey
}).addTo(map);
L.tileLayer.chinaProvider("TianDiTu.Normal.Annotion", {
maxZoom: 18,
minZoom: 5,
key: this.mapKey
}).addTo(map);
this.map = map
this.getPointer(map);
},
getPointer(map) {
let _this = this; // 防止冲突
// 清空点
if(Array.isArray(this.mapMarker) && this.mapMarker.length > 0){
this.leafletView.RemoveMarkers();
this.mapMarker = []
}
// 添加地图图层
let leafletView = new PruneClusterForLeaflet() // 可传参配置距离和边距,不传默认距离和边距
this.mapData.map((res,index)=>{
// 设置标记点位置
let marker = new PruneCluster.Marker(res.lat,res.lng);
// 给标记点传入信息,若是动态更改编辑点,需要进行marker.data赋值,PrepareLeafletMarker中会取最后一次传入的数据覆盖所有
marker.data.info = res
marker.data.icon = L.icon({ // 标记配置-详见leaflet官网
iconUrl: require('../assets/icon.png'), // 使用require加载标记图
iconSize: [20,25],
})
/*
// 若是使用iconfont
marker.data.icon = L.divIcon({
html: '<i class="iconfont icon-zuobiao"></i>',
className: `point-tips` // 可以自定义marker的class名
})
*/
// 添加标记点点击事件
leafletView.PrepareLeafletMarker = function(leafletMarker, data) {
// 标记点
leafletMarker.setIcon(data.icon)
leafletMarker.bindTooltip(data.info.name, {
direction: 'right' ,
})
// 取消点击事件,防止加载多次-on('click')事件会不断叠加,导致点击事件触发N次,所以需要先取消之前的所有点击事件
leafletMarker.off('click')
// 标记点点击事件
leafletMarker.on('click', function(e){
console.log('我点击了');
});
};
// 注册标记点
leafletView.RegisterMarker(marker);
// 保存标记点-动态显示的时候用到
this.mapMarker.push(marker)
})
// 保存,进行更改前需要保存!这个一定要这样写(暂时还不了解为啥)但是不这样写无法触发事件
setInterval(()=> {
leafletView.ProcessView();
}, 500);
// 地图中添加地图图层
map.addLayer(leafletView);
// 保存地图图层配置
this.leafletView = leafletView
}
}
};
</script>
<style>
// 导入官方样式(文件可去github上下载)
@import '../../static/style/LeafletStyleSheet.css';
.delete-btns{
z-index: 9999;
position: absolute;
bottom: 100px;
left: 200px;
}
</style>