vue在PC端引用百度地图实现自定义省市区海量点

vue在PC端引用百度地图实现自定义省、市、区、项目、设备海量点,根据地图的zoomLevel设置成4-6级是省级别、7-9级是市级别、10-12级是区级别、13和14级是项目级别、15级-15级以上是设备级别

1.登录百度地图开发平台创建key  应用类型选择"浏览器端"

链接: 登录百度账号

2.可自行设置个性化样式模板-下图使用的是"眼眸"

链接: 登录百度账号

效果图

一.定义utils工具

src/utils/arrayOperation.ts

// JS去除JSON字符串各种空格、换行符
export function disposeJsonStr(str: string) {
  return str.replace(/\r\n/g, "").replace(/\n/g, "").replace(/\s+/g, "");
}

src/utils/baidu-map.ts

declare const window: any;

// GL版本
export function baiduMapGL() {
  return new Promise(function (resolve, reject) {
    if (typeof window.initBMapGL !== "undefined") {
      resolve(window.initBMapGL);
      return;
    }
    window.initBMapGL= function () {
      resolve(window.initBMapGL);
      // getPosition()
    };
    const script = document.createElement("script");
    script.type = "text/javascript";
    script.src = `https://api.map.baidu.com/api?v=1.0&type=webgl&ak=${你的ak}&callback=initBMapGL`;
    script.onerror = reject;
    document.head.appendChild(script);
  });
}

二.定义图标

放在src/assets目录下

m1.png

m2.png

m3.png

 markerIcon.png

三.定义组件

在与vue页面文件同级目录定义组件 bmap.vue

<template>
    <!-- 地图 -->
    <div id="container" ref="container" style="z-index:1" v-loading="loading" element-loading-text="拼命加载中"
        element-loading-background="rgba(0, 0, 0, 0)"></div>
</template>
  
<script lang="ts">
import { toRefs, reactive, onMounted, getCurrentInstance, defineComponent, nextTick, watch, onBeforeUnmount } from 'vue';
import { disposeJsonStr } from '/@/utils/arrayOperation';
import mapDevIcon from '/@/assets/markerIcon.png';
import m1Png from '/@/assets/m1.png';
import m2Png from '/@/assets/m2.png';
import m3Png from '/@/assets/m3.png';
import { baiduMapGL } from "/@/utils/baidu-map";

