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 相关文章推荐
js 获取和设置css3 属性值的实现方法
May 06 Javascript
js父窗口关闭时子窗口随之关闭完美解决方案
Apr 29 Javascript
如何用jQuery实现ASP.NET GridView折叠伸展效果
Sep 26 Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
Dec 12 Javascript
jQuery实现级联下拉框实战(5)
Feb 08 Javascript
JS区分Object与Aarry的六种方法总结
Feb 27 Javascript
jQuery实现选中行变色效果(实例讲解)
Jul 06 jQuery
用js屏蔽被http劫持的浮动广告实现方法
Aug 10 Javascript
轻松理解vue的双向数据绑定问题
Oct 30 Javascript
利用Angular7开发一个Radio组件的全过程
Jul 11 Javascript
js+css实现扇形导航效果
Aug 18 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
基于php无限分类的深入理解
2013/06/02 PHP
关于ob_get_contents(),ob_end_clean(),ob_start(),的具体用法详解
2013/06/24 PHP
解析func_num_args与func_get_args函数的使用
2013/06/24 PHP
PHP简单实现循环链表功能示例
2017/11/10 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
2019/10/17 PHP
JQuery1.6 使用方法三
2011/11/23 Javascript
javascript中callee与caller的区别分析
2015/04/20 Javascript
浅谈JavaScript的Polymer框架中的事件绑定
2015/07/29 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
2016/02/19 Javascript
Javascript基础知识盲点总结之函数
2016/05/15 Javascript
Bootstrap学习笔记之js组件(4)
2016/06/12 Javascript
深入理解node.js之path模块
2017/05/03 Javascript
Javascript实现倒计时时差效果
2017/05/18 Javascript
JavaScript 通过Ajax 动态加载CheckBox复选框
2017/08/31 Javascript
浅谈React和Redux的连接react-redux
2017/12/04 Javascript
JavaScript设计模式之调停者模式实例详解
2018/02/03 Javascript
AjaxUpLoad.js实现文件上传功能
2018/03/02 Javascript
详解vuejs2.0 select 动态绑定下拉框支持多选
2019/04/25 Javascript
JS async 函数的含义和用法实例总结
2020/04/08 Javascript
javascript前端和后台进行数据交互方法示例
2020/08/07 Javascript
python实现点对点聊天程序
2018/07/28 Python
python使用xlrd和xlwt读写Excel文件的实例代码
2018/09/05 Python
Python实现删除排序数组中重复项的两种方法示例
2019/01/31 Python
Python学习笔记之读取文件、OS模块、异常处理、with as语法示例
2019/06/04 Python
python 多线程对post请求服务器测试并发的方法
2019/06/13 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
2020/09/09 Python
python3爬虫中多线程的优势总结
2020/11/24 Python
纯CSS3+DIV实现小三角形边框效果的示例代码
2020/08/03 HTML / CSS
企业行政文员岗位职责
2013/12/03 职场文书
机械专业应届生求职信
2013/12/12 职场文书
解除劳动合同证明书
2014/09/26 职场文书
音乐会主持人开场白
2015/05/28 职场文书
小时代观后感
2015/06/10 职场文书
高中班主任培训心得体会
2016/01/07 职场文书
图片批量处理 - 尺寸、格式、水印等
2022/03/07 杂记