vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能


Posted in Javascript onNovember 16, 2020

随着前端技术的飞速发展,大数据时代的来临,我们在开发项目时越来越多的客户会要求我们做一个数据展示的大屏,可以直观的展示用户想要的数据,同时炫酷的界面也会深受客户的喜欢。

大屏展示其实就是一堆的图表能够让人一目了然地看到该系统下的一些基本数据信息的汇总,也会有一些实时数据刷新,信息预警之类的。笔者在之前也做过一些大屏类的数据展示,但是由于都是一些图表类的,觉得没什么可说的,加之数据也都牵扯到公司,所以没有沉淀下来什么。

最近有朋友要做一个大屏,问了自己一个问题,自己也刚好做了一个简单的大屏数据展示,趁此机会做一个小总结。

先看一下效果:

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能

由于数据牵扯到公司内部信息,所以将一些复杂的切换逻辑都去掉类,但保留了一些数据间但相互联动。

项目采用的是Vue+Echanrts+datav写的,结构目录如下:

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能

由于只是一个单一页面,数据处理也不是复杂,没有涉及到router和vuex,从结构目录上看就是一个很典型的vue-cli项目,在之前我也讲过关于vue-cli项目的一些操作和目录结构解释,这里就不做多做说明了,在文章最后会提供该项目的源码地址库。

大屏主要的炫酷效果本人引用的是datav组件,地址:http://datav.jiaminghi.com/,这简直就是数据可视化的一款神器,神奇之处我就不多说了,大家可以自己去它的网站上自行体会。它也提供了如何在vue 中使用该组件。

datav可以全局注入,也可以按需注入,本人省事就直接在main.js中进行了全局注入。

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能

所有的页面代码都放在了views文件目录下:

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能

其中index.vue文件为主文件入口,其他都是其子组件,组件名称以方位的形式命名,如centerForm.vue就是中间的表单控件。

本项目引入了中国地图并实现省市县下钻,最初采用的是阿里旗下的高德地图,后来因为种种原因改为了百度提供的Echarts来实现,但两种使用方法都保留了下来,大家可以根据自己的需求进行选择。

其中Echarts中国地图的代码如下:

<template>
 <div id="china_map_box">
 <el-button type="primary" size="mini" class="back" @click="back" v-if="deepTree.length > 1">返回</el-button>
 <div class="echarts">
  <div id="map"></div>
 </div>
 </div>
</template>