let map: any = null;
const _window = window as any;
export default defineComponent({
    name: 'Bmap',
    setup(props: any, { emit }: any) {
        onBeforeUnmount(() => {
            map && map.destroy();
            map = null
        }) 

        // 页面加载时
        onMounted(async () => {
            baiduMapGL().then(() => {
                initMap(); // 创建地图
            })
        });

        const { proxy }: any = getCurrentInstance();

        const state = reactive({
            countryZoom: 3, // 小于等于当前 属于国范围级别

            min_provinceZoom: 4,// 省范围级别  
            middle_provinceZoom: 5,// 省范围级别  
            max_provinceZoom: 6,// 省范围级别  

            min_cityZoom: 7,// 市范围级别
            middle_cityZoom: 8,// 市范围级别
            max_cityZoom: 9,// 市范围级别

            min_areaZoom: 10,// 区范围级别
            middle_areaZoom: 11,// 区范围级别
            max_areaZoom: 12,// 区范围级别

            min_projectZoom: 13,// 项目范围级别
            max_projectZoom: 14,// 项目范围级别

            deviceZoom: 15,// 大于等于当前 属于设备范围级别

            latitude: 22.55329,
            longitude: 113.88308,
            zoom: 5,

            provinceList: [], //省数据
            cityList: [], //市数据
            areaList: [], //区数据
            projectList: [], //项目列表
            deviceList: [], //设备列表

            isInitMapDataList: false,
            noTriggerMapTimer: null as any,
            newZoom: 0,

            loading: false,
        });


        const initMap = async () => {
            map = new BMapGL.Map('container');
            // 给百度地图设置个性化地图样式
            map.setMapStyleV2({
                styleId: "", // 你的styleId
            });
            map.enableScrollWheelZoom(true);
            var cityCtrl = new BMapGL.LocationControl(); // 添加城市列表控件
            map.addControl(cityCtrl);

            map.centerAndZoom(new BMapGL.Point(state.longitude, state.latitude), state.zoom); // 深圳的经纬度 113.88308, 22.55329

            setTimeout(() => {
                initMapDataList();
            }, 2000);

            map.addEventListener('zoomend', (e: any) => {
                state.newZoom = parseInt(e.target.zoomLevel);

                if (state.isInitMapDataList) return

                state.zoom = parseInt(e.target.zoomLevel)
                initMapDataList(undefined, 'zoomend');
            });

            map.addEventListener('dragend', (e: any) => {
                if (state.isInitMapDataList) return

                state.zoom = parseInt(map.getZoom());
                initMapDataList()
            });
        };

        watch(() => state.newZoom, (newZoom: any) => {
            clearTimeout(state.noTriggerMapTimer);
            state.noTriggerMapTimer = null;

            state.noTriggerMapTimer = setTimeout(() => {
                if (state.isInitMapDataList) return
                if (newZoom !== state.zoom) {
                    state.zoom = newZoom;
                    initMapDataList();
                }
            }, 1000);
        });

        const initMapDataList = async (id?: number, sign?: string,) => {
            if (state.zoom <= state.countryZoom) {
                state.cityList = [];
                state.provinceList = [];
                state.areaList = [];
                state.projectList = [];
                state.deviceList = [];
                return false
            } else if (state.zoom <= state.max_provinceZoom) {
                state.cityList = [];
                state.areaList = [];
                state.projectList = [];
                state.deviceList = [];
            } else if (state.zoom <= state.max_cityZoom) {
                state.provinceList = [];
                state.areaList = [];
                state.projectList = [];
                state.deviceList = [];
            } else if (state.zoom <= state.max_areaZoom) {
                state.provinceList = [];
                state.cityList = [];
                state.projectList = [];
                state.deviceList = [];
            } else if (state.zoom <= state.max_projectZoom) {
                state.provinceList = [];
                state.cityList = [];
                state.areaList = [];
                state.deviceList = [];
            } else {
                state.provinceList = [];
                state.cityList = [];
                state.areaList = [];
                state.projectList = [];
            }

            if (state.provinceList.length > 0 && state.zoom <= state.max_provinceZoom) return;
            if (sign === 'zoomend') {
                if (state.cityList.length > 0 && state.zoom <= state.max_cityZoom) return;
                if (state.areaList.length > 0 && state.zoom <= state.max_areaZoom) return;
                if (state.projectList.length > 0 && state.zoom <= state.max_projectZoom) return;
                if (state.deviceList.length > 0 && state.zoom >= state.deviceZoom) return;
            }

            state.isInitMapDataList = true // 开始加载地图数据

            let res: any;
            if (id) {
                res = await proxy.apis.ajaxmap({ areaid: id, grade: state.zoom });
                // 点击项目或者设备级别有数据就跳到有数据的位置
                if (state.zoom >= state.min_projectZoom) {
                    if (res.code === 200) {
                        let filterArr = res.data.filter((item: any) => item.longitude && item.latitude && Number(item.longitude) > Number(item.latitude))

                        if (filterArr.length > 0) {
                            state.loading = true
                            const element = filterArr[0];
                            let point = new BMapGL.Point(Number(element.longitude), Number(element.latitude))
                            setTimeout(() => {
                                state.loading = false
                                map.centerAndZoom(point, state.zoom);
                            }, 500);
                        } else {
                            return proxy.$message.warning("当前项目位置有误")
                        }
                    }
                }
            } else {
                res = await proxy.apis.ajaxmap({
                    lng: map.getCenter().lng.toFixed(6),
                    lag: map.getCenter().lat.toFixed(6),
                    grade: state.zoom,
                });
            }

            if (res.code === 200) {
                map.clearOverlays();
                setTimeout(() => {
                    state.isInitMapDataList = false
                }, 1000);

                let list = [] as any[];
                if (state.zoom <= state.countryZoom) {
                } else if (state.zoom <= state.max_provinceZoom) {
                    state.provinceList = res.data;
                    list = state.provinceList;
                } else if (state.zoom <= state.max_cityZoom) {
                    state.cityList = res.data;
                    list = state.cityList;
                } else if (state.zoom <= state.max_areaZoom) {
                    state.areaList = res.data;
                    list = state.areaList;
                } else if (state.zoom <= state.max_projectZoom) {
                    state.projectList = res.data;
                    list = state.projectList;
                } else {
                    state.deviceList = res.data;
                    list = state.deviceList;
                }
                for (let i = 0; i < list.length; i++) {
                    const item = list[i];
                    var points = new BMapGL.Point(item.longitude ? Number(item.longitude) : 0, item.latitude ? Number(item.latitude) : 0); //创建坐标点
                    let valueBgc = state.zoom <= state.max_provinceZoom ? '#3a7e7e' : state.zoom <= state.max_cityZoom ? '#afc018' : '#8e4191';

                    let bgImg = item.value >= 100 ? m3Png : item.value >= 10 ? m2Png : m1Png;
                    let placeName_dom =
                        `<div class='regionLabel'><div class='name'>${item.name}</div><div class="value" style="background:${valueBgc};border: 1px solid ${valueBgc};">${item.value}</div> <div class="triangle"></div></div>`;
                    let projectText =
                        `<div  class='projectText' data-projectItem=${disposeJsonStr(JSON.stringify(item))} onclick="$handleProjectText(event)" style="z-index:999999;">${item.name}<div class="triangle"></div></div>`
                    let project_dom =
                        `<div class='projectBgImgLabel' style="background-image: url(${bgImg});background-size:contain;">${item.value} ${projectText}</div>`;

                    let label_dom = state.zoom <= state.max_areaZoom ? placeName_dom : state.zoom <= state.max_projectZoom ? project_dom : '';
                    let markersLabel = new BMapGL.Label(label_dom, {
                        offset: new BMapGL.Size(-22, -45),
                        direction: 'top', //设置文本标注方位
                    });
                    markersLabel.setStyle({
                        border: '0',
                        backgroundColor: 'none',
                    });

                    markersLabel.addEventListener('click', async function (event: any) {
                        if (state.isInitMapDataList) return
                        if (state.zoom >= state.min_areaZoom && Number(item.value) === 0) return proxy.$message.warning(`${item.name}没有项目`)

                        let lnglatInfo = new BMapGL.Point(Number(item.longitude), Number(item.latitude))

                        if (state.zoom >= state.max_areaZoom && state.zoom <= state.max_projectZoom) {
                            state.zoom += 2
                        } else {
                            state.zoom += 3
                        }
                        if (state.zoom <= state.max_areaZoom) {
                            map.centerAndZoom(lnglatInfo, state.zoom);
                        }
                        initMapDataList(item.id,);
                    });

                    // 渲染Marker 省市区项目级只显示label
                    initMarker(points, markersLabel, item,);

                }

            } else {
                proxy.$message.error(res.message)
            }
        };

        function initMarker(points: any, markersLabel: any, row: any,) {
            var myIcon = new BMapGL.Icon(mapDevIcon, new BMapGL.Size(state.zoom >= state.deviceZoom ? 50 : 0, state.zoom >= state.deviceZoom ? 50 : 0));
            let markers = new BMapGL.Marker(points, {
                icon: myIcon,
                enableDragging: true, // 可移动
            });
            nextTick(() => {
                map.addOverlay(markers);
                markers.setLabel(state.zoom >= state.deviceZoom ? '' : markersLabel);
            })

            if (state.zoom >= state.deviceZoom) {
                markers.addEventListener('click', function (event: any) {
                    infoWindow(points, row);
                });
                let route_lng = Number(proxy.$route.query.longitude);
                let route_lat = Number(proxy.$route.query.latitude);
                if (route_lng === points.lng && route_lat === points.lat) {
                    state.loading = true;
                    setTimeout(() => {
                        let havePoints = new BMapGL.Point(Number(route_lng), Number(route_lat)); //创建坐标点
                        infoWindow(havePoints, row);
                    }, 500);
                }
            }
        }

        _window.$handleProjectText = function handleProjectText(e: any,) {
            e.stopPropagation();

            const item = JSON.parse(e.target.dataset.projectitem)

            openProjectInfoWindow(item);
        }

        const openProjectInfoWindow = function (item: any) {
            let points = new BMapGL.Point(item.longitude, item.latitude); //创建坐标点
            let geoc = new BMapGL.Geocoder();
            geoc.getLocation(points, (rs: any) => {
                // 地址名称
                let currentAddress = rs.address;
                let dom = `
							  <div>${item.id ? "设备数量" : "分路数量"}: ${item.value}</div>
							  <div>详细地址: ${currentAddress}</div>
							  <div class="btnBox"><div class="actionBtn" data-item=${disposeJsonStr(JSON.stringify(item))} onclick="$detailsAction()">项目详情</div></div>`;
                // 创建文本标注对象
                var labelopts = {
                    position: points, // 指定文本标注所在的地理位置
                    offset: new BMapGL.Size(10, -75), // 设置文本偏移量
                    title: item.name,
                    // width: 50,
                    // height: 100,
                };

                let infoWindows = new BMapGL.InfoWindow(dom, labelopts);
                map.openInfoWindow(infoWindows, points); // 开启信息窗口 鼠标移出
            });
        };


        _window.$detailsAction = function detailsAction() {
            const dom = document.querySelector('.actionBtn') as HTMLElement;
            let item: any = dom.getAttribute('data-item');

            item = JSON.parse(item);

            if (item.id) {
                proxy.$router.push(`/deviceManage/projectDevice?projectid=${item.id}`);
            }
            if (item.deviceid) {
                proxy.$router.push(`/deviceManage/sonDevice?deviceid=${item.deviceid}`);
            }
        };


        const infoWindow = function (points: any, row: any) {
            var opts = {
                // width: 50,
                // height: 100,
                title: row.name,
            };
            var geoc = new BMapGL.Geocoder();
            geoc.getLocation(points, (rs: any) => {
                // 地址名称
                let currentAddress = rs.address;
                let dom = `
							  <div>${row.id ? "设备数量" : "分路数量"}: ${row.value}</div>
							  <div>详细地址: ${currentAddress}</div>
							  <div class="btnBox"><div class="actionBtn" data-item=${disposeJsonStr(JSON.stringify(row))} onclick="$detailsAction()">设备详情</div></div>`;
                var infoWindows = new BMapGL.InfoWindow(dom, opts);
                map.openInfoWindow(infoWindows, points); // 开启信息窗口 鼠标移出
                state.loading = false;
            });
        };

        return {
            ...toRefs(state),
        };
    },
});
</script>
  

