Vue3 对接高德地图之点击可下钻省市

一、效果如下如所示(点击右下角的地址可以定位到该位置):

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、在vue中的使用

  1. 父组件
<template>
    <div class="paths">
        <div v-for="(item,index) in paths" :key="index" class="path-item" @click="clickPath(item)">{{item.name}}</div>
    </div>
    <AMap ref="projectMap" :config="mapConfig" @featureClick="featureClick"></AMap>
</template>

<script>
import {onMounted, ref} from "vue";
import updata from "@/common/updata";
import iconPoint from "../assets/marker.png";
let infoWindow = null
export default {
    name: "projectMap2",
    setup(){
        const projectMap = ref()
        const paths = ref([
            {name:"全国",adcode:100000,level:'province'},
        ])
        const pathCode = ref([100000])
        const mapConfig = ref({
            zoomEnable:true,
            zoom:4.8
        })
        //获取项目分布
        const getProjectMap = (level) => {
            return new Promise(resolve => {
                let data = {}
                if(level === 'province'){
                    data = {
                        type:"省",
                    }
                }else if(level === 'city'){
                    data = {
                        type:"市",
                        province:paths.value[1].name
                    }
                }else{
                    data = {
                        type:"区",
                        province:paths.value[1].name,
                        city:paths.value[2].name
                    }
                }
                updata.getProjectMap(data).then(res=>{
                    if(res.code === '2000'){
                        projectMap.value.clear()
                        res.data.map(item=>{
                            let position = [Number(item.lng),Number(item.lat)]
                            let len = String(item.number).length
                            let scale = 1
                            let baseSize = 50
                            if(len<2){
                                baseSize = 50
                            }else if(len === 3){
                                baseSize = 60
                            }else{
                                baseSize = 70
                            }
                            let icon = new AMap.Icon({
                                image:iconPoint,
                                size:new AMap.Size(baseSize, baseSize*scale),
                                imageSize: new AMap.Size(baseSize, baseSize*scale),
                            })
                            projectMap.value.setMarker({
                                position: position,
                                offset: new AMap.Pixel(-25, -25),
                                icon: icon,
                            }, {
                                    offset: new AMap.Pixel(0, -(baseSize/4.5)), //设置文本标注偏移量
                                    content: '<div style="color:red;width:40px;">' + item.number + '</div>', //设置文本标注内容
                                    direction: 'center', //设置文本标注方位
                                },(marker,_map)=>{
                                    if(infoWindow){
                                        closeInfoWindow()
                                        infoWindow = null
                                    }
                                    let address = item.area ? item.area : item.city ? item.city : item.province
                                    marker.content = '<div class="infoWindow">' +
                                        `<div class="projectName">${address}:引进项目<span>${item.number}</span>个</div>`+
                                        '</div>';
                                    infoWindow = new AMap.InfoWindow({
                                        isCustom: true,
                                        offset: new AMap.Pixel(50, -30)
                                    });
                                    function showInfoWindow (e) {
                                        infoWindow.setContent(e.target.content);
                                        infoWindow.open(_map, e.target.getPosition());
                                    }
                                    function closeInfoWindow () {
                                        _map.clearInfoWindow();
                                    }
                                    marker.on('mouseout', closeInfoWindow);
                                    marker.on('mouseover', showInfoWindow);
                                }
                            )
                        })
                        resolve(data.value)
                    }
                })
            })
        }
        const featureClick = ({adcode,level,name}) => {
            if(!pathCode.value.includes(adcode)){
                if(level === 'district') return
                let types = {
                    "province":"city",
                    "city":"district"
                }
                pathCode.value.push(adcode)
                paths.value.push({name:name,adcode:adcode,level:types[level]})
                // let zoom = level === 'province' ? 4.8 : level === 'city' ? 7 : 9
                getProjectMap(types[level]).then(res=>{
                    projectMap.value.switchAreaNode(adcode)
                })
            }
        }
        const clickPath = (item) => {
            if(paths.value[paths.value.length - 1].adcode !== item.adcode){
                for(let i = 0;i<paths.value.length;i++){
                    if(paths.value[i].adcode === item.adcode){
                        getProjectMap(item.level).then(res=>{
                            // let zoom = item.level === 'city' ? 4.8 : item.level === 'district' ? 7 : 4.8
                            projectMap.value.switchAreaNode(item.adcode)
                            paths.value.splice(i + 1)
                            pathCode.value.splice(i + 1)
                        })
                        break;
                    }
                }
            }
        }
        onMounted(()=>{
            projectMap.value.ready(()=>{
                getProjectMap('province').then(()=>{
                    projectMap.value.switchAreaNode(100000,[
                        {adcode:100000,zoom:4.5,center:[106.2203,39.00214]},
                        {adcode:150000,zoom:5.5},
                        {adcode:650000,zoom:5.8},
                        {adcode:630000,zoom:6.5},
                        {adcode:540000,zoom:6},
                        {adcode:510000,zoom:6.8},
                        {adcode:520000,zoom:7.5},
                        {adcode:440000,zoom:7.5},
                        {adcode:350000,zoom:7.5},
                        {adcode:320000,zoom:7.5},
                        {adcode:370000,zoom:7.5},
                        {adcode:420000,zoom:7.2},

                    ])
                })
            })
        })
        return {
            mapConfig,
            projectMap,
            paths,
            featureClick,
            clickPath
        }
    }
}
</script>

