vue中使用Echarts地理地图并结合高德地图实现一个国、省、市、区的地图下钻功能

vue中使用Echarts地理地图并结合高德地图实现一个国、省、市、区的地图下钻功能

  • 一、需求:按不同的层级展示不同的内容
    • 1.中国地图
    • 2.省级地图
    • 3.市级地图
    • 4.县和区以下的地图
  • 二、开发
    • 1. Echarts和地图容器的设置
      • 相关代码
    • 2. Echarts绘制
      • 相关代码
    • 2.Map绘制
      • 相关代码
  • 三、演示

一、需求:按不同的层级展示不同的内容

先放个UI图,这是要期望达到的效果

1.中国地图

点击带黄圈的深色区域可以进入对应的省份

2.省级地图

点击带黄圈的深色区域可以进入对应的地级市;点击返回上级可以回到中国地图
vue中使用Echarts地理地图并结合高德地图实现一个国、省、市、区的地图下钻功能_第1张图片

3.市级地图

点击带黄圈的深色区域可以进入对应的县区;点击返回上级可以回到市级
(注:右下角对应展示市级相关内容)
vue中使用Echarts地理地图并结合高德地图实现一个国、省、市、区的地图下钻功能_第2张图片

4.县和区以下的地图

高德地图展示对应设备具体位置及信息;点击返回上级可以回到县级
(注:此处高德地图点标记的添加可以看我之前我文章)

二、开发

重点来了!!!

1. Echarts和地图容器的设置

定义两个容器分别放置Echarts图表和高德地图
这里有个坑:我是通过控制display属性来控制这两个容器的显隐!!
那么为什么不用v-show和v-if呢?
1.v-show:Echarts图表在初始化过程中宽度会丢失,默认成为100px,这个我搜索过,碰到这问题的人很多
2.v-if:地图在加载以后无法隐藏,也就是实现不了返回上级的功能

相关代码

<template>
    <div class="all-container">
<!--        背景地图-->
        <div :style="`display: ${mapDisplay}`" class="map-container" id="Map"></div>
        <div :style="`display: ${chartDisplay}`" class="equ-EchartContainer" ref="myEchart" id="myCharts"></div>
    <div class="all-container">
<template>

2.script

data(){
	return {
		mapDisplay:'none',
		chartDisplay:'block',
	}
}

3.style

.all-container{
    position: relative;
    &::after { //伪元素添加背景图,可以控制背景图透明度
        content: "";
        display: inline-block;
        position: absolute;
        z-index: 0; //显示层级
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #f1f5fa url("../../../assets/img/equ/equ-map-bg.png") 63% 50% no-repeat;
        background-size: 720px;
        opacity: 0.5;
    }
}
.map-container{
    width: 100%;
    height: 825px;
    min-height: calc(100vh - 134px) !important;
    z-index: 1;
    /deep/.amap-info-content{ //修改高德地图组件默认样式
        padding: 0px;
        box-shadow: 0 0 6px 0 rgba(0,28,71,0.2);
    }
    /deep/.amap-info-close{
        display: none;
    }
}
.equ-EchartContainer {
    width: 100%;
    height: 825px;
    margin-left: 340px;
    min-height: calc(100vh - 134px) !important;
    z-index: 1;
}

2. Echarts绘制

相关代码

1.数据获取,以及相关数据格式定义

this.$axios.get('你自己获取数据的API').then(res => {
	if (res.code === 0 && res.data) {
		this.adCode = res.data.adCode //地图显示层级的行政区码,如当前为全国则传100000,浙江省传330000,杭州市...
		res.data.forEach((item) => {
			this.mapData.push({ //地图相关省、市、区数据
				'name': item.name, //城市名称
				'value':item.num, //相关设备数量(黄圈内的数字)
				'cityCode': item.adCode //行政区码
			})
			this.pointData.push({
				'name': item.name,
				'value':[item.lng,item.lat,item.num], //黄圈的经纬度及数字,这里也可以不传经纬度,在后续高德UI插件查询后可以加入
				'cityCode': item.adCode
			})
		})
	}
}).finally(()=>{
	if(!this.adCode){
		this.myEchart.showLoading(echartLoadingOptions); //E charts添加loading效果,可以去掉
		this.init(100000)
	}else {
		this.myEchart.showLoading(echartLoadingOptions);
		this.init(this.adCode)
	}
})

2.script相关代码

这里有个很大的坑,我找了好久也没找到一个合适的引入高德查询API的方法!!
此处引入方法load UI组件:

