效果图
说明
默认数据没有就是全国地图,
$bus.off("onresize")
是地图容器变化刷新地图适配的,可以你们自己写
getEchartsFontSize
是适配字体大小的,getEchartsFontSize(0.12) === 12
mapScatter
是base64图片就是图上那个标点的底图
GetMapGeoJson
是获取地图json的,这里的是我公司的,可以用阿里云的代替
还有不明白的可以看是之前的文章,echart5.x地图下钻和地图标点(vue3+ts)
// 地图2--阿里云地图
function GetMapGeoJson2(cityCN: string, citylevel: string) {var uploadedDataURL = "";if (citylevel == "china") {//全国地图return "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json";}if (citylevel != "district" && (cityCN + "").substring(4) != "00")citylevel = "district";if (citylevel == "district") {uploadedDataURL ="https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + ".json";} else if (citylevel == "city") {uploadedDataURL ="https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + "_full.json";} else {uploadedDataURL ="https://geo.datav.aliyun.com/areas_v3/bound/" + cityCN + "_full.json";}return uploadedDataURL;
}
使用
<!-- :defaultMap="defaultMap" -->
<mapChart :list="scatterList" @changeMapData="changeMapData" />import mapChart from "@/views/universal-visuali/components/charts/map/mapChart.vue";// 默认的地图数据
let defaultMap = {// prefix: "china",// adcode: "110000",// name: "全国",prefix: "province",adcode: "150000",name: "内蒙古自治区",
};
// 标点
let scatterList = ref<any>([{FarmName: "养殖场一场",Admin: "小王",Livestock: 10000,Address: "江苏省连云港市",Long: 109.494324,Lati: 19.598813,},{FarmName: "向东养殖户",Admin: "向东",Livestock: 0,Address: "长虹科技大厦",Long: 113.964139785699,Lati: 22.544018837551,},{FarmName: "牧养殖种植合作社",Admin: "马胜军",Livestock: 91,Address: "广东省云浮市新兴县",Long: 112.231496832189,Lati: 22.701890082606,},{FarmName: "苏垦牧场",Admin: "小刘",Livestock: 8080,Address: "江苏省连云港连云区农场",Long: 119.43188,Lati: 34.62367,},
]);
const changeMapData = (info: any) => {console.log(info);
};
mapChart 组件代码
<template><div class="cityMap"><div class="backMap" :class="{ notAllowed: !notAllowed }" @click="backMap"><span>返回</span></div><div class="tradeIn-cattle-map" ref="echartsRef"></div></div>
</template><script setup lang="ts">
/*** 省市区-地图下钻*/
import * as echarts from "echarts";
import { ElMessage } from "element-plus";import {ref,onMounted,reactive,Ref,onUnmounted,nextTick,watch,
} from "vue";
import axios from "axios";
import { getEchartsFontSize } from "@/utils/common";
import { mapScatter } from "@/utils/youran";
import $bus from "@/utils/bus";const props = defineProps({list: {type: Array,default: [],},defaultMap: {type: Object,default: {prefix: "china",adcode: "110000",name: "全国",},},
});// 坐标点
let scatterDataList = ref<any>([]);// dom和注册的echart实例
let echartsRef: Ref = ref(null);
let myChart: any = null;
// 没有上一级了,和点击的防抖
let notAllowed = ref<Boolean>(false);
let timeFn: any = null;// 当前激活地图
let defaultMap = ref<any>({prefix: "china",adcode: "110000",name: "全国",
});
if (props.defaultMap) {defaultMap.value = JSON.parse(JSON.stringify(props.defaultMap));
}// 地图栈
let mapStack: any[] = [];// 所有下级地图,下钻用
let AllMap = ref<any[]>([]);// 向外传值
const emit = defineEmits(["changeMapData"]);onMounted(() => {// 如果容器大小变化$bus.on("onresize", () => {initChart();myChart.resize();});initChart();
});onUnmounted(() => {$bus.off("onresize");if (timeFn) {clearTimeout(timeFn);}
});watch(() => props,(val) => {nextTick(() => {mapStack = []if (props.defaultMap) {defaultMap.value = JSON.parse(JSON.stringify(props.defaultMap));}initChart();});},{deep: true,}
);// 获取地图--和域名一样的地图(上线上上去,防跨域)
function GetMapGeoJson(cityCN: string, citylevel: string) {var uploadedDataURL = "";if (citylevel == "china") {//全国地图return "/YooHooMIS/Scripts/echarts/china/100000_full.json";}if (citylevel != "district" && (cityCN + "").substring(4) != "00")citylevel = "district";if (citylevel == "district") {uploadedDataURL ="/YooHooMIS/Scripts/echarts/china/district/" + cityCN + ".json";} else if (citylevel == "city") {uploadedDataURL ="/YooHooMIS/Scripts/echarts/china/city/" + cityCN + "_full.json";} else {uploadedDataURL ="/YooHooMIS/Scripts/echarts/china/province/" + cityCN + "_full.json";}return uploadedDataURL;
}
// 创建地图实例
let initChart = () => {if (!myChart) {myChart = echarts.init(echartsRef.value);}loadMap();
};
// 注册地图
function loadMap() {// 当前地图if (mapStack.length <= 0) {mapStack.push(defaultMap.value);} else {defaultMap.value = mapStack[mapStack.length - 1];}console.log(defaultMap.value, props.defaultMap, mapStack);let mapData = GetMapGeoJson(defaultMap.value.adcode, defaultMap.value.prefix);// 注册当前激活地图axios.get(mapData).then((geoJson: any) => {AllMap.value = geoJson.data.features || [];echarts.registerMap(defaultMap.value.name, geoJson.data);setOption();}).catch((err: any) => {// 接口404没地图数据的情况ElMessage.error(`无${defaultMap.value.name}的地图数据`);mapStack.pop();defaultMap.value = mapStack[mapStack.length - 1];if (mapStack && mapStack.length <= 1) {notAllowed.value = false;}});
}
// 加牧场坐标点
function addScatter() {scatterDataList.value = [];if (props.list && props.list.length > 0) {props.list.forEach((item: any) => {let name = `<div class="CityMapChartTooltipBgBox"><div class="list"><div class="item"><span>${item.FarmName || ""}:</span><span>${item.Livestock || 0}头</span></div><div class="item"><span>负责人:</span><span>${item.Admin || ""}</span></div><div class="item"><span>地址:</span><span>${item.Address || ""}</span></div></div></div>`;scatterDataList.value.push({name: name,value: [item.Long, item.Lati],});});}
}
// 创建地图
function setOption() {addScatter();let option = {tooltip: {show: true,className: "CityMapChartTooltipBg",formatter: (params: any) => {if (params.componentSubType === "scatter") return params.name;},},geo: {show: false,map: defaultMap.value.name || "全国",},series: [{name: "MAP",type: "map",map: defaultMap.value.name || "全国",selectedMode: "false", //是否允许选中多个区域aspectScale: 0.75,zoom: 1.2,zlevel: 1,label: {show: true,textStyle: {color: "#fff",// fontSize: getEchartsFontSize(0.14),fontFamily: "YouSheBiaoTiHei",},},itemStyle: {areaColor: new echarts.graphic.LinearGradient(0, 0, 1, 1, [{offset: 0,color: `#06236d`,},{offset: 1,color: `#1d46a1`,},]),borderColor: "#6789d7",borderWidth: getEchartsFontSize(0.01),shadowColor: "#0156f2",shadowOffsetX: -getEchartsFontSize(0.03),shadowOffsetY: getEchartsFontSize(0.03),shadowBlur: getEchartsFontSize(0.02),emphasis: {show: true,areaColor: "#182e8f", // 鼠标悬浮地图面的颜色borderColor: "#fff",borderWidth: getEchartsFontSize(0.02),label: {show: true,textStyle: {color: "#fff",fontSize: getEchartsFontSize(0.16),fontFamily: "YouSheBiaoTiHei",},},},},data: [],},{type: "scatter",coordinateSystem: "geo",symbol: "image://" + mapScatter,symbolSize: [getEchartsFontSize(0.66), getEchartsFontSize(0.36)],itemStyle: {color: "#1cedd4",shadowBlur: getEchartsFontSize(0.1),shadowColor: "#333",},zlevel: 200,data: scatterDataList.value || [],},],};// 地图数据的关系setOption有时会报错,暂时无解myChart.setOption(option);mapChartAddClick();
}
// 加点击事件
function mapChartAddClick() {// 清空之前的点击事件myChart.off("click");myChart.on("click", (params: any) => {if (timeFn) {clearTimeout(timeFn);}//由于单击事件和双击事件冲突,故单击的响应事件延迟250毫秒执行timeFn = setTimeout(() => {// 现在和点的是一个阻止if (params.name === mapStack[mapStack.length - 1].name) {return;}if (params.seriesType == "scatter") {// 点标点逻辑,传递标点信息emit("changeMapData", props.list[params.dataIndex]);} else {// 地图下钻逻辑if (AllMap.value && AllMap.value.length > 0) {let clickMap = AllMap.value.find((item) => item.properties.name === params.name);if (!clickMap) {ElMessage.warning("无此区域地图显示");return;}mapStack.push({prefix: clickMap.properties.level,adcode: clickMap.properties.adcode,name: clickMap.properties.name,});notAllowed.value = true;loadMap();} else {ElMessage.warning("无下级地图数据");}}}, 250);});// 绑定双击事件,返回// myChart.on("dblclick", (params: any) => {// backMap();// });
}
// 返回上一级
let backMap = () => {// 当双击事件发生时,清除单击事件,仅响应双击事件if (timeFn) {clearTimeout(timeFn);}// 删最后一个,跳上一个if (mapStack && mapStack.length > 1) {mapStack.pop();loadMap();}// 鼠标放上去的禁用状态if (mapStack && mapStack.length <= 1) {notAllowed.value = false;}
};
</script><style lang="less" scoped>
.cityMap {width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;position: relative;.backMap {position: absolute;top: 27px;left: 40px;border: none;z-index: 9;cursor: pointer;// width: 123px;// height: 44px;// background-image: url("../assets/common/top_icon_back_default.png");// background-size: 100% 100%;// padding-left: 50px;// padding-top: 10px;span {display: block;font-size: 12px;// margin-left: 40px;border-radius: 7px;background-color: #1c4fb1;padding: 4px 6px;color: #fff;}&:focus {outline: none;}&:hover {// opacity: 0.93;// background-image: url("../assets/common/top_icon_back_select.png");background-size: 100% 100%;span {color: #ffffff;}}&.notAllowed {cursor: not-allowed;}}.tradeIn-cattle-map {// height: 600px;width: 100%;height: 100%;// margin-top: 50px;}
}
</style>