<style scoped lang="scss">
#container {
    height: 100%;
    width: 100%;
}

:deep(.BMapLabel) {
    .regionLabel {
        color: #fff;
        height: 28px;
        line-height: 28px;
        position: relative;
        display: flex;
        border: 1px solid #30f0f2;
        border-radius: 5px 0 5px 0;
        background: rgba(57, 91, 102, 0.6);

        .name {
            padding: 0 6px;
        }

        .value {
            font-size: 16px;
            border-radius: 0 0 5px 0;
            padding: 0 6px;
        }

        .triangle {
            border-left: 6px solid transparent;
            border-right: 6px solid transparent;
            border-top: 6px solid #30f0f2;
            width: 0;
            height: 0;
            position: absolute;
            left: 15px;
            bottom: -6.5px;
        }
    }

    .projectBgImgLabel {
        width: 56px;
        height: 56px;
        text-align: center;
        line-height: 56px;
        background-position: center;
        color: #fff;
        font-size: 12px;

        .projectText {
            position: absolute;
            top: -30px;
            left: 50%;
            transform: translateX(-50%);
            color: #fff;
            height: 30px;
            line-height: 30px;
            display: flex;
            border: 1px solid #30f0f2;
            border-radius: 5px;
            background: rgba(57, 91, 102, 1);
            padding: 0 6px;
            cursor: pointer;

            .triangle {
                border-left: 6px solid transparent;
                border-right: 6px solid transparent;
                border-top: 6px solid #30f0f2;
                width: 0;
                height: 0;
                position: absolute;
                left: 50%;
                transform: translateX(-50%);
                bottom: -6.5px;
            }
        }
    }
}