return new Promise((resolve, reject) => {
	AMapLoader.load({}}).then(() =>{
		new AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
			var districtExplorer = new DistrictExplorer();
			districtExplorer.loadAreaNode(adcode, function (error, areaNode) {})
		})
	})
})

绘制:

import echarts from "echarts";

export default {
    data() {
        return {
            option:null,
            myEchart:null,
            geoJson: {},
        }
    },
    mounted() {
        let myCharts = document.getElementById("myCharts");
        myCharts.style.width = window.innerWidth-480 + "px";  //初始化echarts图表宽度
        this.myEchart = echarts.init(this.$refs.myEchart);
        window.addEventListener("resize", this.handleResize);//根据窗口大小动态适配图表大小
    },
    beforeDestroy() {
        this.myEchart.clear(); //销毁
        window.removeEventListener("resize", this.handleResize);
    },
    methods:{
    	//宽度适配
        handleResize() {
            let _this1 = this.myEchart;
            if (this.resizeTimer) {
                clearTimeout(this.resizeTimer);
            }
            this.resizeTimer = setTimeout(function () {
                let myCharts = document.getElementById("myCharts");
                myCharts.style.width = window.innerWidth-480 + "px";
                _this1.resize();
            }, 100);
        },
        //echarts图表绘制,传入显示层级的adcode
        init(adcode){
            this.getGeoJson(adcode).then(data => {
                this.geoJson = data
                this.initEchartMap(this.mapData, this.pointData)
            })
        },
        //封装了高德地图AMapUI的行政区查询插件,传入显示层级的adcode,获取下属的行政区相关信息
        getGeoJson(adcode, childAdcode = '') {
            let _this = this;
            return new Promise((resolve, reject) => {
                AMapLoader.load({
                    "key": "申请好的Web端开发者Key", // 必填
                    "version": "1.4.15",
                    "AMapUI": {             // 是否加载 AMapUI,缺省不加载
                        "version": '1.1',   // AMapUI 缺省 1.1
                        "plugins":['geo/DistrictExplorer'],       // 需要加载的 AMapUI ui插件
                    }
                }).then(() =>{
                    new AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
                        var districtExplorer = new DistrictExplorer();
                        districtExplorer.loadAreaNode(adcode, function (error, areaNode) {
                            if (error) {
                                console.error(error);
                                reject(error);
                                return;
                            }
                            let Json = areaNode.getSubFeatures();
                            //console.log(_this.equRegisters)
                            //此处判断是否到达区级以下
                            if (Json.length === 0) {
                                let parent = areaNode._data.geoData.parent.properties.acroutes;
                                _this.myEchart.clear();
                                _this.mapDisplay = 'block' //显示高德地图容器
                                _this.chartDisplay = 'none' //隐藏图表
                                _this.initMap() //绘制高德地图
                                return;
                            }
                            if (childAdcode) {
                                Json = Json.filter(item => {
                                    return item.properties.adcode == childAdcode;
                                });
                            }
                            let mapJson = {
                                features: Json
                            };
                            //返回查询到的相关的行政区信息
                            resolve(mapJson);
                        });
                    });
                })
            })
        },
        //渲染echarts
        initEchartMap(mapData, pointData) {
        	//这里是绘制的重点,传入地图的格式以及行政区信息
            echarts.registerMap(this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国' ? 'china' : 'map', this.geoJson);
			//传入E charts图表相关数据,存入this.option中
            this.option = this.getOption(mapData,pointData);
            //loading加载用到,可以直接setOptio()
            if (this.isValidOption(this.option)) {
                this.myEchart.clear();
                this.myEchart.setOption(this.option, true)
                setTimeout(()=>{
                    this.myEchart.hideLoading();
                },100)
            }
            //点击前解绑,防止点击事件触发多次
            this.myEchart.off('click');
            this.myEchart.on('click', this.echartsMapClick);
        },
        //loading加载用到,判断
        isValidOption(option) {
            return (
                this.isObject(option) &&
                !this.isEmptyObject(option) &&
                this.hasSeriesKey(option)
            );
        },
        //loading加载用到,判断
        isObject(option) {
            return Object.prototype.isPrototypeOf(option);
        },
        //loading加载用到,判断
        isEmptyObject(option) {
            return Object.keys(option).length === 0;
        },
        //loading加载用到,判断
        hasSeriesKey(option) {
            return !!option["series"];
        },
        //echarts图表数据转换,传入地图省市数据和圆点数据
        getOption(mapData,pointData) {
            return {
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'shadow'
                    },
                },
                //地理地图绘制
                geo: {
                    map: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? 'china' : 'map',
                    zoom: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? 1.3 : 1,
                    //aspectScale: 0.75, //长宽比
                    roam: true,// 拖拽
                    top: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? '17%' : '11%',
                    left:'15%',
                    scaleLimit:{ //缩放层级控制
                        min: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? 1.3 : 1,
                        max: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? 1.3 : 1,
                    },
                    label: {
                        normal: {
                            show: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国'? false : true,
                            color: "rgb(249, 249, 249)", //省份标签字体颜色
                            formatter: p => {
                                switch (p.name) {
                                    case '内蒙古自治区':
                                        p.name = "内蒙古"
                                        break;
                                    case '西藏自治区':
                                        p.name = "西藏"
                                        break;
                                    case '新疆维吾尔自治区':
                                        p.name = "新疆"
                                        break;
                                    case '宁夏回族自治区':
                                        p.name = "宁夏"
                                        break;
                                    case '广西壮族自治区':
                                        p.name = "广西"
                                        break;
                                    case '香港特别行政区':
                                        p.name = "香港"
                                        break;
                                    case '澳门特别行政区':
                                        p.name = "澳门"
                                        break;
                                }
                                return p.name;
                            }
                        },
                        emphasis: {
                            show: true,
                            color: '#8dd7fc',
                        }
                    },
                    itemStyle: {
                        normal: {
                            areaColor: {
                                type: 'linear',
                                x: 0,
                                y: 0,
                                x2: 0,
                                y2: 1,
                                colorStops: [{
                                    offset: 0, color: '#e9f5ff' // 0% 处的颜色
                                }, {
                                    offset: 1, color: '#c2e5ff' // 100% 处的颜色
                                }],
                                global: false // 缺省为 false
                            },
                            borderColor: '#7abfff',
                            borderWidth: 1,
                            /*shadowBlur: 1,
                            shadowColor: '#cbcaca',
                            shadowOffsetX: 10,
                            shadowOffsetY: 5,*/
                        },
                        emphasis: {
                            areaColor: '#e9f5ff',
                            borderWidth: 1.6,
                            shadowBlur: 0,
                        }
                    },
                    regions: [
                        {
                            name: "南海诸岛",
                            itemStyle: {
                                // 隐藏南海诸岛地图
                                normal: {
                                    opacity: 0, // 为 0 时不绘制该图形
                                }
                            },
                            label: {
                                show: false // 隐藏文字
                            }
                        }
                    ],
                },
                //地图的渐变色层次区分
                visualMap: {
                    min: 0,
                    max: 100000,
                    show: false,
                    right: '3%',
                    bottom: '5%',
                    calculable: true,
                    type: "piecewise",
                    realtime: false,
                    seriesIndex: [0],
                    inRange: {
                        color: ['#e9f5ff', '#c2e5ff', '#1E62AC','#467bc0']
                    },
                    pieces: [{
                        min: 0,
                        max: 0,
                        label: '0',
                        color: {
                            type: 'linear',
                            x: 0,
                            y: 0,
                            x2: 0,
                            y2: 1,
                            colorStops: [
                                {
                                    offset: 0,
                                    color: '#e9f5ff'
                                },
                                {
                                    offset: 1,
                                    color: '#c2e5ff'
                                }],
                            globalCoord: false // 缺省为 false
                        }
                    }, {
                        min: 1,
                        max: 100,
                        label: '<100',
                        color: {
                            type: 'linear',
                            x: 0,
                            y: 0,
                            x2: 0,
                            y2: 1,
                            colorStops: [
                                {
                                    offset: 0,
                                    color: '#83c4ff'
                                },
                                {
                                    offset: 1,
                                    color: '#2895ff'
                                }],
                            globalCoord: false // 缺省为 false
                        }
                    }, {
                        min: 100,
                        max: null,
                        label: '>100',
                        color: {
                            type: 'linear',
                            x: 0,
                            y: 0,
                            x2: 0,
                            y2: 1,
                            colorStops: [{
                                offset: 0,
                                color: '#89adff' // 0% 处的颜色
                            },{
                                offset: 1,
                                color: '#2f65d5' // 100% 处的颜色
                            }],
                            globalCoord: false // 缺省为 false
                        }
                    }],
                    textStyle: {
                        color: '#24CFF4'
                    }
                },
                series: [{
                    type: 'map',
                    geoIndex: 0,
                    map: this.parentInfo.length === 1 && this.parentInfo[0].cityName === '全国' ? 'china' : 'map',
                    roam: true,
                    zoom: 1.3,
                    showLegendSymbol: false, // 存在legend时显示
                    label: {
                        normal: {
                            show: false,
                        },
                        emphasis: {
                            show: false,
                        }
                    },
                    data: mapData,

                }, {
                    name: '散点',
                    type: 'effectScatter',
                    coordinateSystem: 'geo',
                    rippleEffect: {
                        brushType: 'fill'
                    },
                    hoverAnimation: true,
                    itemStyle: {
                        normal: {
                            color: '#ff8400',
                            shadowBlur: 0,
                            shadowColor: '#333333'
                        }
                    },
                    symbolSize: function (val) {
                        let value = val[2];
                        if (value > 100) {
                            return 27
                        }
                        return 18
                    },
                    showEffectOn: 'render', //加载完毕显示特效
                    normal: {
                        show: true,
                        color: '#fff',
                        fontWeight: 'bold',
                        position: 'inside',
                        rich: {
                            cnNum: {
                                fontSize: 13,
                                color: '#D4EEFF',
                            }
                        }
                    },
                    label: {
                        normal: {
                            show: true, //黄圈内添加数字
                            color: '#ff8400',
                            fontWeight: 'bold',
                            position: 'inside',
                            formatter: function (para) {
                                return '{cnNum|' + para.data.value[2] + '}'
                            },
                            rich: {
                                cnNum: {
                                    fontSize: 13,
                                    color: '#D4EEFF',
                                }
                            }
                        },
                    },
                    data: pointData,
                },
                ]
            }
        },

        //echarts点击有数据的省份或市,可以下钻
        echartsMapClick(params) {
            //console.log(params)
            if (!params.data) {
                return
            } else {
                //如果当前是最后一级,那就直接return
                if (this.parentInfo[this.parentInfo.length - 1].code == params.data.cityCode) {
                    return
                }
                let data = params.data
                this.parentInfo.push({
                    cityName: data.name,
                    code: data.cityCode
                })
                this.getEquCount(data.cityCode) //这是我封装的获取数据的方法
            }
        },
        returnHome(){
        	//因为最后一层肯定是高德地图,因此点击返回按钮,重新设置一下display属性,就能隐藏高德地图,显示E charts地图了,也不会影响echarts图表之间的层级切换
            this.mapDisplay = 'none' 
            this.chartDisplay = 'block'

            if (this.parentInfo.length === 1) {
                return;
            }
            this.parentInfo.pop()
            if(this.parentInfo[this.parentInfo.length - 1].cityName === '全国'){
                this.getEquCount()
            }else {
                this.getEquCount(this.parentInfo[this.parentInfo.length - 1].code)
            }

        }
    },
}

