vue3封装高德地图类
import { h, render } from "vue";
import { IMapParams } from '@/interfaces/IMapParams';
import AMapLoader from '@amap/amap-jsapi-loader';
import EventBus from "@/utils/bus";
import DeviceMarker from "@/components/你的组件.vue";
import ClusterMarker from "@/components/你的组件.vue";
import DeviceWin from "@/components/你的组件.vue";
class DeviceMap {
private static mapInstance: DeviceMap | null = null;
private points: any[] = [];
private cluster: any = null;
private static count: number = 0;
private static infoWindow: any = null;
private bus: EventBus = EventBus.getInstance();
// 用户传参
private originMap: any = null; // 原始地图
private canvas: string;
private amapKey: string = "";
private plugins: string[] = [];
private uis: string[] = [];
private styleId: string = "";
// 固定参数
private zoom: number = 12;
private zooms: number[] = [4, 20];
private center: number[] = [115.85, 28.68];
private constructor(param: IMapParams) {
this.canvas = param.canvas;
this.amapKey = param.amapKey || "你的地图key";
this.styleId = param.styleId || "你的地图样式id";
this.plugins = param.plugins || [];
this.uis = param.uis || [];
this.loadMap();
}
// 加载地图文件
private async loadMap() {
window._AMapSecurityConfig = {
securityJsCode: '你的地图密钥',
}
try {
await AMapLoader.load({
key: this.amapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: this.plugins, // 需要使用的的插件列表,如比例尺'AMap.Scale'等
AMapUI: {
version: "1.1",
plugins: this.uis,
}
});
DeviceMap.infoWindow = new window.AMap.InfoWindow({
offset: new window.AMap.Pixel(0, -35),
anchor: 'bottom-center',
isCustom: true, //使用自定义窗体
autoMove: false, // 设置为false可避免 InfoWindow 和 setCenter冲突导致不能够正确的设置中心点
});
this.initMap();
} catch (error) {
setTimeout(() => {
console.log("5s后重新加载");
this.loadMap();
}, 5000);
}
}
private async getLocation() {
const userStore = useUserStore();
let res = await fetchRegionDetail(userStore.userInfo.area_code);
let detail = res.data.data;
this.center = [detail.centerLng, detail.centerLat];
this.originMap.setCenter(this.center);
}
// 初始化地图
private initMap() {
this.originMap = new window.AMap.Map(this.canvas, {
zoom: this.zoom, // 级别
zooms: this.zooms, // 层级范围
center: this.center, // 中心点坐标
mapStyle: `amap://styles/${this.styleId}`,
showLabel: true,
});
this.bus.emit("onReady");
this.getLocation();
}
// 对外获取地图实例
public static getInstance(param: IMapParams) {
if (!DeviceMap.mapInstance || param.freshed) {
DeviceMap.mapInstance = new DeviceMap(param);
}
return DeviceMap.mapInstance;
}
private _renderClusterMarker(context: Record<string, any>) {
let div = document.createElement('div');
let size = Math.round(60 + Math.pow(context.count / DeviceMap.count, 1 / 5) * 20);
render(h(ClusterMarker, { count: context.count, size: size, type: 'devicePatrol' }), div);
context.marker.setOffset(new window.AMap.Pixel(-size / 2, -size / 2));
context.marker.setContent(div);
}
private _renderMarker(context: Record<string, any>) {
let content = document.createElement('div');
render(h(DeviceMarker, { type: context.data[0].schoolType, isHasDevice: context.data[0].hasDevice == 1 }), content); // isHasDevice 是否安装设备
let offset = new window.AMap.Pixel(-28, -39);
context.marker.setContent(content);
context.marker.setOffset(offset);
context.marker.setExtData(context.data[0]);
}
on(eventName: string, handler: Function) {
this.bus.on(eventName, handler);
}
off(eventName: string, handler?: Function) {
this.bus.off(eventName, handler);
}
addCluster(points: any[], onClick?: Function) {
if (points.length === 0) return this.cluster.setMap(null);
this.points = points;
DeviceMap.count = points.length;
let gridSize = 60;
if (this.cluster) {
this.cluster.setMap(null);
}
this.cluster = new window.AMap.MarkerCluster(this.originMap, this.points, {
gridSize: gridSize, // 设置网格像素大小
renderClusterMarker: this._renderClusterMarker, // 自定义聚合点样式
renderMarker: this._renderMarker, // 自定义非聚合点样式
});
this.cluster.setAverageCenter(true)
this.cluster.on("click", (e: any) => {
onClick && onClick(e.clusterData)
console.log(e)
if (e.clusterData.length > 1) {
this.originMap.setCenter(e.lnglat, false, 1000);
this.originMap.zoomIn();
} else {
let div = document.createElement("div");
let _data = e.marker.getExtData();
render(h(DeviceWin, {
..._data
}), div);
DeviceMap.infoWindow.setContent(div);
DeviceMap.infoWindow.open(this.originMap, e.marker.getPosition());
}
})
}
// 新增参与聚合的标点
addData(points: any[]) {
this.cluster && this.cluster.addData(points)
this.cluster && this.cluster.setAverageCenter(true)
}
hideWin() {
DeviceMap.infoWindow.close();
}
setMapCenter(lnglat: number[]) {
this.originMap.setCenter(lnglat, false, 1000)
}
setMapZoom(_zoom: number) {
this.originMap.setZoom(_zoom);
}
setMapZoomAndCenter(_zoom: number, lnglat: number[], immediately = false) {
this.originMap.setZoomAndCenter(_zoom, lnglat, immediately, 1000)
}
public static getMap() {
return DeviceMap.mapInstance;
}
// 获取当前 id 的覆盖物
getOneOverlay(markers: any[], targetId: string, lnglat?: number[]) {
console.log(markers.length, '地图标点的长度')
this.originMap.setCenter(lnglat)
let _data:any = {};
for(var i = 0; i < markers.length; i++){
// 获取存在每个 extData 中的 id
var id = markers[i].id;
if(id === targetId){
_data = markers[i];
break;
}
}
if(!_data.id){
ElMessage({ message: "该单位地图点暂未渲染,请稍后操作", type: "warning" });
return false;
}
let position = lnglat ? lnglat : _data.lnglat
let div = document.createElement("div");
render(h(DeviceWin, {
..._data
}), div);
DeviceMap.infoWindow.setContent(div);
DeviceMap.infoWindow.open(this.originMap, position);
}
}
export default DeviceMap;
使用方式
<template>
<div class=''>
<div class="device_map" id="deviceMap"></div>
</div>
</template>
<script setup lang='ts'>
import DeviceMap from "@/store/DeviceMap";
function createMap() {
let map = DeviceMap.getInstance({ canvas: "deviceMap", plugins: ["AMap.MarkerCluster", "AMap.InfoWindow"], freshed: true });
map.on("onReady", () => {
// todo
})
}
</script>
eventBus类
class EventBus {
private _events: Record<string, Function[]>;
static instance: any;
constructor() {
this._events = {};
}
//静态方法
static getInstance(): EventBus {
if (!this.instance) {
this.instance = new EventBus();
}
return this.instance;
}
emit(eventName: string, args?: string | number | Record<string, any>) {
let fns = this._events[eventName] || [];
fns.forEach(fn => fn(args));
}
on(eventName: string, handler: Function) {
if (this._events[eventName]) {
this._events[eventName].push(handler);
} else {
this._events[eventName] = [handler];
}
}
off(eventName: string, handler?: Function) {
if (handler) {
if (this._events[eventName]) {
let index = this._events[eventName].findIndex(h => h == handler);
index >= 0 && (this._events[eventName].splice(index, 1));
}
} else {
this._events[eventName] && (this._events[eventName] = []);
}
}
}
export default EventBus;