写在前面:
实现效果图
1.比较重要的部分用红字标出
2.安装echats:
npm install echarts --save
3.由于echarts5版本的已经没有自带地图数据了,所以地图数据需要到专门的GEO数据网站中下载。这里提供一个阿里的下载地址:DataV.GeoAtlas地理小工具系列 对于这个工具网站,有一个重点需要说一下
用阿里的JSON API测试没有问题,但是上正式环境,调用他们的JSON API是要花钱的。
解决办法就是,将地图数据json文件全部下载下来。然后按照100000_full.json这种格式,放到你们自己的服务器就可以了
4.功能说明,本次教程内容基于vue3+ts+echarts 5版本,实现的内容包括,中国地图的下钻到省市区县级、在指定经纬度进行打点标记。并在鼠标浮动时展示该点的信息、通过区域点数量,呈现地图热力图。
接下来,正式开始实现。
第一步:建立地图容器,给上宽高,导入echarts。
<div ref="echartsMap1" style="width: 100%; height: 79%"></div>
import * as echarts from "echarts";
第二步:实现过程中需要的类型文件:
export interface Geodatav {
type: string;
features: Feature[];
}
export interface Feature {
type: FeatureType;
properties: Properties;
geometry: Geometry;
}
export interface Geometry {
type: GeometryType;
coordinates: Array<Array<Array<number[] | number>>>;
}
export enum GeometryType {
MultiPolygon = "MultiPolygon",
Polygon = "Polygon",
}
export interface Properties {
adcode: number | string;
name: string;
center?: number[];
centroid?: number[];
childrenNum?: number;
level?: Level;
parent?: Parent;
subFeatureIndex?: number;
acroutes?: number[];
adchar?: string;
}
export enum Level {
Province = "province",
}
export interface Parent {
adcode: number;
}
export enum FeatureType {
Feature = "Feature",
}
// 城市属性
export interface citymodel {
name: string,
adcode: number | string,
url: string,
childrenNum: number | undefined,
center?: number[],
parentadcode?: number | string, // 父地图
hasRegister: boolean // 是否已经注册在echarts
}
第三步:写一个简单的工具,实现将阿里中国地图城市数据集合JSON数据引入项目中并使用。
// 引入type
import { Feature, Geodatav, citymodel } from "./geodatav";
// 获取当前json下的省份城市区域adcode和json
// 根据城市adcode
function getCurrentadcode(mapdata: Geodatav) {
let currentMap = new Map();
mapdata.features.map((item:Feature)=>{
if (item.properties.name != '') {
let cityinfo: citymodel = {
name: item.properties.name,
adcode: item.properties.adcode,
childrenNum: item.properties.childrenNum,
url: `https://geo.datav.aliyun.com/areas_v3/bound/${item.properties.adcode}_full.json`,
center: item.properties.center,
parentadcode: item.properties.parent?.adcode,
hasRegister: false
}
currentMap.set(cityinfo.adcode, cityinfo);
}
})
return currentMap;
}
// 根据城市名称name
function getCurrentadcodebyname(mapdata: Geodatav) {
let currentMap = new Map();
mapdata.features.map((item:Feature)=>{
if (item.properties.name != '') {
let cityinfo: citymodel = {
name: item.properties.name,
adcode: item.properties.adcode,
childrenNum: item.properties.childrenNum,
url: `https://geo.datav.aliyun.com/areas_v3/bound/${item.properties.adcode}_full.json`,
center: item.properties.center,
parentadcode: item.properties.parent?.adcode,
hasRegister: false
}
currentMap.set(cityinfo.name, cityinfo);
}
})
return currentMap;
}
export { getCurrentadcode, getCurrentadcodebyname }
注意,在这里,如果你采用将地图数据放在自己的服务器,讲JSON数据下载下来,替换地址即可
第四步:开始渲染地图
首先引入2个工具文件
import * as echarts from "echarts";
import { getCurrentadcode } from "./utils/getAllChineseCity";
import { citymodel } from "./utils/geodatav";
定义地图
const echartsMap1: any = ref(null);
// 定义当前所有的地图
let allMap: Map<string | number, citymodel> = new Map();
// 当前地图
let currentMap: Ref<null | citymodel> = ref(null);
// echarts实例
let myChart: any,
currentadcode: Ref<number | string> = ref(100000);
在onMounted中初始化中国地图
onMounted(async () => {
allMap.set(100000, {
name: "中国",
adcode: 100000,
url: "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json",
childrenNum: 34,
center: [0, 0],
hasRegister: false, // 是否已经注册在echarts
});
currentMap.value = allMap.get(currentadcode.value) as citymodel;
myChart = echarts.init(echartsMap1.value);
renderChart(currentMap.value, data, dataMap);
// 图表跟随屏幕自适应
window.addEventListener("resize", () => {
myChart.resize();
});
// 地图点击事件
myChart.on("click", (params: any) => {
let n = getMapKey(params.name, allMap);
if (allMap.get(n)?.childrenNum == 0) return;
(currentadcode.value as number | string) = n;
});
});
// 根据map中数值,获取key
const getMapKey = (
value: string,
map: Map<string | number, citymodel>
): number | string => {
let arriterator = map.values(),
res: number | string = 0;
for (const iterator of arriterator) {
if (iterator.name == value) {
res = iterator.adcode;
break;
}
}
console.log(res);
return res;
};
其中data,dataMap为我传入地图中需要渲染的数据。你们可以自信传入你们需要展示的数据。
第五步:监听currentadcode的变化,更新地图
// 监听currentadcode地图值
watch(currentadcode, async (newval, oldval) => {
let nextMap = allMap.get(newval) as citymodel;
// 如果存在子节点
if (nextMap?.childrenNum && nextMap.childrenNum > 0) {
currentMap.value = nextMap;
// 如果出现意外,没呀父节点
if (currentMap.value.parentadcode == undefined) {
currentMap.value.parentadcode = oldval;
}
console.log("nextMap: ", nextMap);
if (nextMap.adcode != 100000) {
query.code = nextMap.adcode;
queryData.code = nextMap.adcode;
} else {
delete query.code;
queryData.code = "";
}
const data = await getDeptList();
const dataMap = await getDeptHotMap();
renderChart(nextMap, data, dataMap);
}
});
绘制地图函数:
// 获取地图json, 绘制地图
const renderChart = async (cMap: citymodel | null, dataArr, dataMap) => {
// myChart.showLoading(); // 加载动画
// 访问当前的地图数据
let { data: mapdata } = await axios.get(cMap?.url as any);
let currentName = cMap?.name;
// 判断是否注册过
if (!cMap?.hasRegister) {
echarts.registerMap(currentName as any, mapdata);
// 当前地图下的地区信息
let currentCityMap: Map<string | number, citymodel> =
getCurrentadcode(mapdata);
allMap = new Map([...allMap, ...currentCityMap]);
(allMap.get(cMap?.adcode as string | number) as citymodel).hasRegister =
true;
}
let option = {
tooltip: {
position: "right",
color: "#F7C034",
formatter(d: any) {
console.log(d);
return `<div style="padding: 5px 10px;">${d.name}</div>`;
},
},
title: {
text: `${currentName}地图`,
left: "center",
top: "2%",
textStyle: {
color: "#fff",
},
},
//热力图配置
visualMap: {
left: "left",
orient: "vertical",
itemWidth: 10,
min: 0,
max: 1000,
align: "center",
bottom: "10%",
inRange: {
color: [
"#313695",
"#4575b4",
"#74add1",
"#abd9e9",
"#e0f3f8",
"#ffffbf",
"#fee090",
"#fdae61",
"#f46d43",
"#d73027",
"#a50026",
],
},
calculable: true,
},
//层级地图配置
series: [
{
name: `${currentName}地图`,
map: currentName,
type: "map",
roam: true,
label: {
normal: {
formatter(d: any) {
return `${d.name}`;
},
show: true,
textStyle: {
color: "#fff",
},
},
emphasis: {
show: true,
textStyle: {
color: "#05C3F9",
},
},
},
itemStyle: {
normal: {
areaColor: "#3D8CFD",
borderColor: "#5EC9F9",
borderWidth: 1,
},
emphasis: {
areaColor: "#0C356C",
shadowColor: "#1773c3",
shadowBlur: 20,
},
},
markPoint: {
symbol: "circle",
itemStyle: {
color: "#F7C034",
// borderColor:'#000'
},
label: {
normal: {
show: true,
},
emphasis: {
show: true,
},
},
data: dataArr,
blur: {},
},
data: dataMap,
},
],
};
myChart.clear();
myChart.setOption(option, true);
};
最后,返回上级地图方法:
// 返回上级地图
const returnLastMap = (adcode: any) => {
currentadcode.value = adcode;
};