官网建设建站,桂林旅游,北京网页设计公司兴田德润专业,枣阳网站建设_枣阳山水数码vue3echarts绘制某省区县地图
工作中经常需要画各种各样的图#xff0c;echarts是使用最多的工具#xff0c;接近春节#xff0c;想把之前画的echarts图做一个整合#xff0c;方便同事和自己随时使用#xff0c;因此用vue3专门写了个web项目#xff0c;考虑之后不断完善…vue3echarts绘制某省区县地图
工作中经常需要画各种各样的图echarts是使用最多的工具接近春节想把之前画的echarts图做一个整合方便同事和自己随时使用因此用vue3专门写了个web项目考虑之后不断完善
其中有这么个需求需要展示某省各区县的数据写在vue3项目中最终展示结果如下 大体的思路如下
在阿里云dataV数据可视化平台获取数据整合某省各区县的数据成为一个单独的文件echarts中注册这个省的地图echarts画图
主要用的程序语言是JavaScript和Python
下面详细介绍有些技术细节也是自己经常遇到的通过这段时间强化训练感觉对echarts越来越熟练了
一、阿里云dataV地图数据获取
首先上地址阿里云数据可视化平台感谢阿里和高德提供如此牛逼的工具
然后选择点击自己所需的省份比如上面图示的河北 接下来依次点击河北省各地级市比如我点了石家庄此时右侧出现了一个json链接如下图复制那个链接 如果浏览器装了解析json文件的插件就会显示这个json文件的数据如果安装插件应该会直接把这个json文件下载下来json数据如下 接下来依次去点击河北其他城市的地图并获取数据也可以写个爬虫的程序挺简单的
二、将各地市的数据整合成一个省的数据
其实思路就是把单个json中的features提取出来然后整合到一个json文件中去
把上一步下载好的所有文件放到一个目录中如folder
接下来用Python处理一下 features [] # 初始化 features 列表for file in os.listdir(folder):filename os.path.join(folder, file)try:with open(filename, r, encodingutf-8) as f:data json.load(f)features.extend(data.get(features, []))except (IOError, json.JSONDecodeError) as e:print(fError reading JSON file {filename}: {e})json_file {type: FeatureCollection,features: features }# 导出为 JSON 文件output_file_path hebei_combined.jsonwith open(output_file_path, w, encodingutf-8) as output_file:json.dump(json_file, output_file, ensure_asciiFalse, indent2)通过处理后得到的数据样式如下 我不太喜欢在vue项目中直接使用json因为很多情况下都需要异步引入对于没有后端的项目写起来比较费劲。更为致命的是echarts对各种异步的操作非常不友好经常在等待数据的时候发现数据还没有返回就会各种报错。我更倾向于把数据写入到js文件中然后对外暴露实际上这个项目我也是这么操作的我把json里的内容放进同名js文件中然后按需向外暴露对象名为hebeiAreas
三、echarts注册地图
echarts中注册地图非常简单就两步
导入地图数据注册
体现在程序中如下
import * as echarts from echarts;
import { hebeiAreas } from /assets/js/areasOfProvince/hebei_combined
// 注册
echarts.registerMap(proMap, hebeiAreas)这里的注册需要写在正确的地方如果只画一个图写在哪里都无所谓如果涉及到多个省份的切换我建议写在切换成功的地方或者是重绘地图的地方
四、绘图以及踏过的坑
绘图就是正儿八经写代码我先上完整代码
templatediv classcontainerdiv classtopel-select v-modelprovince placeholder请选择省份 changechoosePro stylewidth: 120pxel-option v-for(item, index) in provinces :keyindex :labelitem.label:valueitem.value/el-option/el-selectel-button typeprimary stylemargin-left: 10px; clickchangeData更换数据/el-buttoninput refinput typefile styledisplay: none changehandleFileChange //divdiv classproMap refproMap/div/div
/templatescript setup
import { ref, onMounted, h } from vue
import { provinces } from ./data/provinceName
import { ElMessage, ElNotification } from element-plus
import * as echarts from echarts;
import { areas } from /assets/js/areas
import { hebeiAreas } from /assets/js/areasOfProvince/hebei_combinedconst province ref(hebei)
const provinceZH ref(河北)
const provinceCode ref(13)
const proMap ref()const drawData ref([])
const maxData ref(100)const getMaxData () {const arr []arr.push(drawData.value.map(item item.value))maxData.value Math.max(...arr[0])
}const getData () {const areasOfCurrentProvince areas.filter(item item.provinceCode provinceCode.value)areasOfCurrentProvince.forEach(item {drawData.value.push({name: item.name,value: Math.floor(Math.random() * 101)})});getMaxData()
}// 更换省份
const choosePro () {console.log(province.value)if (province.value ! hebei) {ElNotification({title: 提醒,message: h(i, { style: color: teal }, 省份到区县分块需要处理大量数据功能待后期完成现在只做了河北的),duration: 0})province.value hebei}
}
// 更换数据
// 隐藏输入框的dom
const input ref()
const changeData () {ElNotification({title: 提醒,message: h(i, { style: color: teal }, 请务必使用当前省份下的区县数据否则无法显示正确的数据),duration: 0})input.value.click()
}
const handleFileChange async event {const file event.target.files[0]const reader new FileReader()reader.readAsText(file, UTF-8)reader.onload async (evt) {const fileString await evt.target.resultconst count fileString.trim().split(\n).lengthconsole.log(count)const handleData []for (let i 0; i count; i) {const fileline fileString.split(\n)[i].split(\t)handleData.push({ name: fileline[0], value: parseInt(fileline[1]) })}// 更换数据drawData.value handleDatagetMaxData()drawProMap()}
}
// 画地图相关
let initMap
const drawProMap () {echarts.registerMap(proMap, hebeiAreas)if (initMap ! null initMap ! initMap ! undefined) {initMap.dispose(); //销毁}initMap echarts.init(proMap.value)initMap.setOption({backgroundColor: transparent, // 设置背景色透明tooltip: {show: true,},visualMap: {text: [, ],showLabel: true,left: 200,bottom: 100,min: 0,max: maxData.value,inRange: {color: [#edfbfb, #b7d6f3, #40a9ed, #3598c1, #215096],},// splitNumber: 5,seriesIndex: 0,},series: [{type: map,map: proMap,tooltip: {trigger: item,formatter: function (params) {// params 包含了鼠标悬浮时的相关信息return params.name br/ 数值: params.value;}},zoom: 1,label: {show: false, // 显示地市名称color: #000,align: center,},top: 10%,left: center,aspectScale: 0.75,roam: true, // 地图缩放和平移itemStyle: {borderColor: #3ad6ff, // 省分界线颜色 阴影效果的borderWidth: 1,areaColor: #F5F5F5,opacity: 1,},// 控制鼠标悬浮上去的效果emphasis: {// 聚焦后颜色disabled: false, // 开启高亮label: {align: center,color: #ffffff,},itemStyle: {color: #ffffff,areaColor: #0075f4, // 阴影效果 鼠标移动上去的颜色},},z: 2,data: drawData.value,}]})window.addEventListener(resize, () {initMap.resize();});
}onMounted(() {getData()setTimeout(() { drawProMap() }, 200)
})
/scriptstyle langscss scoped
.top {padding: 5px;width: 100%;box-shadow: rgba(17, 17, 26, 0.1) 0px 0px 16px;
}.proMap {height: 95%;width: 95%;
}
/style以上代码有自己踏过的不少坑我都说明一下肯定还有其他坑一句话echarts全是坑 getData()是生成地图对应数据的方法我这里用了随机数数据格式如下 [{name: 涞源县, value: 100},....
]就是由key为name和value对象组成的数组 getMaxData()是获取上面数组中的value的最大值这主要是绘图的时候图例范围的最大值设置 drawProMap()是绘制地图的方法 坑1注意onMounted钩子中的写法 onMounted(() {getData()setTimeout(() { drawProMap() }, 200)
})挂载组件之前先要获取数据然后组件出现就应该有图出现这里我设置了0.2s的延时画图原因是需要先等dom渲染完成后再画图不然会直接报错 坑2画图dom的宽和高必须要先设置看我的样式 .proMap {height: 95%;width: 95%;
}这必须写不然图出不来还会报警说无法获取dom的宽高 坑3地图dom的初始化问题 看相关的代码 // 画地图相关
let initMap
const drawProMap () {echarts.registerMap(proMap, hebeiAreas)if (initMap ! null initMap ! initMap ! undefined) {initMap.dispose(); //销毁}initMap echarts.init(proMap.value)/*省略其他代码*/
}一般情况下可能我们会在画图的时候直接就是 const initMap echarts.init(proMap.value)上来就直接初始化画图的dom可能的情况是如果是在相同的dom上重绘echarts图控制台就会报警并非报错效果会正常出现说这个dom上本来就存在echarts图所以在初始化之前正确的操作是判断dom上的echarts图是否占用占用的话就销毁也就是initMap.dispose(); 从上面的代码可以看出省份是可以选择的数据也是可以改的 先说改数据。改数据的逻辑是设定一个隐藏的input dom元素为什么要用input因为input可以打开文件如下代码其中typefile就是打开文件change是文件改变的事件 input refinput typefile styledisplay: none changehandleFileChange /由于这个dom是隐藏的styledisplay: none所以打开文件应该是由按钮来控制也就是下面这行代码 el-button typeprimary stylemargin-left: 10px; clickchangeData更换数据/el-button它俩的逻辑关系是 点击按钮隐藏的input按钮实现点击事件如下代码 const input ref()
const changeData () {ElNotification({title: 提醒,message: h(i, { style: color: teal }, 请务必使用当前省份下的区县数据否则无法显示正确的数据),duration: 0})input.value.click()
}接下来就会触发input的文件打开功能选定文件后就会执行handleFileChange方法在这个方法中使用了处理txt文本文件的方法需要注意其中的异步操作并且有处理换行以及按tab分割的逻辑这里需要根据个人的项目进行适配处理好数据后替换画图的数据即可然后执行获取最大值和画图方法相关代码如下 const handleFileChange async event {const file event.target.files[0]const reader new FileReader()reader.readAsText(file, UTF-8)reader.onload async (evt) {const fileString await evt.target.resultconst count fileString.trim().split(\n).lengthconsole.log(count)const handleData []for (let i 0; i count; i) {const fileline fileString.split(\n)[i].split(\t)handleData.push({ name: fileline[0], value: parseInt(fileline[1]) })}// 更换数据drawData.value handleDatagetMaxData()drawProMap()}
}再说切换省份。我的代码中并没有实现切换省份的逻辑因为需要大量的数据支撑也就是说要把全国34个省级行政区划包括港澳台的地图文件都获取切换成功后异步引入地图文件并注册地图然后画图这一步我在其他地方实现过同样存在坑 坑4异步导入json文件首次绘图会出现报错报错如下 Error: Invalid geoJson format coordinate.charCodeAt is not a function 但是刷新页面就正常了查了一下相关的资料有人解释是 因为 echarts 会绘制解析 json 之后 执行 decode 方法 后 会将其 UTF8Encoding 的值 从 true 改为false第二次绘制 时如果 为 false 则 不需要走 decode 方法如果每次都是新引入的 json那每次都走 decode 就会报错 ———————————————— 版权声明本文为博主原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接和本声明。原文链接https://blog.csdn.net/m0_37805167/article/details/122553278
他建议是 Object.assign({}, json) 拷贝一次解释是异步获取的数据是只读的echarts无法更改所以会报错需要拷贝一下确实在某些情况下能解决但通过路由切换到需要画图的页面上来时依然会报错目前还没有找到靠谱的解决方案可能不用json而是用js会解决这个问题需要我来确认