2.Map绘制

定义

相关代码

1.获取数据

this.$axios.get('你自己获取数据的API').then(res => {
	if (res.code === 0 && res.data) {
		this.equRegisters = res.data.equRegisters
	}
})

2.绘制高德地图

import AMapLoader from '@amap/amap-jsapi-loader';
import { echartLoadingOptions } from "@/utils/constant";
export default {
    data() {
        return {
            option:null,
            equRegisters:[],
        }
    },
    methods:{
    	//地图
        initMap() {
        	//这里用了封装好的地图加载函数,不清楚的可以看我之前的文章
            this.$mapUtil.loadMap().then(AMap => {
                this.map = new AMap.Map('Map', {
                    mapStyle: this.$mapUtil.mapStyle,
                    zooms: [9, 18],
                    zoom: 10,
                    viewMode: "2D",
                    resizeEnable: true,
                    center: [104, 40],
                });
                //关联设备对应的图标
                this.addMarkerDetail()
            }).catch(() => {
                console.log('地图加载失败!')
            })
        },
	},
    //关联设备对应的图标
   addMarkerDetail() {
       let _this = this;
       //标记点的图标自定义
       var markers = [{icon: require('../../../assets/img/equ/map-pcw-4.png')},{icon: require('../../../assets/img/equ/map-pcw-5.png')}],
       ],allMarkers=[];
       //这个是我相关的地图数据,也是后端返回的
       if (this.equRegisters && this.equRegisters.length > 0) {
           var infoWindow = new AMap.InfoWindow({
               offset: new AMap.Pixel(-19, -40),
               content: _this.$refs.equMarkerContent.$el
           });
           //地图加入对应关联设备类型的标记点
           for (let a = 0, y, x; a < this.equRegisters.length; a++) {
               x = this.getDetectorType(this.equRegisters[a].productName);
               y = this.changeStatus(this.equRegisters[a].status);
               if (this.equRegisters[a].longitude && this.equRegisters[a].latitude) {
                   var markerType = new AMap.Marker({
                       icon: new AMap.Icon({
                           image: markers[x][y].icon,
                           imageSize: new AMap.Size(34, 40),
                           size: new AMap.Size(34, 40),
                       }),
                       position: [this.equRegisters[a].longitude, this.equRegisters[a].latitude],
                       offset: new AMap.Pixel(-35, -35),
                       //下面保存的是聚合点内想展示的数据,我没找到clusterData这个数据段的用法,暂时用这个我自定义的方法代替
                       productName: this.equRegisters[a].productName,
                       name: this.equRegisters[a].name,
                       status: this.equRegisters[a].status,
                       seqNo: this.equRegisters[a].seqNo,
                       model: this.equRegisters[a].model,
                       id: this.equRegisters[a].id,
                   });
                   //打开设备标记点窗体信息
                   function onClearMarker(e) {
                       infoWindow.open(_this.map, e.target.getPosition());
                       _this.nowSelectedMarker = _this.equRegisters[a]
                   }

                   markerType.on('click', onClearMarker);
                   /*markerType.on('mouseout', e => {
                       _this.map.clearInfoWindow();
                   });*/
                   _this.map.add(markerType)

                   //聚合点合集
                   allMarkers.push(markerType);
               }
           }
           _this.map.setFitView(allMarkers)

           var _infoWindow = new AMap.InfoWindow({
               offset: new AMap.Pixel(0, -35),
               //挂载信息窗体的组件
               content: _this.$refs.equClusterContent.$el
           });
           //打开设备标记点窗体信息

           AMap.plugin(['AMap.MarkerClusterer'], () => {
               var cluster = new AMap.MarkerClusterer(_this.map, allMarkers, {
                   gridSize: 80,
                   //zoomOnClick:false, //聚合点点击控制,可以看官方开发文档
               });
               //信息窗体显隐控制
               cluster.on('click', clusterCallback);
           })
           function clusterCallback(e) {
               _this.nowClusterType = [];
               e.markers.forEach((item) => {
                   _this.nowClusterType.push({
                       'productName':item.w.productName,
                       'name':item.w.name,
                       'status':item.w.status,
                       'seqNo':item.w.seqNo,
                       'model':item.w.model,
                       'id':item.w.id,
                   })
               })
               var mapZoom = _this.map.getZoom(); //获取当前地图级别
               if(mapZoom === 18){
                   _infoWindow.open(_this.map, [e.lnglat.lng,e.lnglat.lat]);
               }
           }
           //层级变换,清空窗体信息
           var logMapChange = function (){
               //var mapZoom = _this.map.getZoom(); //获取当前地图级别
               _this.map.clearInfoWindow();
           };
           _this.map.on('zoomchange', logMapChange);
       }
   },
   closeInfo(){
       let _this = this;
       _this.map.clearInfoWindow();
   },
}

