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

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

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

先看一下效果:

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

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

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

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

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

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

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

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

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

  1 <template>
2 <div id="china_map_box">
3 <el-button type="primary" size="mini" class="back" @click="back" v-if="deepTree.length > 1">返回</el-button>
4 <div class="echarts">
5 <div id="map"></div>
6 </div>
7 </div>
8 </template>
9
10 <script>
11
12 import {getChinaJson, getProvinceJSON, getCityJSON} from "../api/get-json";
13 import {cityProvincesMap} from '../config/cityProvincesMap'
14 import {mapOption} from '../config/mapOption'
15
16
17 export default {
18 name: "china",
19 components: {},
20 data() {
21 return {
22 chart: null, // 实例化echarts
23 provincesMap: cityProvincesMap.provincesMap, // 省拼音,用于查找对应json
24 provincesCode: cityProvincesMap.provincesCode, // 市行政区划,用于查找对应json
25 areaMap: cityProvincesMap.areaMap, // 省行政区划,用于数据的查找,按行政区划查数据
26 special: ["北京市", "天津市", "上海市", "重庆市", "香港", "澳门"],//直辖市和特别行政区-只有二级地图,没有三级地图
27 mapData: [], // 当前地图上的地区
28 option: {...mapOption.basicOption}, // map的相关配置
29 deepTree: [],// 点击地图时push,点返回时pop
30 areaName: '中国', // 当前地名
31 areaCode: '000000', // 当前行政区划
32 areaLevel: 'country', // 当前级别
33 }
34 },
35 mounted() {
36 this.$nextTick(() => {
37 this.initEcharts();
38 this.chart.on('click', this.echartsMapClick);
39 });
40 },
41 methods: {
42 // 初次加载绘制地图
43 initEcharts() {
44 //地图容器
45 this.chart = this.$echarts.init(document.getElementById('map'));
46 if (this.areaCode === '000000') {
47 this.requestGetChinaJson();
48 } else {
49 this.requestGetProvinceJSON({areaName: this.areaName, areaCode: this.areaCode})
50 }
51 },
52 // 地图点击
53 echartsMapClick(params) {
54 // console.log(params);
55 this.areaName = params.areaName;
56 if (params.name in this.provincesMap) {
57 this.areaCode = params.data.areaCode;
58 this.areaLevel = params.data.areaLevel;
59 //如果点击的是34个省、市、自治区,绘制选中地区的二级地图
60 this.requestGetProvinceJSON(params.data);
61 } else if (params.seriesName in this.provincesMap) {
62 //如果是【直辖市/特别行政区】只有二级下钻
63 if (this.special.indexOf(params.seriesName) >= 0) {
64 return;
65 } else {
66 this.areaCode = this.areaMap[params.name];
67 this.areaLevel = params.data.areaLevel;
68 //显示县级地图
69 this.requestGetCityJSON(params.data)
70 }
71 } else {
72 return;
73 }
74 this.$emit('map-change', params.data);
75 },
76 //绘制全国地图
77 requestGetChinaJson() {
78 getChinaJson().then(res => {
79 let arr = [];
80 for (let i = 0; i < res.features.length; i++) {
81 let obj = {
82 name: res.features[i].properties.name,
83 areaName: res.features[i].properties.name,
84 areaCode: res.features[i].id,
85 areaLevel: 'province',
86 value: Math.round(Math.random()),
87 };
88 arr.push(obj)
89 }
90 this.mapData = arr;
91 this.deepTree.push({
92 mapData: arr,
93 params: {name: 'china', areaName: 'china', areaLevel: 'country', areaCode: '000000'}
94 });
95 //注册地图
96 this.$echarts.registerMap('china', res);
97 //绘制地图
98 this.renderMap('china', arr);
99 });
100 },
101 // 加载省级地图
102 requestGetProvinceJSON(params) {
103 getProvinceJSON(params.areaCode).then(res => {
104 this.$echarts.registerMap(params.areaName, res);
105 let arr = [];
106 for (let i = 0; i < res.features.length; i++) {
107 let obj = {
108 name: res.features[i].properties.name,
109 areaName: res.features[i].properties.name,
110 areaCode: res.features[i].id,
111 areaLevel: 'city',
112 value: Math.round(Math.random()),
113 };
114 arr.push(obj)
115 }
116 this.mapData = arr;
117 this.deepTree.push({
118 mapData: arr,
119 params: params,
120 });
121 this.renderMap(params.areaName, arr);
122 });
123 },
124 // 加载市级地图
125 requestGetCityJSON(params) {
126 this.areaLevel = params.areaLevel;
127 getCityJSON(params.areaCode).then(res => {
128 this.$echarts.registerMap(params.areaName, res);
129 let arr = [];
130 for (let i = 0; i < res.features.length; i++) {
131 let obj = {
132 name: res.features[i].properties.name,
133 areaName: res.features[i].properties.areaName,
134 areaCode: res.features[i].id,
135 areaLevel: 'districts',
136 value: Math.round(Math.random()),
137 };
138 arr.push(obj)
139 }
140 this.mapData = arr;
141 this.deepTree.push({mapData: arr, params: params});
142 this.renderMap(params.areaName, arr);
143 })
144 },
145 renderMap(map, data) {
146 this.option.series = [
147 {
148 name: map,
149 mapType: map,
150 ...mapOption.seriesOption,
151 data: data
152 }
153 ];
154 //渲染地图
155 this.chart.setOption(this.option);
156 },
157 // 返回
158 back() {
159 // console.log(this.deepTree);
160 if (this.deepTree.length > 1) {
161 this.deepTree.pop();
162 let areaName = this.deepTree[this.deepTree.length - 1].params.areaName;
163 let mapData = this.deepTree[this.deepTree.length - 1].mapData;
164 this.$emit('back-change', this.deepTree[this.deepTree.length - 1].params);
165 this.renderMap(areaName, mapData);
166 }
167 }
168 }
169 }
170
171 </script>
172
173 <style lang="scss" scoped>
174 #china_map_box {
175 display: flex;
176 width: 100%;
177 height: 100%;
178 position: relative;
179 .echarts {
180 width: 0;
181 flex: 1;
182 background-size: 100% 100%;
183 #map {
184 height: 100%;
185 }
186 }
187 .back {
188 position: absolute;
189 top: .8rem;
190 right: .5rem;
191 z-index: 999;
192 padding-left: .12rem;
193 padding-right: .12rem;
194
195 }
196 }
197
198 </style>

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

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

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

  1 <template>
