先放个UI图,这是要期望达到的效果
点击带黄圈的深色区域可以进入对应的省份
点击带黄圈的深色区域可以进入对应的地级市;点击返回上级可以回到中国地图
点击带黄圈的深色区域可以进入对应的县区;点击返回上级可以回到市级
(注:右下角对应展示市级相关内容)
高德地图展示对应设备具体位置及信息;点击返回上级可以回到县级
(注:此处高德地图点标记的添加可以看我之前我文章)
重点来了!!!
定义两个容器分别放置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;
}
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)
}
}
},
}
定义
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 .