本demo主要目的是对全球的新冠病例新增数据进行动态可视化,底层用的是echarts [1],数据来自Hopkins [2]。
效果如下:
首先看一下echarts代码的结构:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts</title>
<!-- 引入 echarts.js -->
<script src="incubator-echarts-4.9.0/dist/echarts.min.js"></script>
<script src="incubator-echarts-4.9.0/map/js/world.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 100%;height:600px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
var symbol = "/asset/get/s/data-1541516737897-uvYNg2ec4.png";
var data2 =
[
{'date': '2020.1.20', //2020年1月20日全球各国新增新冠病例
'data':
[{'name': 'China', 'value':77.0},
{'name': 'Dem. Rep. Korea', 'value':1.0},
......//此处填补所有国家的数据
{'name': 'Saint Helena', 'value':0.0}
]
},
{'date': '2020.1.21', //2020年1月21日全球各国新增新冠病例
'data':
[{'name': 'China', 'value':77.0},
{'name': 'Dem. Rep. Korea', 'value':1.0},
......
{'name': 'Saint Helena', 'value':0.0}
]
}
......//此处填补所有日期的全球新冠数据
];
var data = data2;
var geoCoordMap3 = {
'Afghanistan': [67.709953, 33.93911],
'Aland Islands': [39.390897, -99.066067],
......//此处为所有国家的信息,一定注意这里的国家名称与上面json数据中的国家名称要一致
'Central African Rep.': [6.1428, 20.399599]
};
var geoCoordMap = geoCoordMap3;
function formatNum(strNum) {
strNum = strNum.toFixed(0)
if (strNum.length <= 3) {
return strNum;
}
if (!/^(\+|-)?(\d+)(\.\d+)?$/.test(strNum)) {
return strNum;
}
var a = RegExp.$1,
b = RegExp.$2,
c = RegExp.$3;
var re = new RegExp();
re.compile("(\\d)(\\d{3})(,|$)");
while (re.test(b)) {
b = b.replace(re, "$1,$2$3");
}
return a + "" + b + "" + c;
};
function topN(N) {
var dataRaw = [];
for (var i = 0; i < data.length; i++) {
dataRaw[i] = {};
dataRaw[i].date = data[i].date;
dataRaw[i].data = data[i].data.slice(0, N);
}
return dataRaw;
};
var dataTopN = topN(10);
//alert(dataTopN[0].data['name'])
var convertData = function(data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name];
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(Math.round(data[i].value))
});
}
}
return res;
};
var showList = [];//['South Africa', 'United States', 'Russia', 'China', 'Australia', 'India', 'Zimbabwe', 'Nigeria', 'Brazil', 'Greenland']
var convertData2 = function(data) {
var res = [];
for (var i = 0; i < data.length; i++) {
if (showList.indexOf(data[i].name) > -1) {
var geoCoord = geoCoordMap[data[i].name];
res.push({
name: data[i].name,
value: geoCoord.concat(Math.round(data[i].value))
});
}
}
return res;
};
option = {
baseOption: {
backgroundColor: new echarts.graphic.RadialGradient(0.3, 0.3, 0.8, [{
offset: 0,
color: '#f7f8fa'
}, {
offset: 1,
color: '#cdd0d5'
}]),
title: [{
// text: '全球新冠累计病例',
// subtext: '单位:人数',
left: 'center',
top: '5%',
textStyle: {
fontSize: 30,
color: 'rgba(23,23,31, 0.7)',
textShadowColor: '(0,0,0,0.3)',
textShadowBlur: 5,
textShadowOffsetX: 2,
textShadowOffsety: 4
}
},
{
id: 'top 10',
test: ''
}
],
visualMap: {
min: 0,
max: 10000,
show: false,
left: 'left',
top: 'bottom',
text: ['高', '低'], // 文本,默认为数值文本
calculable: true,
seriesIndex: [0,2],
inRange: {
color: ['rgba(255,255,255,1)', 'rgba(129,0,0,1)'],
//color: ['rgba(255,255,255,0.4)', 'rgba(129,0,0,1)'],
//symbolSize: [10, 50]
}
},
timeline: {
show: false,
axisType: 'category',
orient: 'vertical',
autoPlay: true,
loop: false,
// inverse: true,
playInterval: 200,
left: null,
right: 30,
top: 330,
bottom: 100,
// width: 46,
height: null,
label: {
normal: {
show: true,
interval: 0,
},
},
symbol: 'none',
lineStyle: {
color: '#ccc',
show: false
},
checkpointStyle: {
symbol: 'none',
color: '#bbb',
borderColor: '#777',
show: false,
borderWidth: 1
},
controlStyle: {
showNextBtn: false,
showPrevBtn: false,
normal: {
color: '#666',
show: false,
borderColor: '#666'
},
emphasis: {
color: '#aaa',
borderColor: '#aaa'
}
},
data: data.map(function(ele) {
return ele.date
})
},
grid: {
left: '6%',
right: '70%',
top: '65%',
height: 'auto',
bottom: '6%'
},
xAxis: {},
yAxis: {},
geo: {
map: 'world',
show: true,
roam: true,
label: {
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: '#ffffff',
borderColor: '#1773c3',
shadowColor: '#ffffff',
shadowBlur: 1
}
},
top: '16%',
bottom: '5%'
},
series: [{
name: '底图',
type: 'map',
mapType: 'world',
roam: true,
top: '16%',
bottom: '5%',
label: {
normal: {
show: true,
formatter: '{c}',
color: 'rgba(220,220,220,1)'
},
emphasis: {
show: true
}
},
itemStyle: {
normal: {
areaColor: '#ffffff',
borderColor: '#1773c3',
shadowColor: '#ffffff',
shadowBlur: 20,
opacity: 0.6
}
},
data: []
},
{
name: '前5',
type: 'effectScatter',
coordinateSystem: 'geo',
data: [],
},
{
id: 'bar',
type: 'bar',
data: []
}
]
},
options: []
}
for (var i = 0; i < data.length; i++) {
option.options.push({
title: [{
text: "全球新增确诊新冠病例分布 "+data[i].date
},
{
id: 'top 10',
text: 'Top 10',
left: '6%',
right: '70%',
top: '60%',
height: 'auto',
bottom: '6%'
}
],
xAxis: {
show: false,
axisLine: {
show: false,
lineStyle: {
color: 'rgba(121,121,121,0.3)'
//color:'red'
}
},
splitLine: {
show: false
}
},
yAxis: {
type: 'category',
axisTick: {
show: false
},
axisLine: {
show: false,
lineStyle: {
color: 'rgba(121,121,121,0.3)'
//color:'red'
}
},
axisLabel: {
show: false,
textStyle: {
// color: '#ddd'
}
},
data: dataTopN[i].data.map(function(ele) {
return ele.name
}).reverse()
},
geo: {
map: 'world',
show: true,
roam: true,
label: {
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: '#ffffff',
borderColor: '#1773c3',
shadowColor: '#ffffff',
shadowBlur: 20
}
}
},
series: [{
label: {
normal: {
show: false,
formatter: '{c}'
},
emphasis: {
show: true
}
},
data: data[i].data
//data:dataTopN[i].data
},
{
name: '前10',
type: 'effectScatter',
coordinateSystem: 'geo',
data: convertData2(data[i].data),
// data: convertData(dataTopN[i].data),
symbolSize: 1,
// color: (238,25,27,1),
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
label: {
normal: {
formatter: function(p) {
return p.name + ' : ' + formatNum(p.value[2])
},
position: 'right',
show: true,
color: 'white',
fontSize: 15,
fontWeight: 'bold',
// textBorderColor: (0,0,0,1),
shadowColor: 'black',
shadowBlur: 10
}
},
// itemStyle: {
// normal: {
// color: '#f4e925',
// shadowBlur: 1,
// shadowColor: '#333'
// }
// },
zlevel: 1
},
{
id: 'bar',
itemStyle: {
normal: {
color: 'rgba(140, 140, 140, 0)',
label: {
show: true
},
}
},
label: {
normal: {
position: 'insideLeft',
formatter: function(p) {
return p.name + ' : ' + formatNum(Math.round(p.value))
},
color: '#6f3071'
}
},
data: dataTopN[i].data.map(function(ele) {
return ele.value
}).reverse()//从大到小排列 2020-12-05
//.sort(function(a, b) {
// return a > b
//})
}
]
})
}
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
其实通过全球新增新冠病例的趋势发现,最早的暴发集中于北纬30°~北纬50°之间 [3]。
[1] Echarts. http://echarts.apache.org/zh/index.html
[2] Johns Hopkins University Center for Systems Science and Engineering (JHU CSSE). COVID-19 Data. https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_time_series.
[3] Sajadi MM, Habibzadeh P, Vintzileos A, Shokouhi S, Miralles-Wilhelm F, Amoroso A. Temperature, Humidity, and Latitude Analysis to Estimate Potential Spread and Seasonality of Coronavirus Disease 2019 (COVID-19). JAMA Netw Open. 2020 Jun 1;3(6):e2011834. doi: 10.1001/jamanetworkopen.2020.11834.