:deep(.BMap_bubble_pop) {
    background: #0f2858 !important;

    .BMap_bubble_title {
        font-size: 16px;
        color: #fff !important;
    }

    .BMap_bubble_center {
        .BMap_bubble_content {
            color: #fff !important;

            .btnBox {
                display: flex;
                justify-content: flex-end;
                margin: 5px;
                height: 26px;
                line-height: 26px;

                .actionBtn {
                    border: 1px solid #ccc;
                    font-size: 12px;
                    background: transparent;
                    color: #fff;
                    padding: 0 5px;
                    border-radius: 3px;
                    cursor: pointer;

                    &:hover {
                        color: #6dcff6;
                        border: 1px solid #6dcff6;
                    }
                }
            }

            .noneBtnBox {
                display: none;
            }
        }
    }
}
</style>

四.页面文件引用

1.在script脚本引入、注册组件

import Bmap from "./bmap.vue"

components: { Bmap },

2.在template模板使用组件

<Bmap></Bmap>

五.前后端交互的数据

1.拖拽和缩放地图的请求载荷

传给后端的字段是根据地图的缩放等级(grade)和地图的中心经度(lng)、地图的中心纬度(lat)

2.点击海量点的请求载荷

传给后端的字段是地图的被点击海量点的id(areaid)和地图的缩放等级(grade)

3.后端返回给前端的数据格式,都是数组嵌套对象 

省、市、区、项目的数据,对象的字段是: name、value、latitude、longitude、id

设备的数据,对象的字段是: name、value、latitude、longitude、deviceid

省数据 

市数据 

区数据 

​项目数据 

设备数据

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值