3D视角下的全球新冠肺炎实时分布

从新冠肺炎发生以来,诸多平台都提供了新冠肺炎实时信息,例如:百度,QQ,抖音,贴吧等,多数是以二维地图和统计图表来展示实时疫情信息,下面我们介绍如何制作3D视角下的全球疫情实时信息平台,信息主体为全球各国的新冠累计确诊人数,使用的平台是SuperMap iClient3D 10i for WebGL。

1.数据准备

(1)底图

使用世界行政区划图,SuperMap iDesktop范例数据下就有名为“World”的世界各国行政区划矢量面数据。首先我们得保证“World”数据各国名称的翻译,与我们之后需要对接的实时数据中各国名称翻译一致,待修改为一致后,在属性中删除掉不需要的字段(减小数据量),然后把“World”数据导出为GeoJson。

(2)实时新冠肺炎数据

这里使用的是该服务https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5,这个服务不足之处在于,只有中国的新冠肺炎数据是实时的,外国的并没有实时更新,如果是项目需求的话,建议找更好的实时数据服务,或者跟本地卫健委合作。

先来一张成果图:

在这里插入图片描述

2.功能实现

系统总体设计为,点击三维球面任何一个国家的行政区面,右上角信息框弹出,并显示该国家的新冠累计确诊人数。

(1)解析实时数据

我们向上面提到的地址发请求,然后解析返回回来的数据,并且将需要的数据以Key-Value的形式存储起来,其中Key为国家名称,Value为确诊人数,实现代码如下:

    var diseaseArray={};//以Key-Value形式存储返回所需要的结果,其中Key为国家名称,Value为确诊人数
	$.ajax({
				type: "get",
				url: "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5",
				dataType:"json",
				success: function (result) {
					var resultObj = JSON.parse(result.data);//返回结果转成易解析的key-value形式
					var diseaseData=resultObj.areaTree;
					for(var i=0;i<diseaseData.length;i++)
					{
						var name=diseaseData[i].name;
						var confirm=diseaseData[i].total.confirm;
						diseaseArray[name]=confirm;
					}//获取各国确诊人数,并以key-value形式添加到diseaseArray
					
				
					

				},
				error: function (msg) {
					console.log(msg);
				}
		})

(2)创建三维球

我们隐藏掉导航控件,隐藏掉太阳,星空背景和三维球面,着重体现世界行政区划面,代码如下:

    var viewer = new Cesium.Viewer('cesiumContainer',{
			navigation:false//隐藏导航控件
		});
	 var scene = viewer.scene;
	 scene.globe.show=false;//隐藏三维球体
	 scene.sun.show=false;//隐藏太阳
	 scene.skyBox.show=false;//隐藏天空盒

(3)分段专题图来体现各国疫情实况