<script>

 import {getChinaJson, getProvinceJSON, getCityJSON} from "../api/get-json";
 import {cityProvincesMap} from '../config/cityProvincesMap'
 import {mapOption} from '../config/mapOption'


 export default {
 name: "china",
 components: {},
 data() {
  return {
  chart: null, // 实例化echarts
  provincesMap: cityProvincesMap.provincesMap, // 省拼音,用于查找对应json
  provincesCode: cityProvincesMap.provincesCode, // 市行政区划,用于查找对应json
  areaMap: cityProvincesMap.areaMap, // 省行政区划,用于数据的查找,按行政区划查数据
  special: ["北京市", "天津市", "上海市", "重庆市", "香港", "澳门"],//直辖市和特别行政区-只有二级地图,没有三级地图
  mapData: [], // 当前地图上的地区
  option: {...mapOption.basicOption}, // map的相关配置
  deepTree: [],// 点击地图时push,点返回时pop
  areaName: '中国', // 当前地名
  areaCode: '000000', // 当前行政区划
  areaLevel: 'country', // 当前级别
  }
 },
 mounted() {
  this.$nextTick(() => {
  this.initEcharts();
  this.chart.on('click', this.echartsMapClick);
  });
 },
 methods: {
  // 初次加载绘制地图
  initEcharts() {
  //地图容器
  this.chart = this.$echarts.init(document.getElementById('map'));
  if (this.areaCode === '000000') {
   this.requestGetChinaJson();
  } else {
   this.requestGetProvinceJSON({areaName: this.areaName, areaCode: this.areaCode})
  }
  },
  // 地图点击
  echartsMapClick(params) {
  // console.log(params);
  this.areaName = params.areaName;
  if (params.name in this.provincesMap) {
   this.areaCode = params.data.areaCode;
   this.areaLevel = params.data.areaLevel;
   //如果点击的是34个省、市、自治区,绘制选中地区的二级地图
   this.requestGetProvinceJSON(params.data);
  } else if (params.seriesName in this.provincesMap) {
   //如果是【直辖市/特别行政区】只有二级下钻
   if (this.special.indexOf(params.seriesName) >= 0) {
   return;
   } else {
   this.areaCode = this.areaMap[params.name];
   this.areaLevel = params.data.areaLevel;
   //显示县级地图
   this.requestGetCityJSON(params.data)
   }
  } else {
   return;
  }
  this.$emit('map-change', params.data);
  },
  //绘制全国地图
  requestGetChinaJson() {
  getChinaJson().then(res => {
   let arr = [];
   for (let i = 0; i < res.features.length; i++) {
   let obj = {
    name: res.features[i].properties.name,
    areaName: res.features[i].properties.name,
    areaCode: res.features[i].id,
    areaLevel: 'province',
    value: Math.round(Math.random()),
   };
   arr.push(obj)
   }
   this.mapData = arr;
   this.deepTree.push({
   mapData: arr,
   params: {name: 'china', areaName: 'china', areaLevel: 'country', areaCode: '000000'}
   });
   //注册地图
   this.$echarts.registerMap('china', res);
   //绘制地图
   this.renderMap('china', arr);
  });
  },
  // 加载省级地图
  requestGetProvinceJSON(params) {
  getProvinceJSON(params.areaCode).then(res => {
   this.$echarts.registerMap(params.areaName, res);
   let arr = [];
   for (let i = 0; i < res.features.length; i++) {
   let obj = {
    name: res.features[i].properties.name,
    areaName: res.features[i].properties.name,
    areaCode: res.features[i].id,
    areaLevel: 'city',
    value: Math.round(Math.random()),
   };
   arr.push(obj)
   }
   this.mapData = arr;
   this.deepTree.push({
   mapData: arr,
   params: params,
   });
   this.renderMap(params.areaName, arr);
  });
  },
  // 加载市级地图
  requestGetCityJSON(params) {
  this.areaLevel = params.areaLevel;
  getCityJSON(params.areaCode).then(res => {
   this.$echarts.registerMap(params.areaName, res);
   let arr = [];
   for (let i = 0; i < res.features.length; i++) {
   let obj = {
    name: res.features[i].properties.name,
    areaName: res.features[i].properties.areaName,
    areaCode: res.features[i].id,
    areaLevel: 'districts',
    value: Math.round(Math.random()),
   };
   arr.push(obj)
   }
   this.mapData = arr;
   this.deepTree.push({mapData: arr, params: params});
   this.renderMap(params.areaName, arr);
  })
  },
  renderMap(map, data) {
  this.option.series = [
   {
   name: map,
   mapType: map,
   ...mapOption.seriesOption,
   data: data
   }
  ];
  //渲染地图
  this.chart.setOption(this.option);
  },
  // 返回
  back() {
  // console.log(this.deepTree);
  if (this.deepTree.length > 1) {
   this.deepTree.pop();
   let areaName = this.deepTree[this.deepTree.length - 1].params.areaName;
   let mapData = this.deepTree[this.deepTree.length - 1].mapData;
   this.$emit('back-change', this.deepTree[this.deepTree.length - 1].params);
   this.renderMap(areaName, mapData);
  }
  }
 }
 }

</script>

<style lang="scss" scoped>
 #china_map_box {
 display: flex;
 width: 100%;
 height: 100%;
 position: relative;
 .echarts {
  width: 0;
  flex: 1;
  background-size: 100% 100%;
  #map {
  height: 100%;
  }
 }
 .back {
  position: absolute;
  top: .8rem;
  right: .5rem;
  z-index: 999;
  padding-left: .12rem;
  padding-right: .12rem;

 }
 }

</style>

在调用省市地图时本人采用的是将地图信息的json存放在了本地,这是由于本人的项目中很多地市的行政区划很多需要变动,这也是放弃高德地图的原因之一。json文件放在了public文件目录下,如下图:

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能

里面有一些自己没用到的json数据本人进行了删除,关于中国详细的json数据大家可以去https://datav.aliyun.com/tools/atlas/下载,内容由高德开放平台提供。

高德地图chinaGaode.vue代码如下:

