疫情数据分析平台(五):中国疫情地图绘制

中国疫情地图相比世界疫情地图承载更多功能,因此其技术实现的难度也更高,相比世界地图echarts的绘制,中国疫情地图包含大量同步异步函数的使用,同时包含下钻(点击省份进入各省地图)和返回(回到中国地图),以及一些预想好的点击事件,其难度相对较高。

中国地图并非使用像世界地图在echarts中直接调用。而是采用自定义地图,首先找到自定义的地图数据(json格式),包括中国地图以及各省份地图:

 

数字代表各省的adcode前缀,如北京adcode为110000.

一开始我采取的方法是在页面加载时将json文件全部引入,下钻时直接调用,在开发环境中这一方法并无大碍,但在服务器部署时,我发现这会导致网站在前期非常卡顿(由于在下载json数据),于是在优化过程中改为了按需引入json文件。

设计过程如下:

      currentName:'', // 当前地图的名字
      currentLevel:1, // 当前地图层级,1代表中国看省份,2代表各省份看市,一共两个层级
      currentJson:null, // 针对当前地图需要的json数据
      chart:null, // 地图
      options:{}, // 地图的设置

首先在vue的数据中声明如上数据,currentName代表当前地图的名字(中国、山东等);currentLevel代表当前地图层级,共两层,1代表中国地图,2代表各省份地图。currentJson代表当前地图所使用的自定义地图json数据,chart是地图对象,options代表地图的设置。

我所设想的下钻思路是:

首先绘制中国地图,点击事件中触发goDown()函数,进入下一层级及省份地图,将文件全局声明的options调整为对应省份的json文件,重新绘制地图。

这其中有若干异步问题,在函数中我们具体分析:

明确了思路即可编写对应函数,首先确定一些共用的地图设置,编为初始化options:

initOption(){
      this.options={
        grid:{
          width:'100%',
          height:'100%',
          left:'0%',
          bottom:'0%',
          containLabel:true
        },

        /*geo: {
          map: 'china',
          roam: true,
          label: {
            emphasis: {
              show: true
            },
          }
        },*/

        tooltip:{
          trigger:'item',
          formatter:function(val){
            if(val.data==null) return;
            return val.name+': '+val.value
          }
        },

        visualMap:{
          min:0,
          max:10000,
          text:['max','min'],
          realtime:false,
          calcuable:true,
          color:['#ff4500','#fffafa'],
        },

        series:[
          {
            type:'map',
            map:'',
            //roam:false,
            scale:true,
            //data:data,
            label:{
              show:true
            },
            zoom:1.2,
            itemStyle:{
              borderWidth:0.5,
              borderColor:'#000',
              borderType:'solid'
            },
            emphasis:{
              label:{
                show:true,
                color:'#fff'
              },
              itemStyle:{
                areaColor:'#FF6347',
              }
            },

            //data:data

          }
        ]

      }
    },

之后编写绘制地图的函数,这个函数会在页面创始时绘制,同时每次变更层级时再次调用。

async drawChart(){
      if(this.chart){
        if(this.currentLevel==1){
          this.btn_flag=true
        }else {
          this.btn_flag=false
        }

        //已经存在chart了。存在于返回上一层级或者进入下一层级
        this.chart.setOption(this.options)

        //每次重置地图时,重置点击事件,通过现有层级判断点击的事件
        this.chart.off('click')
        if(this.currentLevel==1){
          this.chart.on('click',(params)=>{
            if(params.componentSubType=='map'){
              //console.log(params.name)
              this.$emit('mapClick',params)
              this.provinceName=params.name
              this.goDown(params.name)

            }
          })
        }else{
          this.chart.on('click',(params)=>{
            if(params.componentSubType=='map'){
              //this.citydata=[]
              console.log(this.citydata)
              this.getCityData(params.name)
              this.drawer=true

            }
          })
        }

        this.resize()
        /*var _this=this
        window.addEventListener('resize',function() {
          _this.chart.resize()
        })*/

      }else{
        //第一次打开页面
        const map1=document.getElementById('chart2')
        this.currentName='中国'
        this.currentLevel=1
        this.currentJson=chinaMapJson
        echarts.registerMap('china',chinaMapJson)
        this.initOption()
        this.options.series[0].map='china'
        //console.log(this.options) //该语句执行了,而且name属性确实为china,但是不显示图像,why

        //数据的插入
        this.options.series[0].data=this.chinaChartdata

        this.chart=echarts.init(map1)
        this.chart.setOption(this.options)

        this.resize()
        console.log(this.chart) //chart不是空的
        /*var _this=this
        window.addEventListener('resize',function() {
          _this.chart.resize()
        })*/

        //点击事件
        this.chart.on('click',(params)=>{
          if(params.componentSubType=='map'){
            console.log(params.name)
            this.$emit('mapClick',params)
            this.provinceName=params.name
            this.goDown(params.name)

          }
        })

      }
    },

注意到这个函数声明为async,即异步函数,由于在绘图中存在等待数据的行为,即await,故声明为async。函数逻辑为:首先判断chart是否为空,为空则表明第一次绘图,初始化若干属性,并调用中国json文件的数据进行绘图。若不为空,即下钻或者上卷,这时被设计为只有在goDown()或returnToFrst()函数中才会调用,此时设置已经在对应函数中修改,因此直接传入设置即可。

注意点击事件,在初始化时点击事件为进入下一层级,即goDown()。而在后续绘图时,需要判断是否第一层级,据此来设置点击事件为显示详细数据或进入下一层级。