2 <div id="china_map_box">
3 <el-button type="primary" size="mini" class="back" @click="back">返回</el-button>
4 <div class="map" >
5 <map-range @change="search"></map-range>
6 </div>
7 <div class="echarts">
8 <div id="map"></div>
9 </div>
10 </div>
11 </template>
12
13 <script>
14 import mapRange from "./mapRange";
15
16 export default {
17 name: "chinaGaode",
18 components: {
19 mapRange
20 },
21 data() {
22 return {
23 provinceSelect: null,
24 citySelect: null,
25 districtSelect: null,
26 areaName: '中国',
27 geoJsonData: '',
28 echartsMap: null,
29 map: null,
30 district: null,
31 polygons: [],
32 areaCode: 100000,
33 opts: {},
34 areaData: {},
35 mapData: [],
36 deepTree:[],
37 }
38 },
39 mounted() {
40 this.provinceSelect = document.getElementById('province');
41 this.citySelect = document.getElementById('city');
42 this.districtSelect = document.getElementById('district');
43 this.deepTree = [{mapData: this.mapData,code: 100000}];
44 this.echartsMap = this.$echarts.init(document.getElementById('map'));
45 this.echartsMap.on('click', this.echartsMapClick);
46 this.map = new AMap.Map('container', {
47 resizeEnable: true,
48 center: [116.30946, 39.937629],
49 zoom: 3
50 });
51 this.opts = {
52 subdistrict: 1, //返回下一级行政区
53 showbiz: false //最后一级返回街道信息
54 };
55 this.district = new AMap.DistrictSearch(this.opts);//注意:需要使用插件同步下发功能才能这样直接使用
56 this.district.search('中国', (status, result) => {
57 if (status == 'complete') {
58 this.getData(result.districtList[0], '', 100000);
59 }
60 });
61 },
62 methods: {
63 //地图点击事件
64 echartsMapClick(params) {
65 if (params.data.level == 'street') return;
66 //清除地图上所有覆盖物
67 for (var i = 0, l = this.polygons.length; i < l; i++) {
68 this.polygons[i].setMap(null);
69 }
70 this.areaName = params.data.name;
71 this.areaCode = params.data.areaCode;
72 this.district.setLevel(params.data.level); //行政区级别
73 this.district.setExtensions('all');
74 //行政区查询
75 //按照adcode进行查询可以保证数据返回的唯一性
76 this.district.search(this.areaCode, (status, result) => {
77 if (status === 'complete') {
78 this.deepTree.push({mapData: this.mapData,code: params.data.areaCode});
79 this.getData(result.districtList[0], params.data.level, this.areaCode);
80 }
81 });
82 this.$emit('map-change', params.data);
83 },
84 loadMapData(areaCode) {
85 AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
86 //创建一个实例
87 var districtExplorer = window.districtExplorer = new DistrictExplorer({
88 eventSupport: true, //打开事件支持
89 map: this.map
90 });
91 districtExplorer.loadAreaNode(areaCode, (error, areaNode) => {
92 if (error) {
93 console.error(error);
94 return;
95 }
96 let mapJson = {};
97 mapJson.type = "FeatureCollection";
98 mapJson.features = areaNode.getSubFeatures();
99 this.loadMap(this.areaName, mapJson);
100 this.geoJsonData = mapJson;
101 });
102 });
103 },
104 loadMap(mapName, data) {
105 if (data) {
106 this.$echarts.registerMap(mapName, data);
107 var option = {
108
109 visualMap: {
110 type: 'piecewise',
111 pieces: [
112 {max: 1, label: '审核完成', color: '#2c9a42'},
113 {min: -1, max: 1, label: '未完成', color: '#d08a00'},
114 // {min: 60, label: '危险', color: '#c23c33'},
115 ],
116 color: '#fff',
117 textStyle: {
118 color: '#fff',
119 },
120 visibility: 'off',
121 top:50,
122 left:30,
123 },
124 series: [{
125 name: '数据名称',
126 type: 'map',
127 roam: false,
128 mapType: mapName,
129 selectedMode: 'single',
130 showLegendSymbol: false,
131 visibility: 'off',
132 itemStyle: {
133 normal: {
134 color: '#ccc',
135 areaColor: '#fff',
136 borderColor: '#fff',
137 borderWidth: 0.5,
138 label: {
139 show: true,
140 textStyle: {
141 color: "rgb(249, 249, 249)",
142 fontSize: '1rem'
143 }
144 }
145 },
146 emphasis: {
147 areaColor: false,
148 borderColor: '#fff',
149 areaStyle: {
150 color: '#fff'
151 },
152 label: {
153 show: true,
154 textStyle: {
155 color: "rgb(249, 249, 249)"
156 }
157 }
158 }
159 },
160 data: this.mapData,
161 }]
162 };
163 this.echartsMap.setOption(option);
164 }
165 },
166 getData(data, level, adcode) {
167 var bounds = data.boundaries;
168 if (bounds) {
169 for (var i = 0, l = bounds.length; i < l; i++) {
170 var polygon = new AMap.Polygon({
171 map: this.map,
172 strokeWeight: 1,
173 strokeColor: '#0091ea',
174 fillColor: '#80d8ff',
175 fillOpacity: 0.2,
176 path: bounds[i]
177 });
178 this.polygons.push(polygon);
179 }
180 this.map.setFitView();//地图自适应
181 }
182
183 //清空下一级别的下拉列表
184 if (level === 'province') {
185 this.citySelect.innerHTML = '';
186 this.districtSelect.innerHTML = '';
187 } else if (level === 'city') {
188 this.districtSelect.innerHTML = '';
189 }
190 var subList = data.districtList;
191 if (subList) {
192 let optionName = '--请选择--';
193 var contentSub = new Option(optionName);
194 var curlevel = subList[0].level;
195 if (curlevel === 'street') {
196 let mapJsonList = this.geoJsonData.features;
197 let mapJson = {};
198 for (let i in mapJsonList) {
199 if (mapJsonList[i].properties.name == this.areaName) {
200 mapJson.type = "FeatureCollection";
201 mapJson.features = [].concat(mapJsonList[i]);
202 }
203 }
204 this.mapData = [];
205 this.mapData.push({name: this.areaName, value: 0, level: curlevel});
206 this.loadMap(this.areaName, mapJson);
207 return;
208 }
209
210 var curList = document.querySelector('#' + curlevel);
211 curList.add(contentSub);
212 this.mapData = [];
213 for (var i = 0, l = subList.length; i < l; i++) {
214 var name = subList[i].name;
215 var areaCode = subList[i].adcode;
216 this.mapData.push({
217 name: name,
218 value: Math.round(Math.random()),
219 areaCode: areaCode,
220 level: curlevel
221 });
222 var levelSub = subList[i].level;
223 contentSub = new Option(name);
224 contentSub.setAttribute("value", levelSub);
225 contentSub.center = subList[i].center;
226 contentSub.adcode = subList[i].adcode;
227 curList.add(contentSub);
228 }
229 this.loadMapData(adcode);
230 this.areaData[curlevel] = curList;
231 }
232
233 },
234 search(area) {
235 let obj = this.areaData[area];
236 //清除地图上所有覆盖物
237 for (var i = 0, l = this.polygons.length; i < l; i++) {
238 this.polygons[i].setMap(null);
239 }
240 var option = obj[obj.options.selectedIndex];
241
242 var keyword = option.text; //关键字
243 var adcode = option.adcode;
244 this.areaName = keyword;
245 this.areaCode = adcode;
246 this.district.setLevel(option.value); //行政区级别
247 this.district.setExtensions('all');
248 //行政区查询
249 //按照adcode进行查询可以保证数据返回的唯一性
250 this.district.search(adcode, (status, result) => {
251 if (status === 'complete') {
252 this.deepTree.push({mapData: this.mapData,code:adcode});
253 this.getData(result.districtList[0], obj.id, adcode);
254 }
255 });
256 var params = {
257 areaCode: adcode,
258 level: area,
259 name: keyword,
260 value: '',
261 };
262 this.$emit('map-change', params);
263 },
264 back() {
265 // console.log(this.deepTree)
266 if (this.deepTree.length > 1) {
267 this.mapData = this.deepTree[this.deepTree.length - 1].mapData;
268 this.deepTree.pop();
269 // console.log(this.deepTree[this.deepTree.length - 1], 'back');
270 this.loadMapData(this.deepTree[this.deepTree.length - 1].code)
271 }
272 }
273 }
274 }
275 </script>
276
277 <style lang="scss" scoped>
278 #china_map_box {
279 display: flex;
280 width: 100%;
281 height: 100%;
282 position: relative;
283 .echarts {
284 width: 0;
285 flex: 1;
286 background-size: 100% 100%;
287 #map {
288 height: 100%;
289 }
290 }
291 .back {
292 position: absolute;
293 top: .8rem;
294 right: .5rem;
295 z-index: 999;
296 }
297
298 }
299
300 </style>

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

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

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

