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 相关文章推荐
javascript 年月日联动实现核心代码
Dec 21 Javascript
对jQuery的事件绑定的一些思考(补充)
Apr 20 Javascript
ExtJS4 动态生成的grid导出为excel示例
May 02 Javascript
Javascript 多物体运动的实现
Dec 24 Javascript
yui3的AOP(面向切面编程)和OOP(面向对象编程)
May 01 Javascript
jQuery实现滚动鼠标放大缩小图片的方法(附demo源码下载)
Mar 05 Javascript
jQuery on()方法绑定动态元素的点击事件无响应的解决办法
Jul 07 Javascript
详解Node.js:events事件模块
Nov 24 Javascript
基于angular实现三级联动的生日插件
May 12 Javascript
phantomjs导出html到pdf的方法总结
Oct 19 Javascript
vue+swiper实现组件化开发的实例代码
Oct 26 Javascript
超好用的jQuery分页插件jpaginate用法示例【附源码下载】
Dec 06 jQuery
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
javascript学习之闭包分析
2010/12/02 Javascript
Jquery命名冲突解决的五种方案分享
2012/03/16 Javascript
可自己添加html的伪弹出框实现代码
2013/09/08 Javascript
使用GruntJS构建Web程序之合并压缩篇
2014/06/06 Javascript
JS实现表单中checkbox对勾选中增加边框显示效果
2015/08/21 Javascript
JavaScript各类型的关系图解
2015/10/16 Javascript
详解JavaScript的回调函数
2015/11/20 Javascript
JS加载iFrame出现空白问题的解决办法
2016/05/13 Javascript
js控住DOM实现发布微博效果
2016/08/30 Javascript
基于AngularJS前端云组件最佳实践
2016/10/20 Javascript
完美解决input[type=number]无法显示非数字字符的问题
2017/02/28 Javascript
Vue中的ref作用详解(实现DOM的联动操作)
2017/08/21 Javascript
小程序实现列表删除功能
2018/10/30 Javascript
重学JS之显示强制类型转换详解
2019/06/30 Javascript
vue+element导航栏高亮显示的解决方式
2019/11/12 Javascript
JS制作简易计算器的实例代码
2020/07/04 Javascript
[54:58]完美世界DOTA2联赛PWL S2 LBZS vs Rebirth 第一场 11.25
2020/11/25 DOTA
简单的Python抓taobao图片爬虫
2014/10/26 Python
Python基于scrapy采集数据时使用代理服务器的方法
2015/04/16 Python
python从sqlite读取并显示数据的方法
2015/05/08 Python
Python浅复制中对象生存周期实例分析
2018/04/02 Python
python中break、continue 、exit() 、pass终止循环的区别详解
2019/07/08 Python
pytorch torchvision.ImageFolder的用法介绍
2020/02/20 Python
Django自定义全局403、404、500错误页面的示例代码
2020/03/08 Python
Python操作MySQL数据库的示例代码
2020/07/13 Python
如何通过python计算圆周率PI
2020/11/11 Python
HTML5中实现拖放效果无须借助javascript
2012/12/26 HTML / CSS
Nike瑞士官网:Nike CH
2021/01/18 全球购物
大学生毕业求职的自我评价
2013/09/29 职场文书
销售文员的岗位职责
2013/11/20 职场文书
服务标兵事迹材料
2014/05/04 职场文书
物业消防安全责任书
2014/07/23 职场文书
2015年幼儿教师个人工作总结
2015/05/20 职场文书
如何起草一份正确的合伙创业协议书?
2019/07/04 职场文书
Django路由层如何获取正确的url
2021/07/15 Python
vue项目中的支付功能实现(微信支付和支付宝支付)
2022/02/18 Vue.js