vue+echarts+datav大屏資料展示及實現中國地圖省市縣下鑽功能
隨著前端技術的飛速發展,大資料時代的來臨,我們在開發專案時越來越多的客戶會要求我們做一個數據展示的大屏,可以直觀的展示使用者想要的資料,同時炫酷的介面也會深受客戶的喜歡。
大屏展示其實就是一堆的圖表能夠讓人一目瞭然地看到該系統下的一些基本資料資訊的彙總,也會有一些實時資料重新整理,資訊預警之類的。筆者在之前也做過一些大屏類的資料展示,但是由於都是一些圖表類的,覺得沒什麼可說的,加之資料也都牽扯到公司,所以沒有沉澱下來什麼。
最近有朋友要做一個大屏,問了自己一個問題,自己也剛好做了一個簡單的大屏資料展示,趁此機會做一個小總結。
先看一下效果:
由於資料牽扯到公司內部資訊,所以將一些複雜的切換邏輯都去掉類,但保留了一些資料間但相互聯動。
專案採用的是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中國地圖的程式碼如下:
<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,areaLevel: 'city',params: params,}); this.renderMap(params.areaName,// 載入市級地圖 requestGetCityJSON(params) { this.areaLevel = params.areaLevel; getCityJSON(params.areaCode).then(res => { this.$echarts.registerMap(params.areaName,areaName: res.features[i].properties.areaName,areaLevel: 'districts',}; 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檔案目錄下,如下圖:
裡面有一些自己沒用到的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,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',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,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,areaStyle: { color: '#fff' },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,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,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大屏資料展示內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!