疫情数据地图展示
中国地图的实现
先看一下效果图吧。
整个项目是在vue框架下完成的,在完成了路由配置后,就可以开始做地图的展示部分了。在这里只展示国内疫情部分也就是我自己独立完成的部分。
地图样式
地图的部分主要是用的echart插件来封装完成的。具体的地图的option如下
getMapOpt(place) {
let option = option = {
title:{
text:"现有确诊不包含死亡病例和治愈病例",
textStyle:{
color:"#ccc",
fontSize:16,
fontWeight:'normal'
},
left:'center',
top:'10'
},
textStyle: {
fontSize: 10
},
tooltip: {
trigger: 'item',
formatter: function(params) {
//console.log(params);
return (params.data.name + "<br>现有确诊:" + params.data.value)
}
},
visualMap: {
type: 'piecewise',
pieces: [{
gte: 10000,
color: '#B80909'
},
{
gte: 1000,
lte: 9999,
color: '#E85B5B'
},
{
gte: 100,
lte: 999,
color: '#F57567'
},
{
gte: 10,
lte: 99,
color: '#FF9985'
},
{
gte: 1,
lte: 9,
color: '#FFE5DB'
},
{
value: 0,
color: '#fff'
}
],
},
series: [{
name: '确诊数量',
type: 'map',
mapType: place ? place : 'china',
roam: true,
zoom: 1,
label: {
normal: {
show: true
}
},
emphasis: {
itemStyle: {
areaColor: "#95F3F1",
},
label: {
color: "#fff"
}
},
data:this.initdata(place)
}]
}
return option
},
option里面的data部分,我用initdata函数做了处理 ,这个放在后面陈述。配置好option后,就可以看到灰色的中国地图。接下来就是填充数据。
数据填充
首先准备好json 文件,我的json文件是调用了网上的免费接口,然后打印出来复制到本地得到的。嗯,废话不多说,调用json文件,存到data里面。由于echart地图的格式与json的格式不一,所以再拿到数据后还是需要重新赋值一次。对数据处理的代码如下。
getHomeInfo(){
/* axios.get('static/mock/China.json')
.then(this.getHomeInfoSucc) */
axios.get('http://localhost:3000/chinalist')
.then(this.getHomeInfoSucc).then(this.initMap())
},
getHomeInfoSucc(res){
res = res.data
// console.log(res);
if( res.data){
const data = res.data
// console.log(data);
for (var i = 0;i< data.Chinalist.length;i++)
{
this.confirmedlist.push({
name:data.Chinalist[i].provinceShortName,
value:data.Chinalist[i].confirmedCount,
cities:[
data.Chinalist[i].cities
]
})
}
}
// console.log(this.rightdata);
},
由于后面还要 实现地图下沉的功能,所以我在这里也获取了省级地图的数据。拿到数据后,在option里面给data赋值就好了。由于我这里只有最终完成的代码,可以看到上方描述的地图样式代码中的data是initdata()。在没有做地图下沉的时候,自己填充this.confirmedlist即可。
我的json文件结构如下:
{
"data": {
"Chinalist": [{
"provinceName": "香港",
"provinceShortName": "香港",
"currentConfirmedCount": 51,
"confirmedCount": 1093,
"suspectedCount": 63,
"curedCount": 1038,
"deadCount": 4,
"comment": "疑似1例",
"locationId": 810000,
"cities": []
}, {
"provinceName": "内蒙古自治区",
"provinceShortName": "内蒙古",
"currentConfirmedCount":0,
"confirmedCount": 77,
"suspectedCount": 0,
"curedCount": 76,
"deadCount": 1,
"comment": "",
"locationId": 150000,
"cities": [ {
"cityName": "鄂尔多斯市",
"currentConfirmedCount": 0,
"confirmedCount": 11,
"suspectedCount": 0,
"curedCount": 11,
"deadCount": 0,
"locationId": 150600
}
}]
}]
}
地图下沉
在实现地图下沉之前,需要拿到中国所有省份的地图json文件。大致思路就是,点击了地图 之后拿到echart地图param参数,根据点击的省份名称去重新加载省份的地图和省份城市的数据。在设置option的时候传入拿到的省份名称的参数,就可以显示出对应的省份地图。代码如下
<script>
import axios from 'axios'
import echarts from 'echarts'
import "echarts/map/js/china.js"
var provinces = ['shanghai', 'hebei', 'shanxi1', 'neimenggu', 'liaoning',
'jilin', 'heilongjiang', 'jiangsu','zhejiang', 'anhui',
'fujian', 'jiangxi', 'shandong', 'henan', 'hubei',
'hunan', 'guangdong', 'guangxi', 'hainan', 'sichuan',
'guizhou', 'yunnan', 'xizang', 'shanxi', 'gansu',
'qinghai', 'ningxia', 'xinjiang', 'beijing',
'tianjin', 'chongqing', 'xianggang', 'aomen', 'taiwan'
];
var provincesText = ['上海', '河北', '山西', '内蒙古', '辽宁',
'吉林', '黑龙江', '江苏', '浙江', '安徽',
'福建', '江西', '山东', '河南', '湖北', '湖南',
'广东', '广西', '海南', '四川', '贵州', '云南',
'西藏', '陕西', '甘肃', '青海', '宁夏', '新疆',
'北京', '天津', '重庆', '香港', '澳门', '台湾'
];
export default {
name: 'mapcurrent',
data(){
return{
cities:[]
}
},
methods: {
initdata(place){
var provinceIndex
for(var i in provinces){
if(provinces[i] === place)
{
provinceIndex = i
}
}
place = provincesText[provinceIndex]
if(place){
var list = JSON.parse(this.$route.query.currentlist);
var index;
for (var i in list){
//console.log(i);
var name = list[i].name
if(name === place){
index = i;
}
}
var cities = list[index].cities[0]
//console.log(list[3].cities);
for (var i of cities)
{
//console.log(i)
this.cities.push({
name:i.cityName,
value:i.currentConfirmedCount
})
}
//console.log(this.cities);
return this.cities
}
else{
return JSON.parse(this.$route.query.currentlist)
}
},
getMapOpt(place) {
let option = option = {
title:{
text:"现有确诊不包含死亡病例和治愈病例",
textStyle:{
color:"#ccc",
fontSize:16,
fontWeight:'normal'
},
left:'center',
top:'10'
},
textStyle: {
fontSize: 10
},
tooltip: {
trigger: 'item',
formatter: function(params) {
//console.log(params);
return (params.data.name + "<br>现有确诊:" + params.data.value)
}
},
visualMap: {
type: 'piecewise',
pieces: [{
gte: 10000,
color: '#B80909'
},
{
gte: 1000,
lte: 9999,
color: '#E85B5B'
},
{
gte: 100,
lte: 999,
color: '#F57567'
},
{
gte: 10,
lte: 99,
color: '#FF9985'
},
{
gte: 1,
lte: 9,
color: '#FFE5DB'
},
{
value: 0,
color: '#fff'
}
],
},
series: [{
name: '确诊数量',
type: 'map',
mapType: place ? place : 'china',
roam: true,
zoom: 1,
label: {
normal: {
show: true
}
},
emphasis: {
itemStyle: {
areaColor: "#95F3F1",
},
label: {
color: "#fff"
}
},
data:this.initdata(place)
}]
}
return option
},
//显示中国地图
showChinaMap() {
let option = this.getMapOpt()
this.map.setOption(option, true);
},
//显示各省地图
getProvinceMapOpt(provinceAlphabet) {
axios.get('http://localhost:3000/province',{
params:{
province:provinceAlphabet
}
}).then((s) => {
echarts.registerMap(provinceAlphabet, s.data)
let option = this.getMapOpt(provinceAlphabet)
this.map.setOption(option, true);
})
},
initMap() {
this.map = echarts.init(this.$refs.chart1);
let option = this.getMapOpt()
if (option && typeof option === "object") {
this.map.setOption(option, true);
}
this.map.on('click', (param) => {
event.stopPropagation() // 阻止冒泡
// 找到省份名
let provinceIndex = provincesText.findIndex(x => {
return param.name === x
})
if (provinceIndex === false) return
let provinceAlphabet = provinces[provinceIndex]
// 重新渲染各省份地图
this.getProvinceMapOpt(provinceAlphabet)
})
}
},
created() {
},
mounted() {
this.$nextTick(function(){
this.initMap();
})
},
}
</script>
代码中initdata函数部分,是对接收的数据部分的处理。
后台
后台部分就比较简单,直接上代码吧
var express = require("express"); //首先引入express模块,不了解去看nodejs教程 安装:npm install express
var app = express();
var fs = require("fs"); // 文件系统,引入user.json的数据 也可以自己随便写个数据 ;
var path = require('path');
var cors = require("cors");// 这个比较重要,解决跨域问题.npm install cors 装一下
app.use(cors({
origin: ['http://localhost:8080'], // 这是本地的默认地址和端口,vue启动的项目就是在这里,这样保证了等会我们在浏览器能访问服务器的数据(user.json)
methods: ["GET", "POST"],
alloweHeaders: ["Content-Type", "Authorization"]
}))
app.get("/chinalist", function (req, res) { //"/user" 是自定义的,用于显示在地址栏
fs.readFile(__dirname + "/" + "China.json", "utf-8", function (err, data) { // __dirname是文件夹的名,我们用fs读取China.json
res.end(data) // 然后把读取的文件通过 res.end()发送给客户端
})
const url= require('url');
app.get("/province",function(req,res){
var province = url.parse(req.url,true).query.province;
fs.readFile(__dirname+"/"+"province"+"/"+province+".json","utf-8",function(err,data){
res.end(data)
})
})
});
var server = app.listen(3000, function () { // 设置服务端端口为3000,即:http://127.0.0.1:3000
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
可以看到,当点击到省份地图的时候,就用传递的参数来决定获取省份的json文件。注意获取请求参数,需要调用一下parse方法。
两侧排名实现
对于两侧的排名实现,就是拿到数据之后,直接展示就可以了。值得一提的是,根据某个对象属性对数组排序。代码如下:
<script>
function sortKey(array,key){
return array.sort(function(a,b){
var x = a[key];
var y = b[key];
if(x<y){
return 1
}else if(x>y){
return -1
}else {
return 0
}
})
}
export default{
name:"LeftMap",
props:{
top50:Array,
},
computed:{
sortList(){
return sortKey(this.top50,"confirmedCount")
}
}
}
</script>
然后展示出来就可以了
<ul>
<div class="title">国内全省累计确诊病例 </div>
<li v-for="(item,index) in sortList">
<div class="num">Top{{index+1}} {{item.confirmedCount}}</div>
<div class="cityname">疫情地区:{{item.name}}</div>
</li>
</ul>
关于echart的饼图和左侧时间的显示比较简单,我就不在这里多说了,关于echart地图的配置可以去官网上面看,另外官网上也有很多实例。
码字不易,点个赞吧。