3.信息窗体添加
(1)主文件内写入

<div style="display: none">
	//标记点信息窗体
	<markerContent @closeInfo="closeInfo" ref="equMarkerContent" :marker="nowSelectedMarker"></markerContent>
	//聚合点信息窗体
	<clusterContent @closeInfo="closeInfo" ref="equClusterContent" :cluster="nowClusterType"></clusterContent>
</div>
<script>
import markerContent from "./markerContent";
import clusterContent from "./clusterContent";
import equEchartMix from "@/components/device/equhome/equEchartMix";
	export default {
    	name:'equMap',
    	components:{markerContent,clusterContent},
    	mixins: [equEchartMix],
    }
</script>

(2)标记点信息窗体(聚合点类似)
主要在于js代码里:

<template>
	<div @click="closeInfo" class="close-icon">
		<svg-icon class="info-svg" icon-class="equ-close"/>
	 </div>
</template>
<script>
export default {
    name:'markerContent',
    props:{
        marker:{}
    },
    methods:{
        closeInfo() {
            //父子传递函数信息,关闭窗体
            this.$emit('closeInfo');
        },
	}
}
</script>

三、演示

链接: http://m.youku.com/v_show/id_XNTEzMTc1ODIzMg==.html?pgcpgcid=UNjExNzkxMDQyNA%3D%3D&sharekey=d65f62f5b1297526bf7eb2e1e139bf024 .

你可能感兴趣的:(vue,javascript,css)