<template>
 <div id="china_map_box">
 <el-button type="primary" size="mini" class="back" @click="back">返回</el-button>
 <div class="map" >
  <map-range @change="search"></map-range>
 </div>
 <div class="echarts">
  <div id="map"></div>
 </div>
 </div>
</template>

<script>
 import mapRange from "./mapRange";

 export default {
 name: "chinaGaode",
 components: {
  mapRange
 },
 data() {
  return {
  provinceSelect: null,
  citySelect: null,
  districtSelect: null,
  areaName: '中国',
  geoJsonData: '',
  echartsMap: null,
  map: null,
  district: null,
  polygons: [],
  areaCode: 100000,
  opts: {},
  areaData: {},
  mapData: [],
  deepTree:[],
  }
 },
 mounted() {
  this.provinceSelect = document.getElementById('province');
  this.citySelect = document.getElementById('city');
  this.districtSelect = document.getElementById('district');
  this.deepTree = [{mapData: this.mapData,code: 100000}];
  this.echartsMap = this.$echarts.init(document.getElementById('map'));
  this.echartsMap.on('click', this.echartsMapClick);
  this.map = new AMap.Map('container', {
  resizeEnable: true,
  center: [116.30946, 39.937629],
  zoom: 3
  });
  this.opts = {
  subdistrict: 1, //返回下一级行政区
  showbiz: false //最后一级返回街道信息
  };
  this.district = new AMap.DistrictSearch(this.opts);//注意:需要使用插件同步下发功能才能这样直接使用
  this.district.search('中国', (status, result) => {
  if (status == 'complete') {
   this.getData(result.districtList[0], '', 100000);
  }
  });
 },
 methods: {
  //地图点击事件
  echartsMapClick(params) {
  if (params.data.level == 'street') return;
  //清除地图上所有覆盖物
  for (var i = 0, l = this.polygons.length; i < l; i++) {
   this.polygons[i].setMap(null);
  }
  this.areaName = params.data.name;
  this.areaCode = params.data.areaCode;
  this.district.setLevel(params.data.level); //行政区级别
  this.district.setExtensions('all');
  //行政区查询
  //按照adcode进行查询可以保证数据返回的唯一性
  this.district.search(this.areaCode, (status, result) => {
   if (status === 'complete') {
   this.deepTree.push({mapData: this.mapData,code: params.data.areaCode});
   this.getData(result.districtList[0], params.data.level, this.areaCode);
   }
  });
  this.$emit('map-change', params.data);
  },
  loadMapData(areaCode) {
  AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
   //创建一个实例
   var districtExplorer = window.districtExplorer = new DistrictExplorer({
   eventSupport: true, //打开事件支持
   map: this.map
   });
   districtExplorer.loadAreaNode(areaCode, (error, areaNode) => {
   if (error) {
    console.error(error);
    return;
   }
   let mapJson = {};
   mapJson.type = "FeatureCollection";
   mapJson.features = areaNode.getSubFeatures();
   this.loadMap(this.areaName, mapJson);
   this.geoJsonData = mapJson;
   });
  });
  },
  loadMap(mapName, data) {
  if (data) {
   this.$echarts.registerMap(mapName, data);
   var option = {

   visualMap: {
    type: 'piecewise',
    pieces: [
    {max: 1, label: '审核完成', color: '#2c9a42'},
    {min: -1, max: 1, label: '未完成', color: '#d08a00'},
    // {min: 60, label: '危险', color: '#c23c33'},
    ],
    color: '#fff',
    textStyle: {
    color: '#fff',
    },
    visibility: 'off',
    top:50,
    left:30,
   },
   series: [{
    name: '数据名称',
    type: 'map',
    roam: false,
    mapType: mapName,
    selectedMode: 'single',
    showLegendSymbol: false,
    visibility: 'off',
    itemStyle: {
    normal: {
     color: '#ccc',
     areaColor: '#fff',
     borderColor: '#fff',
     borderWidth: 0.5,
     label: {
     show: true,
     textStyle: {
      color: "rgb(249, 249, 249)",
      fontSize: '1rem'
     }
     }
    },
    emphasis: {
     areaColor: false,
     borderColor: '#fff',
     areaStyle: {
     color: '#fff'
     },
     label: {
     show: true,
     textStyle: {
      color: "rgb(249, 249, 249)"
     }
     }
    }
    },
    data: this.mapData,
   }]
   };
   this.echartsMap.setOption(option);
  }
  },
  getData(data, level, adcode) {
  var bounds = data.boundaries;
  if (bounds) {
   for (var i = 0, l = bounds.length; i < l; i++) {
   var polygon = new AMap.Polygon({
    map: this.map,
    strokeWeight: 1,
    strokeColor: '#0091ea',
    fillColor: '#80d8ff',
    fillOpacity: 0.2,
    path: bounds[i]
   });
   this.polygons.push(polygon);
   }
   this.map.setFitView();//地图自适应
  }

  //清空下一级别的下拉列表
  if (level === 'province') {
   this.citySelect.innerHTML = '';
   this.districtSelect.innerHTML = '';
  } else if (level === 'city') {
   this.districtSelect.innerHTML = '';
  }
  var subList = data.districtList;
  if (subList) {
   let optionName = '--请选择--';
   var contentSub = new Option(optionName);
   var curlevel = subList[0].level;
   if (curlevel === 'street') {
   let mapJsonList = this.geoJsonData.features;
   let mapJson = {};
   for (let i in mapJsonList) {
    if (mapJsonList[i].properties.name == this.areaName) {
    mapJson.type = "FeatureCollection";
    mapJson.features = [].concat(mapJsonList[i]);
    }
   }
   this.mapData = [];
   this.mapData.push({name: this.areaName, value: 0, level: curlevel});
   this.loadMap(this.areaName, mapJson);
   return;
   }

   var curList = document.querySelector('#' + curlevel);
   curList.add(contentSub);
   this.mapData = [];
   for (var i = 0, l = subList.length; i < l; i++) {
   var name = subList[i].name;
   var areaCode = subList[i].adcode;
   this.mapData.push({
    name: name,
    value: Math.round(Math.random()),
    areaCode: areaCode,
    level: curlevel
   });
   var levelSub = subList[i].level;
   contentSub = new Option(name);
   contentSub.setAttribute("value", levelSub);
   contentSub.center = subList[i].center;
   contentSub.adcode = subList[i].adcode;
   curList.add(contentSub);
   }
   this.loadMapData(adcode);
   this.areaData[curlevel] = curList;
  }

  },
  search(area) {
  let obj = this.areaData[area];
  //清除地图上所有覆盖物
  for (var i = 0, l = this.polygons.length; i < l; i++) {
   this.polygons[i].setMap(null);
  }
  var option = obj[obj.options.selectedIndex];

  var keyword = option.text; //关键字
  var adcode = option.adcode;
  this.areaName = keyword;
  this.areaCode = adcode;
  this.district.setLevel(option.value); //行政区级别
  this.district.setExtensions('all');
  //行政区查询
  //按照adcode进行查询可以保证数据返回的唯一性
  this.district.search(adcode, (status, result) => {
   if (status === 'complete') {
   this.deepTree.push({mapData: this.mapData,code:adcode});
   this.getData(result.districtList[0], obj.id, adcode);
   }
  });
  var params = {
   areaCode: adcode,
   level: area,
   name: keyword,
   value: '',
  };
  this.$emit('map-change', params);
  },
  back() {
  // console.log(this.deepTree)
  if (this.deepTree.length > 1) {
   this.mapData = this.deepTree[this.deepTree.length - 1].mapData;
   this.deepTree.pop();
   // console.log(this.deepTree[this.deepTree.length - 1], 'back');
   this.loadMapData(this.deepTree[this.deepTree.length - 1].code)
  }
  }
 }
 }