根据我们现有的json文件名,需要设计一个地区名和文件名映射的函数,结构很简单,switch进行判断:

getMapJson(name){
      if (name=='china'){
        return chinaMapJson
      }else{
        switch (name){
          /*case '北京':
            return beijingMapJson
          case '天津':
            return tianjinMapJson
          case '河北':
            return hebeiMapJson
          case '湖北':
            return hubeiMapJson
          case '上海':
            return shanghaiMapJson
          case '山东':
            return shandongMapJson
          case '辽宁':
            return liaoningMapJson
          case '河南':
            return henanMapJson
          case '黑龙江':
            return heilongjiangMapJson
          case '吉林':
            return jilinMapJson
          case '江苏':
            return jiangsuMapJson
          case '浙江':
            return zhejiangMapJson
          case '安徽':
            return anhuiMapJson
          case '内蒙古':
            return neimengguMapJson
          case '山西':
            return shan1xiMapJson
          case '陕西':
            return shan3xiMapJson
          case '甘肃':
            return gansuMapJson
          case '宁夏':
            return ningxiaMapJson
          case '新疆':
            return xinjiangMapJson
          case '广西':
            return guangxiMapJson
          case '四川':
            return sichuanMapJson
          case '重庆':
            return chongqingMapJson
          case '湖南':
            return hunanMapJson
          case '西藏':
            return xizangMapJson
          case '江西':
            return jiangxiMapJson
          case '广东':
            return guangdongMapJson
          case '福建':
            return fujianMapJson
          case '云南':
            return yunnanMapJson
          case '香港':
            return xianggangMapJson
          case '台湾':
            return taiwanMapJson
          case '海南':
            return hainanMapJson
          case '贵州':
            return guizhouMapJson
          case '青海':
            return qinghaiMapJson*/
          case '北京':
            return '11'
          case '天津':
            return '12'
          case '河北':
            return '13'
          case '湖北':
            return '42'
          case '上海':
            return '31'
          case '山东':
            return '37'
          case '辽宁':
            return '21'
          case '河南':
            return '41'
          case '黑龙江':
            return '23'
          case '吉林':
            return '22'
          case '江苏':
            return '32'
          case '浙江':
            return '33'
          case '安徽':
            return '34'
          case '内蒙古':
            return '15'
          case '山西':
            return '14'
          case '陕西':
            return '61'
          case '甘肃':
            return '62'
          case '宁夏':
            return '64'
          case '新疆':
            return '65'
          case '广西':
            return '45'
          case '四川':
            return '51'
          case '重庆':
            return '50'
          case '湖南':
            return '43'
          case '西藏':
            return '54'
          case '江西':
            return '36'
          case '广东':
            return '44'
          case '福建':
            return '35'
          case '云南':
            return '53'
          case '香港':
            return '81'
          case '台湾':
            return '71'
          case '海南':
            return '46'
          case '贵州':
            return '52'
          case '青海':
            return '63'
        }
      }
    },

注意注释掉的部分,这部分为初始版本中一开始将json文件全部引入的方法,直接对应到对应的json文件,goDown()函数调用返回结果直接使用即可。而后续版本改为返回adcode的前缀字符串。

之后我们聚焦goDown()函数:

async goDown(name){
      if(this.currentLevel!=1){
        return false
      }

      this.currentLevel=2
      const mapname=name
      this.currentName=name
      //this.currentJson=this.getMapJson(name)
      const n1=this.getMapJson(name)
      await this.getJsonByname(n1).then(res=>{
        echarts.registerMap(this.currentName,res)
      })
      console.log(this.currentJson)

      this.options.series[0].map=this.currentName


      //this.loadProvinceData(name)
      this.loadProvinceChartData(name)

      /*this.chart.on('click',(params)=>{
        if(params.componentSubType=='map'){
          console.log(params.name)
          this.$emit('mapClick',params)
          this.drawer=true
        }
      })*/



    },

注意函数中为了保证设置和加载数据在获取对应文件之后,使用了await,而使用await必须在async中,因此声明为async函数。await即等待该方法体执行完(返回promise对象)才执行后续语句。

具体的获取对应文件的函数如下:

 getJsonByname(name){
      const jsondata=import('../../assets/echarts-mapJson-master/geometryProvince/'+name+'.json')

      return jsondata
    },

简单的引入。但是需要注意,这里的jsondata实际为一个promise对象,要想获得对象的数据而非其对象本身,需要在then函数中处理,即上面函数中的

await this.getJsonByname(n1).then(res=>{
        echarts.registerMap(this.currentName,res)
      })

到此,绘图的函数基本解决。编写axios请求后端数据的函数即可:

loadChinaData(){
      var _this=this
      this.$axios.get('/user/china_data').then(resp=>{
        if(resp&&resp.status===200){
          _this.chinaChartdata=resp.data
        }
      }).then(()=>{
        this.initChart()
      })
    },

loadProvinceChartData(name){
      var _this=this
      this.$axios.get('/user/pro_data?pro='+name).then(resp=>{
        if(resp&&resp.status===200){
          _this.provincedata=resp.data.data
          for(var i=0;i<_this.provincedata.length;i++){
            var obj={
              name:_this.provincedata[i].mapName,
              value:_this.provincedata[i].econNum
            }
            _this.provinceChartdata.push(obj)
            _this.options.series[0].data=_this.provinceChartdata
            _this.drawChart()
          }
        }
      })

    },

效果如下:

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值