<style scoped lang="less">
.paths{
    position: absolute;
    bottom:150px;
    width:300px;
    right:930px;
    z-index: 1000;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    background: #04498d;
    display: flex;
    flex-direction: column-reverse;
    .path-item{
        font-weight: bold;
        cursor: pointer;
        padding:20px;
        &:last-child{
            background: #0061C0;
        }
    }
}
:deep(.infoWindow){
    background: rgba(1, 18, 52, 0.8);
    padding:5px;
    .projectName{
        font-size:16px;
        white-space: nowrap;
        color:white;
        span{
            color: #ffbc04;
        }
    }
}
</style>

2.Map子组件

<template>
    <div class="AMap">
        <div :id="id" :style="getStyle()" class="map-container"></div>
        <!-- <img class="map-cover" v-if="showCover" src="../assets/images/map-cover.png" alt=""> -->
    </div>
</template>

<script>
import {onBeforeMount, reactive, ref} from 'vue'
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
    name: "AMap",
    props:{
        config:Object
    },
    setup(props,cxt) {
        const showCover = ref(false)
        let map = reactive(null)
        let mass = reactive(null)
        let districtExplorer = reactive(null)
        let currentAreaNode = reactive(null)
        let markers = reactive([])
        let heatmap = reactive(null)
        const id = ref('map_' + String(Math.random()).split('.')[1])
        const scale = ref(2)
        const zoom = ref(3)
        const transform = ref("translate(-50% , -50%) scale(2)")
        const center = ref([106.2203,39.00214])
        const switchConfig = ref([])
        const defaultConfig = ref({
            center:center.value,
            mapStyle:'amap://styles/527e13e12603a649d24cb36aadb097ea',
            zoom:zoom.value,
            resizeEnable: true,
            rotateEnable:false,
            pitchEnable:false,
            zoomEnable: false, //是否允许缩放
            dragEnable:true, //是否允许拖拽
            viewMode:'3D',//开启3D视图,默认为关闭
            buildingAnimation:true,//楼块出现是否带动画
            expandZoomRange:true,
            zooms:[3,20],
        })
        const mapConfig = Object.assign(defaultConfig.value,props.config)
        //创建地图
        const createMap = (id) => {
            window._AMapSecurityConfig = {
                securityJsCode:'77963cbc37bc03014370e4ed3451447f',
            }
            return new Promise((resolve, reject) => {
                if ('AMap' in window) {
                    resolve(new AMap.Map(id, mapConfig))
                } else{
                    AMapLoader.load({
                        key: '043e0e2a9b32576106486e1170f8d18c',
                        version:'1.4.15',
                        AMapUI: {
                            version: '1.1',
                            plugins:['overlay/SimpleMarker','geo/DistrictExplorer']
                        },
                        plugins:['AMap.Scale','AMap.ToolBar','AMap.DistrictSearch','AMap.ImageLayer','AMap.InfoWindow','AMap.DistrictLayer','AMap.LabelsLayer','Map3D',"AMap.Heatmap","AMap.GeoJSON"],
                    }).then((AMap)=>{
                        resolve(new AMap.Map(id, mapConfig))
                    }).catch(e => {
                        reject(e)
                    })
                }
            })
        }
        //删除所有标记
        const removeMarker = () => {
            map.remove(markers)
            markers = []
        }
        //设置标记
        const setMarker = (config,labelConfig,callback) => {
            let marker = new AMap.Marker(config);
            if(labelConfig){
                marker.setLabel(labelConfig)
            }
            if(callback){
                callback(marker,map)
            }
            markers.push(marker)
            map.add(marker)
        }
        //清空地图
        const clear = () => {
            map.clearMap()
        }
        //设置水波图------------------------------------开始-------------------------------------

        //设置水波图-------------------------------------结束------------------------------------

        //自定义窗体---------------------------------------开始---------------------------------
        //构建自定义窗体并打开
        const openInfoWindow = (position,content) => {
            let infoWindow = new AMap.InfoWindow({
                isCustom: true, //使用自定义窗体
                content: content,
                offset: new AMap.Pixel(0, 0),
            })
            infoWindow.open(map, position)
        }

        //关闭窗体
        const closeInfoWindow = () => {
            map.clearInfoWindow()
        }
        //自定义窗体---------------------------------------结束---------------------------------


        //AMap ui设置行政边界------------------------------------开始-------------------------------------
        //加载行政区域
        const loadAreaNode = (adcode, callback) => {
            districtExplorer.loadAreaNode(adcode, function (error, areaNode) {
                if (error) {
                    if (callback) {
                        callback(error);
                    }
                    return;
                }
                if (callback) {
                    callback(null, areaNode);
                }
            });
        }
        const switchAreaNode = (adcode,config,callback) => {
            if(config){
                switchConfig.value = config
            }
            loadAreaNode(adcode, function (error, areaNode) {
                if (error) {
                    if (callback) {
                        callback(error);
                    }
                    return;
                }
                currentAreaNode = areaNode;
                //设置当前使用的定位用节点
                districtExplorer.setAreaNodesForLocating([currentAreaNode]);
                refreshAreaNode(areaNode);
                if(zoom){
                    setZoomAndCenter(zoom)
                }
                if (callback) {
                    callback(null, areaNode);
                }
            });
        }
        //绘制某个区域的边界
        const renderAreaPolygons = (areaNode) => {
            //更新地图视野
            map.setBounds(areaNode.getBounds(), null, null, true);
            //像素平移
            switchConfig.value.map(item=>{
                if (areaNode.adcode === item.adcode) {
                    let zoom = item.zoom
                    let center = item.center ? item.center : null
                    map.setZoomAndCenter(zoom,center)
                }
            })

            districtExplorer.clearFeaturePolygons();
            var lnglatData = [];

            //绘制子区域
            districtExplorer.renderSubFeatures(areaNode, function (feature, i) {
                lnglatData.push(feature.properties);
                return {
                    cursor: "pointer",
                    bubble: true,
                    strokeColor: "#2BE8F6", //线颜色
                    strokeOpacity: 1, //线透明度
                    strokeWeight: 1, //线宽
                    fillColor: "#0061C0", //填充色
                    fillOpacity: 0.7, //填充透明度
                };
            });
            //绘制父区域
            districtExplorer.renderParentFeature(areaNode, {
                cursor: "pointer",
                bubble: true,
                strokeColor: "#D8F6FF", //线颜色
                strokeOpacity: 1, //线透明度
                strokeWeight:2, //线宽
                fillColor: "#0061C0", //填充色
                fillOpacity: 0, //填充透明度
            });

            function toggleHoverFeature(feature, isHover, position) {
                if (!feature) {
                    return;
                }
                var props = feature.properties;
                //更新相关多边形的样式
                var polys = districtExplorer.findFeaturePolygonsByAdcode(props.adcode);
                for (var i = 0, len = polys.length; i < len; i++) {
                    polys[i].setOptions({
                        strokeColor: "#00BAF6", //线颜色
                        strokeOpacity: 1, //线透明度
                        strokeWeight: 1, //线宽
                        fillColor: isHover ? "#07ABD4" : "#0061C0", //填充色
                        fillOpacity: isHover ? 0.8 : 0.7, //填充透明度
                    });
                }
            }
            //移入移出事件
            districtExplorer.on(
                "featureMouseout featureMouseover",
                function (e, feature) {
                    toggleHoverFeature(
                        feature,
                        e.type === "featureMouseover",
                        e.originalEvent ? e.originalEvent.lnglat : null
                    );
                }
            );
            //点击事件
            districtExplorer.on("featureClick", async (e, feature) => {
                const { adcode,center,level, name } = feature.properties;
                cxt.emit('featureClick',{adcode,center,name,level})
            });

            lnglatData.forEach((item) => {
                //创建纯文本标记
                let text = new AMap.Text({
                    text: item.name,
                    anchor: "center", // 设置文本标记锚点
                    draggable: false,
                    // cursor: "pointer",
                    pointer: 'none',
                    zIndex: 0,
                    style: {
                        backgroundColor: "transparent",
                        border: "none",
                        color: "#7df6ec",
                        fontSize: "12px",
                    },
                    position: item.centroid || item.center,
                    map: map,
                });
                text.on('click',()=>{
                    const { adcode,level, name,center } = item;
                    cxt.emit('featureClick',{adcode,level, name,center})
                })
            });
            showCover.value = true
        }
        const refreshAreaNode = (areaNode) => {
            districtExplorer.setHoverFeature(null);
            renderAreaPolygons(areaNode);
        }
        //AMap ui设置行政边界-------------------------------------结束------------------------------------
        const setMassMarks = (data,size = 7) => {
            var style = [ {
                url: 'https://webapi.amap.com/images/mass/mass1.png',
                anchor: new AMap.Pixel(4, 4),
                size: new AMap.Size(size, size),
                zIndex: 2,
            }];
            mass = new AMap.MassMarks(data, {
                opacity: 0.8,
                zIndex: 111,
                cursor: 'pointer',
                style: style
            });
            map.add(mass)
        }
        const setCircleMarker = (center) => {
            var circleMarker = new AMap.CircleMarker({
                center:center,
                radius:10+Math.random()*10,//3D视图下,CircleMarker半径不要超过64px
                strokeColor:'white',
                strokeWeight:2,
                strokeOpacity:0.5,
                fillColor:'rgba(0,0,255,1)',
                fillOpacity:0.5,
                zIndex:10,
                bubble:true,
                cursor:'pointer',
                clickable: true
            })
            map.add(circleMarker)
        }

        //设置热力图
        const setHeatmap = (data,max = 1,config) => {
            heatmap = new AMap.Heatmap(map, Object.assign({
                radius: 10,
                opacity: 1,
                zIndex:1000,
                gradient: {
                    0.1: "RGBA(12, 232, 12, 1)",
                    0.7: "RGBA(194, 44, 30, 1)",
                    1.0: "RGBA(199, 44, 30, 1)",
                },
            },config));
            heatmap.setDataSet({
                data: data,
                max: max,
            });
        }
        //判断时候具有已经渲染的图层
        const has = (coverage) => {
            return eval(coverage)
        }
        //删除图层
        const remove = (arr) => {
            let list = []
            arr.map(item=>{
                if(eval(item)){
                    list.push(eval(item))
                }
            })
            if(list.length){
                map.remove(list);
            }
        }
        //这是缩放比例
        const setZoom = (value) => {
            map.setZoom(value)
        }
        //设置缩放比例和中心点
        const setZoomAndCenter = (zoom,center) => {
            map.setZoomAndCenter(zoom,center)
        }
        const ready = (callback,zoomValue) => {
            createMap(id.value).then(_map=>{
                map = _map
                if(zoom){
                    zoom.value = zoomValue
                }
                window.AMapUI.load(['ui/geo/DistrictExplorer', 'lib/$'], function(DistrictExplorer, $) {
                    //创建一个实例
                    districtExplorer = window.districtExplorer = new DistrictExplorer({
                        eventSupport: true,
                        map: map
                    });
                    if(callback){
                        callback(map)
                    }
                });
            })
        }
        const getStyle = () => {
            return{
                transform:transform.value
            }
        }
        const resize = () => {
            let h = 2160/window.innerHeight
            let w = 3840/window.innerWidth
            if (h > w) {
                transform.value = `translate(-50% , -50%) scale(${h})`
                scale.value = h
            } else {
                transform.value = `translate(-50% , -50%) scale(${w})`
                scale.value = h
            }
        }
        onBeforeMount(()=>{
            resize()
            window.addEventListener("resize", (evt) => {
                resize()
            });
        })
        return {
            id,
            showCover,
            setMarker,
            setHeatmap,
            has,
            remove,
            ready,
            setZoom,
            setZoomAndCenter,
            switchAreaNode,
            getStyle,
            clear,
            setCircleMarker,
            setMassMarks,
            removeMarker,
            openInfoWindow,
            closeInfoWindow,
        }
    }
}
</script>

<style scoped lang="less">
.AMap{
    //为了适配 3840 * 2160 做缩放处理
    height:100%;
    width:100%;
    position: relative;
    overflow: hidden;
    .map-cover{
        position: absolute;
        z-index: 1;
        height:100%;
        width:100%;
        pointer-events: none;
    }
    .map-container{
        height:50%;
        width:50%;
        position: absolute;
        top:50%;
        left:50%;
        transform-origin: 50% 50%;
    }
}
</style>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值