vue3封装高德地图类

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;
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值