• 全国疫情精准定点动态更新(.net core)


    前言

    疫情远比我们在年初想的发展迅速,在过年前还计划着可以亲戚聚聚,结果都泡汤了,开始了自家游。
    在初三的时候,看到那个丁香医生,觉得不够详细,比如说我想看下周边城市的疫情情况,但是我地理不好,根本不清楚其他城市的位置。
    当时我想的是做一张地图标注各个城市的数量,及严重程度。然后我用python去爬虫,晚上成功了,第二点防爬了。当然拦不住我的,我使用元素爬取的方式也行。
    但是这种方式需要运行crome内核渲染,然后要隔一段时间更新,我已经放弃了我买的windows,原因是贵,且自己贫苦。
    当时我认为疫情很快会得到控制,所以我就放弃了。
    前几天在博客园看到有人写了一个爬取的demo,那个api返回的数据相当标准,所以我有产生了想法。
    看下我做的效果吧:

    密密麻麻的,这是啥呢?完全没有可视度。
    放大分析下。
    1.我根据中国不同的省份,根据不同人数显示不同的颜色,且放上去会显示当前疫情。

    颜色可以通过左侧控制,上下有两个箭头可以上拉下拉,选取区域,如下图:

    2.当地图放大后,可以看到更多的细节,比如说如果数量达到100后我就会让当前位置,加入警报,当然随着数量越多该位置的点更大,且冒泡提升更大。
    放大后效果如下图:

    好了看下大概思路吧,本博客只介绍思路,项目开源,写的随意,不要介意,地址在末尾贴出。

    正文

    第一步

    我想的肯定是获取数据,在前几天看到一篇博客,上面介绍一个非常标准的api,我没有去找那篇博客了,在此感谢,如果该博主觉得需要贴出地址,请联系我,毕竟博文给与了我help。

    HttpClient httpClient = new HttpClient { BaseAddress = new Uri("https://view.inews.qq.com/") };
    HttpResponseMessage httpResponseMessage = httpClient.GetAsync("g2/getOnsInfo?name=disease_h5").GetAwaiter().GetResult();
    var result = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    nCoVData data = JsonConvert.DeserializeObject<nCoVData>(result);
    nCoVDataDetail nCoVDataDetail = JsonConvert.DeserializeObject<nCoVDataDetail>(data.Data);
    

    通过格式化将json成c# 对象。

    nCoVDataDetail.AreaTree 就是各个省的信息。
    

    因为数量较多,我无法去截图数据在此介绍格式。

    public class AreaTree
    {
    	public AreaTree()
    	{
    		this.Today = new Today();
    		this.Total = new Overview();
    		this.Children = new List<Children>();
    	}
           //国家名字
    	public string Name { get; set; }
            //今天的变化情况
    	public Today Today { get; set; }
            //总数量
    	public Overview Total { get; set; }
            //省或者直辖市
    	public List<Children> Children { get; set; }
    }
    
    public class Children
    {
    	 //省名或者直辖市名
    	public string Name { get; set; }
    
    	// 今日变化
    	public Today Today { get; set; }
    	// 统计
    	public Overview Total { get; set; }
            //省下面的区,直辖市下面的区
    	public List<Children> children { get; set; }
    }
    

    模型就是这样的。

    第二步

    我需要确定每个地方的经纬度,这样我才能在地图上定位.
    这时候我想到了百度地图。

    private static mapv3 GetHttpRequest(string areaAddress)
    {
    	HttpClient httpClient = new HttpClient { BaseAddress = new Uri("http://api.map.baidu.com/") };
    	HttpResponseMessage httpResponseMessage = httpClient.GetAsync("geocoding/v3/?address=" + areaAddress + "&output=json&ak=你的key").GetAwaiter().GetResult();
    	var result = httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    	mapv3 data = JsonConvert.DeserializeObject<mapv3>(result);
    	return data;
    }
    

    这个时候需要你去百度地图注册你的key了,免费哈。
    看下mapv3模型,在这里我只介绍用到的经纬度,其他的自己看官网。吐槽一下,官网的文档绝对是程序员写的。

    public class mapv3
    {
    	public int status { get; set; }
    
    	public result result { get; set; }
    }
    

    status 为状态0就ok,其他不ok。
    看下result:

    public class result
    {
    	public location location { get; set; }
    
    	public int precise { get; set; }
    
    	public int confidence { get; set; }
    
    	public int comprehension { get; set; }
    
    	public string level { get; set; }
    }
    

    其他不介绍了,用不上,详细看官网,在这里只介绍location。

    public class location
    {
    	public double lng { get; set; }
    
    	public double lat { get; set; }
    
    }
    

    这两个就是经纬度。

    第三步

    整理数据与echarts数据格式相对应,echarts是可视化的插件。
    echarts经纬度是这样的格式:
    {
    "位置":[经,纬]
    }
    经纬度地址需要存取。

    private static Dictionary<string, double[]> dic = new Dictionary<string, double[]>();
    

    我使用dictionary,因为我需要鉴别是否已经存在了,方便查询。
    下面是整体格式化:

    private static void GetPositionOfJson(IList<AreaTree> areaTrees)
    {
    	// 考虑到查询成本
    	echartsModels = new List<EchartsModel>();
    	echartsMapModels = new List<EchartsMapModel>();
    	pronvincedic =new List<EchartsModel>();
    	EchartsModel echartsModel = new EchartsModel();
    	EchartsMapModel echartsMapModel = new EchartsMapModel();
    	foreach (var country in areaTrees)
    	{
    		var CountryName = country.Name;
    		if (CountryName != "中国")
    		{
    			//only china 其他国家不管
    			continue;
    		}
    		var provinceRank = "省";
    		foreach (var province in country.Children)
    		{
    			if (province.Name == "北京" || province.Name == "天津" || province.Name == "上海" || province.Name == "重庆")
    			{
    				provinceRank = "市";
    			}
    			var provinceName = province.Name + provinceRank;
    
    			//加入统计 因为西藏省区
    			if (!dic.Keys.Contains(province.Name))
    			{
    				var fullName = provinceName + province.Name;
    				mapv3 mapv3 = GetHttpRequest(fullName);
    				if (mapv3.status == 0)
    				{
    					var location = mapv3.result.location;
    					double[] d = new double[] { location.lng, location.lat };
    					dic.Add(province.Name, d);
    				}
    			}
    			EchartsModel echartsModelPClone = (EchartsModel)echartsModel.clone();
    			echartsModelPClone.name = province.Name;
    			echartsModelPClone.value = province.Total.Confirm;
    			pronvincedic.Add(echartsModelPClone);
    
    
    			//颜色
    			EchartsMapModel echartsMapModelClone = (EchartsMapModel)echartsMapModel.clone();
    			echartsMapModelClone.name = province.Name;
    			//总感染人数
    			EchartsModel InfectSum = (EchartsModel)echartsModel.clone();
    			InfectSum.name = "感染人数";
    			InfectSum.value = province.Total.Confirm;
    			//治愈人数
    			EchartsModel CureSum = (EchartsModel)echartsModel.clone();
    			CureSum.name = "治愈人数";
    			CureSum.value = province.Total.Heal;
    			//沉重的死亡人数
    			EchartsModel HeadSum = (EchartsModel)echartsModel.clone();
    			HeadSum.name = "死亡人数";
    			HeadSum.value = province.Total.Dead;
    			List<EchartsModel> echartsModelMapList = new List<EchartsModel>();
    			echartsModelMapList.Add(InfectSum);
    			echartsModelMapList.Add(CureSum);
    			echartsModelMapList.Add(HeadSum);
    			echartsMapModelClone.value = echartsModelMapList;
    			echartsMapModels.Add(echartsMapModelClone);
    			foreach (var city in province.children)
    			{
    				if (!dic.Keys.Contains(city.Name))
    				{
    					var fullName = provinceName + city.Name;
    					mapv3 mapv3 = GetHttpRequest(fullName);
    					if (mapv3.status == 0)
    					{
    						var location = mapv3.result.location;
    						double[] d = new double[] { location.lng, location.lat  };
    						dic.Add(city.Name, d);
    					}
    				}
    				//后续需要优化部分
    				EchartsModel echartsModelClone= (EchartsModel)echartsModel.clone();
    				echartsModelClone.name = city.Name;
    				echartsModelClone.value = city.Total.Confirm;
    				echartsModels.Add(echartsModelClone);
    			}
    		}
    	}
    }
    

    分析下:
    下面是装载经纬度的:

    foreach (var city in province.children)
    {
    	if (!dic.Keys.Contains(city.Name))
    	{
    		var fullName = provinceName + city.Name;
    		mapv3 mapv3 = GetHttpRequest(fullName);
    		if (mapv3.status == 0)
    		{
    			var location = mapv3.result.location;
    			double[] d = new double[] { location.lng, location.lat  };
    			dic.Add(city.Name, d);
    		}
    	}
    	//后续需要优化部分
    	EchartsModel echartsModelClone= (EchartsModel)echartsModel.clone();
    	echartsModelClone.name = city.Name;
    	echartsModelClone.value = city.Total.Confirm;
    	echartsModels.Add(echartsModelClone);
    }
    

    判断不包含,然后去通过百度查询。
    EchartsModel 是传递echarts模型中的散点格式。
    echarts格式是{name:"",value:""},这时候散点就会显示数字和名字了。
    因为每个城市创建数量过多,所以我采用克隆的方式进行处理。
    其他我就不介绍了,源码公开逻辑也不复杂。
    有一个地方需要介绍下:

    if (province.Name == "北京" || province.Name == "天津" || province.Name == "上海" || province.Name == "重庆")
    {
    	provinceRank = "市";
    }
    

    为什么我这么做,因为这几个是直辖市。
    比如我要查询武汉经纬度,肯定湖北省武汉。
    查询北京的朝阳区,肯定是北京市朝阳区。如果是输入北京朝阳区是不准的。

    第四步

    当我把经纬度,保存在字典中,我每次我重启的时候需要查询一次,这非常耗时,我将会保存为json格式,然后存在本地,重启的时候,我将会读取,这里我贴代码。
    当然我启动的时候我要初始化,且数据必须动态更新哈,所以我每隔一个小时去更新数据。

    timer.LoadMap();
    //初始化
    timer.getData(null,null);
    //每隔一小时执行一次
    System.Timers.Timer  timerOneHour= new System.Timers.Timer(60 * 60 * 1000);
    timerOneHour.Elapsed += new System.Timers.ElapsedEventHandler(timer.getData);
    timerOneHour.AutoReset = true;
    

    第五步

    前端根据数据渲染。
    我个人觉得能够介绍的只有颜色和大小。

    visualMap: {
    	show: true,
    	min: 0,
    	max: 2000,
    	left: 'left',
    	top: 'bottom',
    	text: ['高', '低'], // 文本,默认为数值文本
    	calculable: true,
    	seriesIndex: [1],
    	pieces: [{
    	}],
    	inRange: {
    		color: ["#F2FE96",'#FFFF00', '#A5CC82',"#BF444C"], // 绿到黄到红    
    	}
    },
    

    设定省份的数量区间是0-2000,颜色在这区间变动:

    color: ["#F2FE96",'#FFFF00', '#A5CC82',"#BF444C"]
    

    散点和气泡大小如下:

    symbolSize: function (val) {
    	num = val[2] / 5;
    	num = num > 50 ? 50 : num;
    	num = num < 10 ? 10 : num;
    	return num;
    }
    

    最大为50,最小为10。
    下面是如果value>100,那么让它显示危险标志。

    {
    	name: 'item>100',
    	type: 'effectScatter',
    	coordinateSystem: 'geo',
    	data: convertData(data.sort(function (a, b) {
    		return b.value - a.value;
    	}).filter(function (item) {
    		return item.value >= 100
    	})
    	)
    	,
    	symbolSize: function (val) {
    		num = (val[2] / 10);
    		num = num > 50 ? 50 : num
    		if (val[2] == 0) {
    			num = 0;
    		}
    		return num;
    	},
    	showEffectOn: 'render',
    	rippleEffect: {
    		brushType: 'stroke'
    	},
    	hoverAnimation: true,
    	label: {
    		normal: {
    			formatter: '{b}',
    			position: 'right',
    			show: false
    		}
    	},
    	itemStyle: {
    		normal: {
    			color: 'red',
    			shadowBlur: 10,
    			shadowColor: 'red'
    		}
    	},
    	zlevel: 1
    },
    

    总结

    愿疫情快速结束,带好口罩,保护自己,保护他人。人人为我,我为人人。

    本来,我想在我的服务器上部署的,但是黑客太多,本人安全防护水平太低了。

    所以上传到github,没有数据库,直接可运行。.net core 库,2.2,可自行更换,写的随意,见谅。

    需要替换百度的key,因为我已经去掉了。如果实在不想去注册,可评论发到你的邮箱。

    github地址:

    https://github.com/aoximin/ViralCollapse

  • 相关阅读:
    java 调用可执行文件时,ProcessBuilder异常CreateProcess error=2
    easyUI行内编辑与jdbc批量更新
    Oracle中merge into应用举例
    mybatis插入List<Map<String, String>>批量数据到Oracle数据库
    插入数据库值大于数据库字段设置的长度导致的mapper执行中断,控制台未报错
    ORA-25156:旧样式的外部联接(+)不能与 ANSI链接一起使用
    Oracle列转行函数listagg使用演示
    Oracle查询序列和函数方法封装
    js取url问号后的参数方法封装
    linux查看文件具体时间和大小
  • 原文地址:https://www.cnblogs.com/aoximin/p/12298477.html
Copyright © 2020-2023  润新知