如何使用ECharts绘制中国地图(结合CDN和阿里地图免下载JSON版)
使用ECharts绘制中国地图是常见需求,今天就给大家分享一种利用CDN和阿里地图资源来实现的方法,而且无需下载JSON文件,方便又高效。
一、基础设置:防止403错误
在项目的index.html
文件里,添加下面这行代码,它的作用是防止出现403错误:
<meta name="referrer" content="no-referrer" />
这行代码设置了页面的引用策略,避免在请求资源时因引用问题导致403错误,为后续顺利加载地图资源做好准备。
二、数据与图表初始化
接下来,要对数据赋值,同时初始化图表和配置项option
。这里以初始化全国地图配置为例:
// 初始化绘制全国地图配置 option: { backgroundColor: "transparent", // 设置背景色透明 // 必须设置 tooltip: { show: false }, // 地图阴影配置 }
在这段代码中,设置了地图的背景为透明,并且暂时隐藏了提示框tooltip
。大家可以根据实际需求,对这些初始配置进行调整。
三、挂载阶段:初始化地图相关操作
在mounted
钩子函数中,主要进行地图初始化、获取地图以及获取图表的操作:
mounted() { this.initMap(); this.getMap(); this.myChart = window.echarts.init(document.getElementById("centerMap")); }
initMap()
和getMap()
是自定义的方法,分别用于初始化地图数据和获取地图资源。window.echarts.init(document.getElementById("centerMap"))
则是使用ECharts的init
方法,通过传入对应的DOM元素ID,来初始化一个ECharts图表实例。
四、初始化地图:获取数据并绘制
initMap
函数主要负责从阿里地图获取数据,注册地图,绘制地图并绑定点击事件:
async initMap() { document.getElementById("back").style.display = "none"; await axios .get(`https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json`) .then((res) => { // 获取所有省份 let shengAll = this.getChildMap(res.data); // 注册大地图 window.echarts.registerMap("china", res.data); // 绘制地图 this.renderMap("china", shengAll); // 绑定点击地图区域事件 this.myChart.on("click", this.clickMap); }); }
这里通过axios.get
从阿里云的地图数据接口获取中国地图的JSON数据。拿到数据后,先调用getChildMap
方法处理数据,获取所有省份信息。接着使用window.echarts.registerMap
注册地图,renderMap
方法绘制地图,最后绑定点击事件clickMap
,方便后续实现点击地图的交互功能。
五、点击地图:切换地图层级
点击地图后,要根据点击的区域判断地图类型,并显示相应层级的地图:
clickMap(params) { document.getElementById("back").style.display = "block"; const name = params.name; const adcode = this.getAdcodeFromGeoJSON(name); const geoLevel = this.getAdcodeFromGeoLevel(name); if (geoLevel == "province" || geoLevel == "city") { if (name == "台湾省") { this.$message.warning("已经是最后一层地图了"); } else { axios .get(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`) .then((res) => { // 注册省级地图 window.echarts.registerMap(params.name, res.data); // 获取当前省下所有市 let shiAll = this.getChildMap(res.data); this.renderMap(params.name, shiAll); }); } } else { this.$message.warning("没有更小的地图了"); // this.renderMap("china"); } }
这段代码中,先获取点击区域的名称name
,再通过getAdcodeFromGeoJSON
和getAdcodeFromGeoLevel
方法获取对应的行政区划代码adcode
和地图层级geoLevel
。如果点击的是省份或城市,且不是台湾省,就获取该区域的详细地图数据,注册地图并绘制;如果点击的区域没有更小层级的地图,则给出提示。
六、辅助方法:获取信息
(一)获取adcode和地图类型
getAdcodeFromGeoJSON
方法用于从GeoJSON数据中获取adcode
:
getAdcodeFromGeoJSON(name) { const geoJSON = window.echarts.getMap(this.option.geo.map).geoJSON; for (let feature of geoJSON.features) { if (feature.properties.name === name) { return feature.properties.adcode; } } return null; }
这个方法通过遍历当前地图的GeoJSON数据,找到与点击名称匹配的区域,返回其adcode
,找不到则返回null
。
getAdcodeFromGeoLevel
方法用于获取地图类型:
getAdcodeFromGeoLevel(name) { const geoLevel = window.echarts.getMap(this.option.geo.map).geoJSON; for (let feature of geoLevel.features) { if (feature.properties.name === name) { return feature.properties.level; } } return null; }
该方法与上面类似,只不过返回的是匹配区域的地图层级信息。
(二)获取下级所有地名
getChildMap
方法用于获取下级所有地名:
getChildMap(data) { let childMapAll = []; // value为鼠标悬停地名显示的数据 for (var i = 0; i < data.features.length; i++) { childMapAll.push({ name: data.features[i].properties.name, value: 0 }); } return childMapAll; }
这个方法遍历传入的地图数据,将每个区域的名称和初始值0
组成对象,添加到数组中,最后返回包含所有下级地名的数组。
七、渲染地图:配置与更新
renderMap
方法用于修改ECharts配置并重新渲染地图,实现地图的缩放、拖动等功能:
renderMap(map, data) { // 标题 this.option.geo = { map: map, // 这里必须定义,不然后面series里面不生效 tooltip: { show: false }, label: { show: false }, zoom: 1.03, silent: true, // 不响应鼠标时间 show: true, roam: false, // 地图缩放和平移 aspectScale: 0.75, layoutSize: "108%", itemStyle: { normal: { borderColor: "rgba(147, 235, 248, 1)", borderWidth: 0.5, color: { type: "linear-gradient", x: 0, y: 1500, x2: 2500, y2: 0, colorStops: [ { offset: 0, color: "#009DA1" // 0% 处的颜色 }, { offset: 1, color: "#005B9E" // 50% 处的颜色 } ], global: true // 缺省为 false }, opacity: 0.5 }, emphasis: { areaColor: "#2a333d" } }, // 地图区域的多边形 图形样式 阴影效果 // z值小的图形会被z值大的图形覆盖 top: "18%", left: "center", // 去除南海诸岛阴影 series map里面没有此属性 regions: [ { name: "南海诸岛", selected: false, emphasis: { disabled: true }, itemStyle: { areaColor: "#00000000", borderColor: "#00000000" } } ], z: 1 }; this.option.series = [ // 地图配置 { type: "map", map: map, zoom: 1, tooltip: { show: false }, label: { show: true, // 显示省份名称 color: "#04CFF5", align: "center" }, top: "18%", left: "center", aspectScale: 0.75, layoutSize: "108%", roam: false, // 地图缩放和平移 itemStyle: { borderColor: "#0FA3F0", // 省分界线颜色 阴影效果的 borderWidth: 1, areaColor: "#065CAE", opacity: 1 }, // 去除选中状态 select: { disabled: true }, emphasis: { // 聚焦后颜色 disabled: false, // 开启高亮 label: { align: "center", color: "#04CFF5" }, itemStyle: { color: "#ffffff", areaColor: "#0a8bd8" // 阴影效果 鼠标移动上去的颜色 } }, z: 2 }, // 点 { name: "companyPoint", type: "effectScatter", coordinateSystem: "geo", showEffectOn: "render", // zlevel: 2, // zlevel用于 Canvas 分层 相同的绘制在同一个canvas上 rippleEffect: { number: 3, // 波纹数量 period: 4, // 动画周期 数值越大,波动越慢 scale: 3.5, // 动画中波纹的最大缩放比例 brushType: "stroke" // 波纹的绘制方式 stroke fill }, label: { show: false, position: "right", formatter: "{b}", color: "#97e9e1", fontSize: 14 }, symbol: "circle", symbolSize: 10, tooltip: { show: true, padding: 0, borderWidth: 0, backgroundColor: "rgba(17, 132, 87,0.8)", textStyle: { fontSize: 14, color: "#fff" }, formatter: function (params) { // console.log(params, 222); var data = params.data; return ( " " + "所属用户:" + data.name + "<br>" + " " + "设备编号:" + data.deviceId + "<br>" + " " + "位置描述:" + data.location + " " + "<br>" + " " + "数据时间:" + data.dataTime ); } }, z: 4 } ]; // 重新渲染echarts if (map == "china") { this.option.geo.layoutCenter = ["50%", "65%"]; this.option.series[0].layoutCenter = ["50%", "65%"]; this.option.geo.roam = false; this.option.series[0].roam = false; // 地图缩放和平移 } else { this.option.geo.layoutCenter = ["50%", "50%"]; this.option.series[0].layoutCenter = ["50%", "50%"]; this.option.geo.roam = true; this.option.series[0].roam = true; // 地图缩放和平移 this.myChart.on("georoam", (params) => { var option = this.myChart.getOption(); //获得option对象 if (params.zoom != null && params.zoom != undefined) { //捕捉到缩放时 option.geo[0].zoom = option.series[0].zoom; //下层geo的缩放等级跟着上层的geo一起改变 option.geo[0].center = option.series[0].center; //下层的geo的中心位置随着上层geo一起改变 this.myChart.getZr().on("mousewheel", (event) => { var zoom = option.geo[0].zoom; var zooms = option.series[0].zoom; var newZoom = event.wheelDelta > 0? zoom * 2 : zoom / 2; var newZooms = event.wheelDelta > 0? zooms * 2 : zooms / 2; newZoom = Math.max(1, Math.min(200, newZoom)); // 限制缩放级别 newZooms = Math.max(1, Math.min(200, newZooms)); // 限制缩放级别 this.myChart.setOption( { geo: { zoom: newZoom }, series: [ { zoom: newZooms } ] }, { lazyUpdate: true }// 是否延迟更新 ); }); } else { //捕捉到拖曳时 option.geo[0].center = option.series[0].center; //下层的geo的中心位置随着上层geo一起改变 this.myChart.setOption(option, { lazyUpdate: true }); //设置option// 是否延迟更新 } }); } this.option.series[1].data = this.provinceData; // 假设数据加载到data变量中 // // 更新图表数据 this.myChart.setOption(this.option, true); // 第二个参数为true表示不合并之前的option,而是完全替换 //随着屏幕大小调节图表 window.addEventListener("resize", () => { this.myChart.resize(); }); }
这个方法配置了地图的各种属性,包括地图样式、缩放、拖动、标记点等。根据传入的地图名称,设置不同的布局和交互方式。最后更新图表数据,并添加监听窗口大小变化的事件,使图表能自适应屏幕变化。
通过以上步骤,我们就利用CDN和阿里地图资源,完成了ECharts中国地图的开发,并且实现了地图层级切换、缩放、拖动等功能。大家可以根据实际项目需求,对代码进行进一步优化和扩展。希望这篇文章能帮助到正在做相关开发的朋友们。