加载json数据,读取各个国家对应面节点,以及各个国家名称,通过polygon类型的entity来构造面。entity的name指定成需要展示的各国新冠确诊人数信息,这样选中entity后,infobox就会在右上角自动弹出,并且展示name中设置的信息,entity的颜色按照各国新冠确诊人数来区分。这里需要提到的一个点是,某个国家的矢量面数据,可能是由多个面组合而成,即MultiPolygon,在解析面数据的时候需要区分该国的矢量面是一个面还是多个面。具体代码如下:

		 Cesium.loadJson('world_data.json').then(function(jsonData) {
		 
	     var polygonfeatures=jsonData.features;
		 for(var i=0;i<polygonfeatures.length;i++)
		 {
			 var polygonfeature=polygonfeatures[i].geometry.coordinates;//各国的面要素

			for(var j=0;j<polygonfeature.length;j++)
			{
				if(polygonfeature.length>1)//该国家矢量面由多个面对象组合而成的情况
				{
					var feature=polygonfeature[j][0];
					var points=[];
					var name=polygonfeatures[i].properties.COUNTRY;
					var color=null;
					if(diseaseArray.hasOwnProperty(name)){//判断该国是否有确诊病例
						var confirm=diseaseArray[name];//获取确诊人数
						name=name+"确诊人数是:"+confirm;//name中信息将会直接展示到infobox中
						if(Number(confirm)>10000)//按确诊人数不同,面的颜色也不同
						{
							color=new Cesium.Color(102/255, 2/255,8/255, 1);
						}
						else if(Number(confirm)>500 && Number(confirm)<=10000)
						{
							color=new Cesium.Color(140/255, 13/255,13/255, 1);
							
						}
						else if(Number(confirm) <=500 && Number(confirm)>100)
						{
							color=new Cesium.Color(204/255, 41/255,41/255, 1);
							
						}
						else if(Number(confirm) <=100 && Number(confirm)>10)
						{
							color=new Cesium.Color(255/255, 123/255,105/255, 1);
						}
						else{
							
							color=new Cesium.Color(255/255, 170/255,133/255, 1);
						}
					}
					else
					{
						name=name+":没有确认病例";
						color=new Cesium.Color(1, 1,1,1)
					}
					for(var k=0;k<feature.length;k++)//读取每个面的节点信息,并存进数组
					{						 
											 var x=feature[k][0];
											 var y=feature[k][1];
											 var z=0;
											 points.push(x);
											 points.push(y);
											 points.push(z);						 
					}
					if(points[0]!=undefined)//面节点异常判断
					{
											 var redPolygon = viewer.entities.add({//构造面实体
												 name : name,													 
												 polygon : {
													 hierarchy : Cesium.Cartesian3.fromDegreesArrayHeights(points),
													 perPositionHeight : true,
													 material : color,
													 outline:true,
													 outlineColor : Cesium.Color.BLACK,
													 heightReference:Cesium.HeightReference.CLAMP_TO_GROUND
												 }
												 
											 });
					}
				}
				else//该国家矢量面仅由一个面对象构成的情况
				{						
					var feature=polygonfeature[0];
					var points=[];
					var name=polygonfeatures[i].properties.COUNTRY;
					if(diseaseArray.hasOwnProperty(name)){
						var confirm=diseaseArray[name];
						name=name+"确诊人数是:"+confirm;
						if(Number(confirm)>10000)
						{
							color=new Cesium.Color(102/255, 2/255,8/255, 1);
						}
						else if(Number(confirm)>500 && Number(confirm)<=10000)
						{
							color=new Cesium.Color(140/255, 13/255,13/255, 1);
							
						}
						else if(Number(confirm) <=500 && Number(confirm)>100)
						{
							color=new Cesium.Color(204/255, 41/255,41/255, 1);
							
						}
						else if(Number(confirm) <=100 && Number(confirm)>10)
						{
							color=new Cesium.Color(255/255, 123/255,105/255, 1);
						}
						else{
							
							color=new Cesium.Color(255/255, 170/255,133/255, 1);
						}
					}
					else
					{
						name=name+":没有确认病例";
						color=new Cesium.Color(1, 1,1,1)
					}
					for(var k=0;k<feature.length;k++)
					{						 
											 var x=feature[k][0];
											 var y=feature[k][1];
											 var z=0;
											 points.push(x);
											 points.push(y);
											 points.push(z);
					}
					if(points[0]!=undefined)
					{
											 var redPolygon = viewer.entities.add({
												 name : name,
												 polygon : {
														 hierarchy : Cesium.Cartesian3.fromDegreesArrayHeights(points),
														 perPositionHeight : true,
														 material : color,
														 outline:true,
														 outlineColor : Cesium.Color.BLACK,
														 heightReference:Cesium.HeightReference.CLAMP_TO_GROUND
												 }
											 });
					}
				}
				
			}
			 
		 }
	 }).otherwise(function(error) {
	 });

(4)添加图例

直接上图例样式代码:

<style type="text/css">
	.linear{
		position: absolute;
		bottom: 10px;
		right: 0px;
		z-index: 1;
	    width: 300px;
	    height: 10px;
	    border-radius: 5px;
	    background-image: linear-gradient(to right, rgb(255,255,255) 16%, rgb(255,170,133) 16%,
													rgb(255,170,133) 32%,rgb(255,123,105) 32%,
	                                                rgb(255,123,105) 48%, rgb(204,41,41) 48%, 
													rgb(204,41,41) 65%, rgb(104,13,13) 65%,
	                                                rgb(104,13,13) 82%, rgb(102,2,8) 82%);
	}
</style>

<div class="linear"></div>
<p style="position: absolute;right: 248px;bottom: 20px;color: white;z-index: 1;">0</p>
<p style="position: absolute;right: 197px;bottom: 20px;color: white;z-index: 1;">10</p>
<p style="position: absolute;right: 146px;bottom: 20px;color: white;z-index: 1;">100</p>
<p style="position: absolute;right: 93px;bottom: 20px;color: white;z-index: 1;">500</p>
<p style="position: absolute;right: 30px;bottom: 20px;color: white;z-index: 1;">10000</p>

范例代码可以在超图技术资源中心下载,http://support.supermap.com.cn/,搜索“全球新冠确诊实时分布图”,再点击“超图代码”即可下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值