</script>

<style lang="scss" scoped>
 #china_map_box {
 display: flex;
 width: 100%;
 height: 100%;
 position: relative;
 .echarts {
  width: 0;
  flex: 1;
  background-size: 100% 100%;
  #map {
  height: 100%;
  }
 }
 .back {
  position: absolute;
  top: .8rem;
  right: .5rem;
  z-index: 999;
 }

 }

</style>

在网上有很多下伙伴都在查找如何使用中国地图并实现下钻,在实际使用地图时其实并不难,以上是本人提供的一些解决方案和代码提供。

由于代码是从本人的一个项目中剥离而来,代码的质量可能欠佳,有些逻辑处理和傅子组件间的数据联动也都有所减少,但并不影响该项目demo的使用,如果有需要大家可以去以下地址下载源码学习,也欢迎star。

gitee源码地址:https://gitee.com/vijtor/vue-map-datav

到此这篇关于vue+echarts+datav大屏数据展示及实现中国地图省市县下钻的文章就介绍到这了,更多相关vue+echarts大屏数据展示内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
写的htc的数据表格
Jan 20 Javascript
jQuery中用dom操作替代正则表达式
Dec 29 Javascript
JS实现可关闭的对联广告效果代码
Sep 14 Javascript
JavaScript中的原始值和复杂值
Jan 07 Javascript
可输入文字查找ajax下拉框控件 ComBox的实现方法
Oct 25 Javascript
Bootstrap学习笔记之环境配置(1)
Dec 07 Javascript
Es6 写的文件import 起来解决方案详解
Dec 13 Javascript
webpack实现热更新(实施同步刷新)
Jul 28 Javascript
iview给radio按钮组件加点击事件的实例
Sep 30 Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
Jul 17 Javascript
iview同时验证多个表单问题总结
Sep 29 Javascript
JavaScript中的连续赋值问题实例分析
Jul 12 Javascript
angular8.5集成TinyMce5的使用和详细配置(推荐)
Nov 16 #Javascript
js实现纯前端压缩图片
Nov 16 #Javascript
Vue基于localStorage存储信息代码实例
Nov 16 #Javascript
微信小程序自定义底部弹出框动画
Nov 18 #Javascript
vue 封装面包屑组件教程
Nov 16 #Javascript
Vue使用路由钩子拦截器beforeEach和afterEach监听路由
Nov 16 #Javascript
小程序实现密码输入框
Nov 16 #Javascript
You might like
SONY SRF-M100的电路分析
2021/03/02 无线电
php调用nginx的mod_zip模块打包ZIP文件
2014/06/11 PHP
php基于Redis消息队列实现的消息推送的方法
2018/11/28 PHP
用正则表达式替换图片地址img标签
2013/11/22 Javascript
JS onmousemove鼠标移动坐标接龙DIV效果实例
2013/12/16 Javascript
JavaScript中利用Array和Object实现Map的方法
2015/07/27 Javascript
基于JavaScript实现一定时间后去执行一个函数
2015/12/14 Javascript
javascript实现网页端解压并查看zip文件
2015/12/15 Javascript
jQuery 局部div刷新和全局刷新方法总结
2016/10/05 Javascript
js document.getElementsByClassName的使用介绍与自定义函数
2016/11/25 Javascript
Bootstrap基本插件学习笔记之折叠(22)
2016/12/08 Javascript
微信小程序外卖选购页实现切换分类与数量加减功能案例
2019/01/15 Javascript
vue接入腾讯防水墙代码
2019/05/07 Javascript
vue实现div可拖动位置也可改变盒子大小的原理
2020/09/16 Javascript
vue实现简易的双向数据绑定
2020/12/29 Vue.js
Python中的map、reduce和filter浅析
2014/04/26 Python
Python单元测试框架unittest使用方法讲解
2015/04/13 Python
使用Node.js和Socket.IO扩展Django的实时处理功能
2015/04/20 Python
Python中处理字符串的相关的len()方法的使用简介
2015/05/19 Python
使用Python的urllib和urllib2模块制作爬虫的实例教程
2016/01/20 Python
Python数组定义方法
2016/04/13 Python
python自动发微信监控报警
2019/09/06 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
Python定时任务框架APScheduler原理及常用代码
2020/10/05 Python
Python操控mysql批量插入数据的实现方法
2020/10/27 Python
Hotels.com英国:全球领先的酒店住宿提供商
2019/01/24 全球购物
美国最大的在线生存商店:Survival Frog
2020/12/13 全球购物
公司出纳岗位职责
2013/12/07 职场文书
大学生实习证明范本
2014/01/15 职场文书
2014年元旦感言
2014/03/06 职场文书
优秀毕业生自荐信
2014/06/10 职场文书
小学领导班子对照材料
2014/08/23 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
2014年自愿离婚协议书范本
2014/09/25 职场文书
2014年学习委员工作总结
2014/11/14 职场文书
2014教师专业技术工作总结
2014/12/03 职场文书