vue+echarts+datav大屏数据展示及实现中国地图省市县下钻的更多相关文章

  1. vue+echarts可视化大屏,全国地图下钻,页面自适应

    之前写过一篇关于数据大屏及地图下钻的文章 https://www.cnblogs.com/weijiutao/p/13977011.html ,但是存在诸多问题,如地图边界线及行政区划老旧,无法自适应 ...

  2. 使用echarts开发电子屏数据展示页面

    背景 之前的项目因为要顾及体量问题,选用了highchart,没用上echarts:这次因为是本地部署电子屏幕的展示页,不需要考虑体量大小,直接用上了echarts:用起来觉得非常不错,特别是地图上非 ...

  3. 设备数据通过Azure Functions 推送到 Power BI 数据大屏进行展示(2.Azure Functions实战)

    本案例适用于开发者入门理解Azure Functions/ IoT Hub / Service Bus / Power BI等几款产品. 主要实战的内容为: 将设备遥测数据上传到物联网中心, 将遥测数 ...

  4. Visual-platform,基于Vue的可视化大屏开发GUI框架

    visual-platform 基于Vue的可视化大屏开发GUI框架 ------ CreatedBy 漆黑小T 构建用于开发可视化大屏项目的自适应布局的GUI框架. github仓库: https: ...

  5. 海量大数据大屏分析展示一步到位:DataWorks数据服务对接DataV最佳实践

    1. 概述 数据服务(https://ds-cn-shanghai.data.aliyun.com)  是DataWorks产品家族的一员,提供了快速将数据表生成API的能力,通过可视化的向导,一分钟 ...

  6. 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践

    1. 概述 数据服务(https://ds-cn-shanghai.data.aliyun.com) 是DataWorks产品家族的一员,提供了快速将数据表生成API的能力,通过可视化的向导,一分钟“ ...

  7. 设备数据通过Azure Functions 推送到 Power BI 数据大屏进行展示(1.准备工作)

    本案例适用于开发者入门理解Azure Functions/ IoT Hub / Service Bus / Power BI等几款产品. 主要实战的内容为: 将设备遥测数据上传到物联网中心, 将遥测数 ...

  8. 产品如何进行大屏数据可视化.md

    最近接到一个需求,需要给公司的竞赛平台面对省/校/竞赛进行大屏的可视化话数据展示,闲暇之余对自己最近的工作进行一些总结; 一.数据可视化的定义 数据可视化主要是关于数据_视觉表现形式的科学技术研究 - ...

  9. echarts.js多图表数据展示使用小结

    echarts api文档: http://echarts.baidu.com/echarts2/doc/doc.html echarts demo示例: http://echarts.baidu.c ...

随机推荐

  1. c++ 西安交通大学 mooc 第十三周基础练习&第十三周编程作业

    做题记录 风影影,景色明明,淡淡云雾中,小鸟轻灵. c++的文件操作已经好玩起来了,不过掌握好控制结构显得更为重要了. 我这也不做啥题目分析了,直接就题干-代码. 总结--留着自己看 1. 流是指从一 ...

  2. Windows下CertUtil校验和编码文件

    目录 前言 CertUtil计算文件hash 计算MD2 计算MD4 计算MD5 计算SHA1 计算SHA256 计算SHA384 计算SHA512 文件base64编码 文件base64解码 文件h ...

  3. MeteoInfoLab脚本示例:TRMM 2A12 HDF数据

    TRMM 2A12 HDF数据是卫星观测的SWATH数据(轨道数据),比格点数据处理起来要麻烦一些.数据的经纬度保存在geolocation变量中,需要先将经纬度数据读出来(均为2维数组),然后读取云 ...

  4. Linux下快速搭建测试网站DVWA

    DVWA(Damn Vulnerable Web App)是一个基于PHP/MySql搭建的Web应用程序,旨在为安全专业人员测试自己的专业技能和工具提供合法的 环境,帮助Web开发者更好的理解Web ...

  5. hugo不蒜子统计数量

    date: "2020-10-18T22:39:27+08:00" title: "hugo不蒜子统计数量" tags: ["不蒜子"] c ...

  6. 第四章 Bash Shell 的简单应用

    一.Bash Shell 的简单介绍 1.什么是bash shell? 是一个命令解释器 它在操作系统的最外面 负责用户与内核进行交互的一种接口 将用户输入的命令翻译给操作系统,并将处理后的结果输出到 ...

  7. Cypress系列(67)- 环境变量设置指南

    如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 常见的环境变量设置方式 可参考这篇文章: ...

  8. Python基础数据类型方法补充

    str 补充的方法: capitalize():首字母大写,其余变小写 s = 'liBAI' s1 = s.capitalize() print(s1) # Libai swapcase():大小写 ...

  9. JavaWeb学习笔记(六)jsp

    第六章.jsp 1.什么是jsp jsp:java server pages,java的服务器页面 作用:代替Servlet回传HTML页面的数据 因为Servlet程序回传HTML页面的数据很繁琐, ...

  10. JAVA递归实现线索化二叉树

    JAVA递归实现线索化二叉树 基础理论 首先,二叉树递归遍历分为先序遍历.中序遍历和后序遍历. 先序遍历为:根节点+左子树+右子树 中序遍历为:左子树+根节点+右子树 后序遍历为:左子树+右子树+根节 ...