echarts制作疫情地图
由于种种原因,需要制作一个疫情专题页面,而这个任务分配到了我头上,对于第一次接触echarts的我来说是一个巨大的挑战。所以在家,边查文档,边思考,磕磕碰碰地把地图完成了。
首先,看一下效果:
北京疫情地图 世界疫情地图用到的相关技术
- jquery
- echartsjs::https://www.echartsjs.com/zh/index.html
- 地图数据:https://github.com/cj0x39e/echarts-map-data
- 疫情数据来源于各大权威网站,这里不做过多叙述
echart地图配置
1. 引入jquery
和echarts
<script type="text/javascript" src="/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="/js/echarts.min.js"></script>
2. 设置地图显示区域以及加载地图json文件
html代码:
<style>
.map-view{
height:80px;
width:90%;
margin: 0 auto;
}
</style>
<body>
...
<div id="map-view" class="map-view" ></div>
...
</body>
加载json文件:
var myChart = echarts.init(document.getElementById('map-view'));
myChart.showLoading();
// 国内省份
var cityArr = ['beijing','北京'];
var cityNameList = []; // 地图内城市名称
$.get('/js/map/json/province/'+ cityArr[0] +'.json', function (geoJson) {
myChart.hideLoading();
echarts.registerMap(cityArr[0], geoJson);
cityNameList = geoJson.features.map(v=>{
return v.properties.name;
})
// 添加南海诸岛屿的图片
if(cityArr[1] === "海南"){
$("#map-view").append('<img class="hainan-extra" src="/images/hainan-extra.png" />')
}
myChart.setOption(option = {
// 地图具体配置
...
})
})
上面是国内省份地图,下面是世界地图的写法,当然json路径需要示具体情况而定。
// 世界地图
var cityArr = ['world','世界'];
var cityNameList = []; // 地图内国家和地区名称
$.get('/js/map/json/'+ cityArr[0] +'.json', function (geoJson) {
myChart.hideLoading();
echarts.registerMap(cityArr[0], geoJson);
cityNameList = geoJson.features.map(v=>{
return v.properties.name;
})
myChart.setOption(option = {
// 地图具体配置
...
})
})
注意:陕西和山西的拼音都是一样的,所以陕西后面带了个‘1’
{
"陕西":"shanxi1",
"山西":"shanxi"
}
3. 地图配置
这里只说明一下用到的,具体可以查看以下文章:
ECharts地图详解:https://blog.csdn.net/xieweikun7/article/details/52766676
var options = {
tooltip: { // 提示
formatter:function(params,ticket, callback){
if(!params.data){
return undefined; // 无数据时不弹出提示
}else{
return params.name
+ '<br />确诊:'+params.data.confirm
+ '<br />治愈:'+params.data.heal
+ '<br />死亡:'+params.data.dead
}
} ,// 数据格式化
visualMap: {
min: 0, // 最小值
max: 0, // 最大值
show: true,
splitNumber: 5, // 色阶切分
icon: 'rect', // 例图形状
itemWidth: 14,
itemHeight: 14,
itemGap: 2,
textStyle: { // 例图文本样式
color: '#A3A3A3',
fontSize: 12,
}
}
}
}
基本配置到这里就结束了,然后有一些配置放在了数据加载的时候。
echarts 可以多次调用
myChart.setOption(option)
,配置的参数将会合并在一起,已有的配置将会被覆盖掉
4. 疫情数据加载以及详细配置
4.1 给数据分等级
为了更好地展示效果,以及解决人数为0的时候单独划为一个等级
这个问题,所以给数据做了一下处理。
function fixNum(value){
// 0-10 10-20 20-30 30-40 40-50 50-60
// 0 1-9 10-99 100-999 1000-9999 >=10000
if(value===0){
return 0;
}else if(value < 10){
return 15;
}else if(value < 100){
return 25;
}else if(value < 1000){
return 35;
}else if(value < 10000){
return 45;
}
return 55;
}
世界地图显示等级是倒过来的,不过差别不大:
function fixNum(value){
// 70-60 60-50 50-40 40-30 30-20 20-10 10-0
// 0 1-9 10-99 100-599 500-999 1000-9999 >=10000
if(value>=10000){
return 0;
}else if(value >= 1000){
return 15;
}else if(value >= 500){
return 25;
}else if(value >= 100){
return 35;
}else if(value >= 10){
return 45;
}else if(value >= 1){
return 55;
}
return 65;
}
4.2 数据预处理
然后,就是对数据做预处理,主要是为了方便配置。
这里讲一下国内省份地图的处理。需要处理如下问题:
- 由于省份地图形状和大小不一,尤其是海南省有诸岛屿,所以海南省地图特别大。需要对地图所适当缩放,以及位移;
- 解决例图与省份地图重叠的问题,需要修正例图在在各个省份的显示位置;
- 数据分等级,色阶也需要根据具体情况划分显示阶数;
- 地图数据和疫情数据中文
市镇州等地区
名称需要一一对应
function genData(items){
var confirmData = items.map(v=>{
// 数据分等级
v.value = fixNum(parseInt(v.confirm))
return v;
});
// 数据修正
// 中文省份的中文 市镇州等地区 对应地图的中文地区
var max = 0;
for(var i = 0; i < confirmData.length; i++){
max = Math.max(max, confirmData[i].value+5);
var name = confirmData[i].name
.replace("州区","aa")
.replace("州市","aa")
.replace("自治州","")
.replace("县","").replace("州","").replace("区","").replace("市","")
.replace("aa","州")
if(name.length == 1){
name = confirmData[i].name;
}
for(var j = 0; j < cityNameList.length; j++){
if(cityNameList[j].indexOf(name) >= 0){
confirmData[i].name = cityNameList[j];
break;
}
}
}
// 色阶
var colors = [];
var colors0 = ['#ffffff','#FFAA85','#FF7B69','#CC2929','#8C0d0d','#660208'];
var splitNumber = 5;
if(max <= 20){
max = 20;
}
// 合理划分色阶,最多5层
for(var i = 0; i*10 < max; i++){
colors.push(colors0[i]);
}
// 省份名称:例图水平位置,例图垂直位置,缩放比例
var pos = {
// 各省份具体配置,看下文配置
};
pos = pos[cityArr[1]];
if(!pos){
pos = ['left','bottom', 100];
}
return {
confirmData: confirmData, // 疫情数据
max: max, // 最大值
splitNumber: max/10, // 色阶阶数
color: colors, // 色阶数组
x: pos[0], // 例图水平位置
y: pos[1], // 例图垂直位置
// 缩放比例
layoutSize: Math.floor((pos[2] || 350)*(Math.min($(window).width(), 675)||375)/375),
}
}
上述代码中pos
的具体配置数据:
var pos = {
"安徽": ["right","top",380],
"甘肃": ["left","bottom", 320],
"河北": ["right","bottom", 380],
"江苏": ["left","bottom"],
"宁夏": ["left","top", 400],
"陕西": ["left","top", 380],
"新疆": ["left","top", 336],
"澳门": ["left","bottom", 380],
"广东": ["left","top", 330],
"黑龙江": ["right","top", 330],
"江西": ["right","bottom",380],
"青海": ["left","bottom", 330],
"四川": ["right","bottom", 330],
"西藏": ["right","top", 330],
"北京": ["left","top", 340],
"广西": ["left","top", 325],
"河南": ["left","top",340],
"吉林": ["left","bottom", 330 ],
"山东": ["left","top", 325],
"台湾": ["left","bottom", 350],
"云南": ["left","bottom",390],
"重庆": ["left","top", 350],
"贵州": ["left","top", 330],
"湖北": ["right","top", 330],
"辽宁": ["left","top", 330],
"上海": ["left","top", 380],
"天津": ["left","top", 380],
"浙江": ["left","top", 360],
"福建": ["left","top", 390],
"海南": ["left","bottom", 2600],
"湖南": ["left","bottom", 390],
"内蒙古": ["left","top", 330],
"山西": ["left","top", 390],
"香港": ["left","top",320],
}
对于世界地图来说,并不需要这么多处理。地图不需要缩放,例图位置可以写死。
- 数据分等级,色阶目前可以写死为6阶;
- 地图数据和疫情数据
国家和地区
中英文名称需要一一对应
首先色阶如下:
// 色阶
var colors = ['#A34830', '#CD503B','#E6664D','#F1813A','#FFC551','#FFF6B3', '#EFEFEF'];
国家中英文对照,这里需要特别声明一下,部分国家和地区数据可能有误,如果有发现的小伙伴可以在评论区反馈一下。
// 由于数据太多,这里将数据放在最底下。
// 部分国家和地区有重复出现,但并不影响使用。
同理也需要对疫情数据国家和地区的名称做一下处理。
for(var i = 0; i < confirmData.length; i++){
var name = confirmData[i].name // 中文需要转英文
var cname = name;
name = cityMap[name];
if(!name){
continue;
}
// var flag = false
for(var j = 0; j < cityNameList.length; j++){
if(cityNameList[j] === name){
confirmData[i].name = cityNameList[j];
confirmData[i].cname = cname;
flag = true
break;
}
}
// !flag && console.log("=========地图上没有这个国家:", name);
}
4.3 数据加载
好了,到这里,需要将所有方法组织起来。
// data:疫情数据 locCity:当前所在地区
function handleConfirmData(data, locCity){
// 数据预处理
var fmtedData = genData(data);
// 当前所在地区
var selectedIndex = -1;
// 数据和配置
var series = [{
name: cityArr[0],
type: 'map',
map: cityArr[0], // 需要与加载省份地图设置的名称一致
label: { // 地区区域文本
normal: {
show: false // 正常情况下不显示文字信息
},
emphasis: { // 点击地区样式
show: true,
color: '#000', // 区域颜色
fontSize: 10, // 区域
align: 'center',
baseline: 'middle'
}
},
// 单选,设置默认提示区域时,需要设置这一项为single
selectedMode: 'single',
layoutCenter: [ '50%', '50%' ], // 位置
layoutSize : fmtedData.layoutSize, // 缩放
data: fmtedData.confirmData // 数据
}]
// 海南省份的数据需要做一下位移
if(cityArr[1] === "海南" ){
if($(window).width() > 750){
series[0].layoutCenter = ['156%', '300%']
}else{
series[0].layoutCenter = ['170%', '330%']
}
}
// 获取选择城市数据的索引
var flag = true;
if(locCity && fmtedData.length){
for(var j = 0; j < fmtedData.length; j++){
if(locCity.indexOf(fmtedData[j].name) >= 0){
selectedIndex = j;
flag = false;
break;
}
}
}
// 当前省的数据
myChart && myChart.setOption(option = {
visualMap: {
max: fmtedData.max, // 最大值
show: true, // 显示例图
splitNumber: fmtedData.splitNumber, // 颜色分阶-阶数
inRange: {
color: fmtedData.color // 颜色组
},
formatter: function(left){ // 例图项文本显示
return {
"0": "0",
"10": "1-9",
"20": "10-99",
"30": "100-999",
"40": "1000-9999",
"50": "≥10000"
}[left];
},
x: fmtedData.x,
y: fmtedData.y,
},
series: series, // 处理后的疫情数据
});
if(myChart && selectedIndex >= 0){
setTimeout(function(){
// 当前地区 弹出提示
confirmMap.dispatchAction({
type: 'showTip',
seriesIndex:0, // 显示第几个series
dataIndex: selectedIndex // 显示第几个数据
});
// 当前地区 选中当前地区
confirmMap.dispatchAction({
type:'mapSelect',
seriesIndex: 0,
dataIndex:selectedIndex
});
});
}
}
南海诸岛屿显示问题
海南诸疫情地图关于海南省的地图显示,由于南海省包含了南海诸岛屿,所以显示的时候需要将南海诸岛单独提取出来显示。这个问题,困扰了我好久,最后借鉴某网站解决了这个问题。
南海诸岛解决方法就是在canvas上层以图片的形式放置南海诸岛。
// 添加南海诸岛屿的图片
if(cityArr[1] === "海南"){
$("#map-view").append('<img class="hainan-extra" src="/images/hainan-extra.png" />')
}
样式:
.hainan-extra{
width: 3rem;
position: absolute;
bottom: 1rem;
right: 1rem;
z-index: 1;
}
在地图上层插入图片
好了,到这里就全部结束了。写这份代码颇为费劲,所以在这里总结一下。目前源码包含有其他业务代码,不方面展示,如有需要源码的伙伴,只能说声抱歉,请参照上述代码自行进行修改。
国家和地区中英文对照
var cityMap = {
"阿富汗": "Afghanistan",
"新加坡": "Singapore",
"安哥拉": "Angola",
"阿尔巴尼亚": "Albania",
"阿联酋": "United Arab Emirates",
"阿根廷": "Argentina",
"亚美尼亚": "Armenia",
"法属南半球和南极领地": "French Southern and Antarctic Lands",
"澳大利亚": "Australia",
"奥地利": "Austria",
"阿塞拜疆": "Azerbaijan",
"布隆迪": "Burundi",
"比利时": "Belgium",
"贝宁": "Benin",
"布基纳法索": "Burkina Faso",
"孟加拉国": "Bangladesh",
"保加利亚": "Bulgaria",
"巴哈马": "Bahamas",
"波斯尼亚和黑塞哥维那": "Bosnia and Herz.",
"波黑": "Bosnia and Herz.",
"白俄罗斯": "Belarus",
"伯利兹": "Belize",
"百慕大": "Bermuda",
"玻利维亚": "Bolivia",
"巴西": "Brazil",
"文莱": "Brunei",
"不丹": "Bhutan",
"博茨瓦纳": "Botswana",
"中非共和国": "Central African Rep.",
"加拿大": "Canada",
"瑞士": "Switzerland",
"智利": "Chile",
"中国": "China",
"象牙海岸": "Côte d'Ivoire",
"喀麦隆": "Cameroon",
"刚果民主共和国": "Dem. Rep. Congo",
"刚果(金)": "Dem. Rep. Congo",
"刚果(布)": "Congo",
"刚果共和国": "Congo",
"刚果": "Congo",
"哥伦比亚": "Colombia",
"哥斯达黎加": "Costa Rica",
"古巴": "Cuba",
"北塞浦路斯": "Northern Cyprus",
"塞浦路斯": "Cyprus",
"捷克共和国": "Czech Rep.",
"捷克": "Czech Rep.",
"德国": "Germany",
"吉布提": "Djibouti",
"丹麦": "Denmark",
"阿尔及利亚": "Algeria",
"厄瓜多尔": "Ecuador",
"埃及": "Egypt",
"厄立特里亚": "Eritrea",
"西班牙": "Spain",
"爱沙尼亚": "Estonia",
"埃塞俄比亚": "Ethiopia",
"芬兰": "Finland",
"斐": "Fiji",
"福克兰群岛": "Falkland Is.",
"法国": "France",
"加蓬": "Gabon",
"英国": "United Kingdom",
"格鲁吉亚": "Georgia",
"加纳": "Ghana",
"冈比亚": "Gambia",
"几内亚": "Guinea",
"几内亚比绍": "Guinea-Bissau",
"赤道几内亚": "Eq. Guinea",
"希腊": "Greece",
"格陵兰": "Greenland",
"危地马拉": "Guatemala",
"法属圭亚那": "Fr. S. Antarctic Lands",
"圭亚那": "Guyana",
"洪都拉斯": "Honduras",
"克罗地亚": "Croatia",
"海地": "Haiti",
"匈牙利": "Hungary",
"印尼": "Indonesia",
"印度": "India",
"爱尔兰": "Ireland",
"伊朗": "Iran",
"伊拉克": "Iraq",
"冰岛": "Iceland",
"以色列": "Israel",
"意大利": "Italy",
"牙买加": "Jamaica",
"约旦": "Jordan",
"日本": "Japan",
"日本本土": "Japan",
"哈萨克斯坦": "Kazakhstan",
"肯尼亚": "Kenya",
"吉尔吉斯斯坦": "Kyrgyzstan",
"柬埔寨": "Cambodia",
"韩国": "Korea",
"朝鲜": "Dem. Rep. Korea",
"北朝鲜": "Dem. Rep. Korea",
"科索沃": "Kosovo",
"科威特": "Kuwait",
"老挝": "Lao PDR",
"黎巴嫩": "Lebanon",
"利比里亚": "Liberia",
"利比亚": "Libya",
"斯里兰卡": "Sri Lanka",
"莱索托": "Lesotho",
"立陶宛": "Lithuania",
"卢森堡": "Luxembourg",
"拉脱维亚": "Latvia",
"摩洛哥": "Morocco",
"摩尔多瓦": "Moldova",
"马达加斯加": "Madagascar",
"墨西哥": "Mexico",
"马其顿": "Macedonia",
"北马其顿": "Macedonia",
"马里": "Mali",
"缅甸": "Myanmar",
"黑山": "Montenegro",
"蒙古": "Mongolia",
"莫桑比克": "Mozambique",
"毛里塔尼亚": "Mauritania",
"马拉维": "Malawi",
"马来西亚": "Malaysia",
"纳米比亚": "Namibia",
"新喀里多尼亚": "New Caledonia",
"尼日尔": "Niger",
"尼日利亚": "Nigeria",
"尼加拉瓜": "Nicaragua",
"荷兰": "Netherlands",
"挪威": "Norway",
"尼泊尔": "Nepal",
"新西兰": "New Zealand",
"阿曼": "Oman",
"巴基斯坦": "Pakistan",
"巴拿马": "Panama",
"秘鲁": "Peru",
"菲律宾": "Philippines",
"巴布亚新几内亚": "Papua New Guinea",
"波兰": "Poland",
"波多黎各": "Puerto Rico",
"葡萄牙": "Portugal",
"巴拉圭": "Paraguay",
"卡塔尔": "Qatar",
"罗马尼亚": "Romania",
"俄罗斯": "Russia",
"卢旺达": "Rwanda",
"西撒哈拉": "W. Sahara",
"沙特阿拉伯": "Saudi Arabia",
"苏丹": "Sudan",
"南苏丹": "S. Sudan",
"塞内加尔": "Senegal",
"所罗门群岛": "Solomon Is.",
"塞拉利昂": "Sierra Leone",
"萨尔瓦多": "El Salvador",
"索马里兰": "Somaliland",
"索马里": "Somalia",
"塞尔维亚": "Serbia",
"苏里南": "Suriname",
"斯洛伐克": "Slovakia",
"斯洛文尼亚": "Slovenia",
"瑞典": "Sweden",
"斯威士兰": "Swaziland",
"叙利亚": "Syria",
"乍得": "Chad",
"多哥": "Togo",
"泰国": "Thailand",
"塔吉克斯坦": "Tajikistan",
"土库曼斯坦": "Turkmenistan",
"东帝汶": "Timor-Leste",
"特里尼达和多巴哥": "Trinidad and Tobago",
"突尼斯": "Tunisia",
"土耳其": "Turkey",
"坦桑尼亚": "Tanzania",
"乌干达": "Uganda",
"乌克兰": "Ukraine",
"乌拉圭": "Uruguay",
"美国": "United States",
"乌兹别克斯坦": "Uzbekistan",
"委内瑞拉": "Venezuela",
"越南": "Vietnam",
"瓦努阿图": "Vanuatu",
"西岸": "West Bank",
"也门": "Yemen",
"南非": "South Africa",
"赞比亚": "Zambia",
"津巴布韦": "Zimbabwe",
"印度尼西亚": "Indonesia",
"奥兰群岛": "Aland",
"美属萨摩亚": "American Samoa",
"安道尔": "Andorra",
"安圭拉": "Anguilla",
"安提瓜和巴布达": "Antigua and Barb.",
"阿鲁巴": "Aruba",
"孟加拉": "Bangladesh",
"巴林": "Bahrain",
"巴巴多斯": "Barbados",
"布维岛": "Bouvet Island",
"佛得角": "Cape Verde",
"中非": "Central African Rep.",
"圣诞岛": "Christmas Islands",
"科科斯(基林)群岛": "Cocos (keeling) Islands",
"科摩罗": "Comoros",
"库克群岛": "Cook Islands",
"科特迪瓦": "Côte d'Ivoire",
"多米尼加": "Dominica",
"多米尼克": "Dominica",
"多明尼加共和国": "Dominican Rep.",
"法罗群岛": "Faeroe Is.",
"斐济": "Fiji",
"法国大都会": "MetropolitanFrance",
"法属波利尼西亚": "French Polynesia",
"直布罗陀": "Gibraltar",
"格林纳达": "Grenada",
"瓜德罗普岛": "Fr. S. Antarctic Lands",
"法属瓜德罗普岛": "Fr. S. Antarctic Lands",
"关岛": "Guam",
"根西岛": "Guernsey",
"马恩岛": "Isle of Man",
"泽西岛": "Jersey",
"基里巴斯": "Kiribati",
"列支敦士登": "Liechtenstein",
"列支敦士登公国": "Liechtenstein",
"马尔代夫": "Maldives",
"马耳他": "Malta",
"马绍尔群岛": "Marshall Islands",
"马提尼克岛": "Fr. S. Antarctic Lands",
"毛里求斯": "Mauritius",
"马约特": "Fr. S. Antarctic Lands",
"马约特岛": "Fr. S. Antarctic Lands",
"密克罗尼西亚": "Micronesia",
"摩纳哥": "Monaco",
"蒙特塞拉特": "Montserrat",
"瑙鲁": "Nauru",
"纽埃": "Niue",
"诺福克岛": "Norfolk Island",
"帕劳": "Palau",
"巴勒斯坦": "Palestine",
"皮特凯恩群岛": "Pitcairn Islands",
"留尼汪岛": "Fr. S. Antarctic Lands",
"留尼汪": "Fr. S. Antarctic Lands",
"俄罗斯联邦": "Russian Federation",
"圣赫勒拿": "Saint Helena",
"圣卢西亚": "Saint Lucia",
"圣基茨和尼维斯": "Saint Kitts-Nevis",
"圣文森特和格林纳丁斯": "St. Vin. and Gren.",
"萨摩亚": "Samoa",
"圣马力诺": "San Marino",
"圣多美和普林西比": "Sao Tome and Principe",
"塞舌尔": "Seychelles",
"特立尼达和多巴哥": "Trinidad and Tobago",
"托克劳": "Tokelau",
"汤加": "Tonga",
"图瓦卢": "Tuvalu",
"阿拉伯联合酋长国": "United Arab Emirates",
"梵蒂冈": "Vatican City",
"瓦利斯群岛和富图纳群岛": "Wallis and Futuna",
"南斯拉夫": "Yugoslavia"
};
码农那些年