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 相关文章推荐
jquery选择器(常用选择器说明)
Sep 28 Javascript
JS实现鼠标经过好友列表中的好友头像时显示资料卡的效果
Jul 02 Javascript
node.js中使用q.js实现api的promise化
Sep 17 Javascript
AngularJs解决跨域问题案例详解(简单方法)
May 19 Javascript
jQuery ready()和onload的加载耗时分析
Sep 08 Javascript
Vue实现一个返回顶部backToTop组件
Jul 25 Javascript
webpack多页面开发实践
Dec 18 Javascript
vue、react等单页面项目应该这样子部署到服务器
Jan 03 Javascript
在react中使用vuex的示例代码
Jul 30 Javascript
使用flow来规范javascript的变量类型
Sep 12 Javascript
js实现随机点名器精简版
Jun 29 Javascript
JavaScript+HTML实现学生信息管理系统
Apr 20 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
Thinkphp+smarty+uploadify实现无刷新上传
2015/07/30 PHP
Yii中创建自己的Widget实例
2016/01/05 PHP
php把时间戳转换成多少时间之前函数的实例
2016/11/16 PHP
TP5框架实现上传多张图片的方法分析
2020/03/29 PHP
javascript之可拖动的iframe效果代码
2008/08/01 Javascript
javascript 浏览器检测代码精简版
2010/03/04 Javascript
jquery动态加载js三种方法实例
2013/08/03 Javascript
jQuery防止click双击多次提交及传递动态函数或多参数
2014/04/02 Javascript
js实现鼠标拖拽多选功能示例
2017/08/01 Javascript
Vue组件之全局组件与局部组件的使用详解
2017/10/09 Javascript
vue组件父子间通信详解(三)
2017/11/07 Javascript
javascript 通过键名获取键盘的keyCode方法
2017/12/31 Javascript
JavaScript设计模式之工厂模式简单实例教程
2018/07/03 Javascript
JS封装的模仿qq右下角消息弹窗功能示例
2018/08/22 Javascript
JS继承定义与使用方法简单示例
2020/02/19 Javascript
基于javascript原生判断DOM是否加载完毕
2020/10/14 Javascript
简单谈谈python中的Queue与多进程
2016/08/25 Python
python爬虫selenium和phantomJs使用方法解析
2019/08/08 Python
Python API自动化框架总结
2019/11/12 Python
简单介绍一下pyinstaller打包以及安全性的实现
2020/06/02 Python
Python如何读写CSV文件
2020/08/13 Python
CSS3 中filter(滤镜)属性使用详解
2020/04/07 HTML / CSS
HTML5使用DOM进行自定义控制示例代码
2013/06/08 HTML / CSS
斯凯奇美国官网:SKECHERS美国
2016/08/20 全球购物
Doyoueven官网:澳大利亚健身服饰和配饰品牌
2019/03/24 全球购物
伦敦鲜花递送:Flower Station
2021/02/03 全球购物
电大物流学生的自我评价
2013/10/25 职场文书
超级搞笑检讨书
2014/01/15 职场文书
违反校纪校规检讨书
2014/02/15 职场文书
党员承诺书格式
2014/05/21 职场文书
法学求职信
2014/06/22 职场文书
中专生自荐信
2014/06/25 职场文书
纪念九一八事变83周年国旗下讲话稿
2014/09/15 职场文书
PHP对接阿里云虚拟号的实现(号码隐私保护)
2021/04/06 PHP
Spring Security中用JWT退出登录时遇到的坑
2021/10/16 Java/Android
详解NumPy中的线性关系与数据修剪压缩
2022/05/25 Python