0


疫情可视化(后续)

前言

这是疫情可视化最开始的文章,有需要了解的可前往查看:https://blog.csdn.net/xi1213/article/details/126824752。 本来说有时间就把这个项目完结了的,结果后面一直有事拖着,直到现在十一月份了才搞完。老样子,先看成果。

修改与添加

后面可能审美疲劳了,越看越丑,就干脆直接用dataV(这可不是阿里的那个dataV)修饰页面了。这是项目改动后的样子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主要做了如下改动:

  1. 添加首页的3d粒子球体。
  2. 完成“省内分析”模块。
  3. 完成当地疫情报告生成与下载。
  4. 使用dataV修饰页面。

粒子球体

粒子球体也是用three.js完成的,放大仔细看会发现其实是有三层构成的:内层透明球体,中间点状球体,外层病毒球体。
在这里插入图片描述

具体实现过程是这样的:

  1. 先绘制一个内层透明球体,记得将球体材质的transparent设为true,然后设置不透明度opacity值。
//创建斑点球体asyncfunctioncreateSpotSphere(){let globeBufferGeometry =newTHREE.SphereGeometry(earthSize -1,50,50);//球体几何体let globeInnerMaterial =newTHREE.MeshBasicMaterial({color:newTHREE.Color(dvColor[0]),//颜色// blending: THREE.AdditiveBlending,//纹理融合的叠加方式// side: THREE.FrontSide,//前面显示transparent:true,//透明// depthWrite: false,//深度写入// depthTest: false,//黑洞效果opacity:.3,//不透明度});let globeInnerMesh =newTHREE.Mesh(
    globeBufferGeometry,
    globeInnerMaterial
  );
  earthGroup.add(globeInnerMesh);//将网格放入地球组
  cre
  1. 创建点状球体。这里需要使用一张黑白的世界地图。
let img =newImage();
img.src = earthGrayscale;//黑白地图

将图片使用onload加载到项目中后,利用canvas绘制一遍该图,再使用getImageData获取到像素点数据canData。

let canvas = document.createElement("canvas");
    canvas.width = img.width;//使得canvas尺寸与图片尺寸相同
    canvas.height = img.height;(canvas.getContext("2d")as any).drawImage(img,0,0, img.width, img.height);//canvas绘制图片let canData =(canvas.getContext("2d")as any).getImageData(0,0, canvas.width, canvas.height);//获取画布像素数据

利用canData .data中的rgba信息生成缓冲几何顶点数组globeCloudVerticesArray。

let globeCloudBufferGeometry =newTHREE.BufferGeometry();//设置缓冲几何体let globeCloudVerticesArray =[];//地球云缓冲几何体顶点let o =null;//数组处理时的计数for(o =0; o < canData.data.length; o +=4){let r =(o /4)% canvas.width,
        i =(o /4- r)/ canvas.width;if((o /4)%2==1&& i %2==1)if(0=== canData.data[o]){let n = r,
            longitude =(i /(canvas.height /180)-90)/-1,//经度
            latitude = n /(canvas.width /360)-180;//维度let s =latLongToVector3(longitude, latitude, earthSize,.1);//经纬度变换
          globeCloudVerticesArray.push(s);//将变换后的顶点放入数组}}

然后再使用three中的BufferAttribute生成属性position与color。

let l =newFloat32Array(3* globeCloudVerticesArray.length);//创建顶点数组长度for(o =0; o < globeCloudVerticesArray.length; o++){
      l[3* o]= globeCloudVerticesArray[o].x;//设置顶点数组数据
      l[3* o +1]= globeCloudVerticesArray[o].y;
      l[3* o +2]= globeCloudVerticesArray[o].z;}let positionVal =newTHREE.BufferAttribute(l,3);//设置缓冲区属性值
    globeCloudBufferGeometry.setAttribute("position", positionVal);//给缓冲几何体添加位置属性let globeCloudMaterial =newTHREE.PointsMaterial({color:newTHREE.Color(dvColor[1]),//颜色fog:true,size:1,});//球面斑点材质let d =newFloat32Array(3* globeCloudVerticesArray.length), c =[];for(o =0; o < globeCloudVerticesArray.length; o++){
      c[o]=newTHREE.Color(dvColor[1]);//球面斑点颜色
      d[3* o]= c[o].r;//设置地球云数组rgb颜色
      d[3* o +1]= c[o].g;
      d[3* o +2]= c[o].b;}let color_val =newTHREE.BufferAttribute(d,3);
    globeCloudBufferGeometry.setAttribute("color", color_val);//给缓冲几何体添加颜色属性,修改颜色直接修改globeCloudBufferGeometry的setAttribute

最后再使用THREE.Points创建球面的点,将position与color属性添加到点的几何体BufferGeometry中。

let globeCloud =newTHREE.Points(//球面的象素点
      globeCloudBufferGeometry,
      globeCloudMaterial
    );

这是需要用到的坐标转换方法:

//经纬度坐标变换(传入e:纬度、a经度、t球半径、o球额外距离)functionlatLongToVector3(e: any,a: any,t: any,o: any){var r =(e * Math.PI)/180,
    i =((a -180)* Math.PI)/180,
    n =-(t + o)* Math.cos(r)* Math.cos(i),
    s =(t + o)* Math.sin(r),
    l =(t + o)* Math.cos(r)* Math.sin(i);returnnewTHREE.Vector3(n, s, l);//计算三维向量};
  1. 创建最外层的病毒球体。每一个病毒都是一个THREE.Sprite,材质是THREE.SpriteMaterial,利用Sprite.position.set设置具体坐标位置,最后将Sprite添加到球体组中。病毒的颜色是由当前点确诊值决定的,颜色值在colors数组中取出。
//创建病毒functioncreateVirus(data: any,earthSize: any){let colors =[newTHREE.Color(0xf9b8b8),newTHREE.Color(0xfe4242),newTHREE.Color(0xff0000),];//病毒颜色列表let virSize =4;//病毒大小let list =JSON.parse(JSON.stringify(data));
  list.forEach((e:{value: number; color: any; position: any[];})=>{
    e.value >=10000000&&(e.color = colors[2]);//根据病毒数赋予不同颜色
    e.value >=500000&& e.value <10000000&&(e.color = colors[1]);
    e.value <500000&&(e.color = colors[0]);if(e.position){let virusMaterial =newTHREE.SpriteMaterial({color: e.color,map:newTHREE.TextureLoader().load(virusImg),side:THREE.FrontSide,//只显示前面});//病毒材质let Sprite =newTHREE.Sprite(virusMaterial);//点精灵材质
      Sprite.scale.set(virSize, virSize,1);//点大小let lat = e.position[1];//纬度let lon = e.position[0];//经度let s =latLongToVector3(lat, lon, earthSize,1);//坐标转换
      Sprite.position.set(s.x, s.y, s.z);//设置点的位置
      Sprite.dotData = e;//将点的数据添加到dotData属性中
      Sprite.name ="病毒";
      earthGroup.add(Sprite);//将病毒添加进球体组中}});};

省内分析

  1. 省内数据概况。在这里插入图片描述 该数值在加载时是有增加动画的,是利用vue响应式原理完成的,在上一篇文章中有提到。
  2. 省内各地疫情柱状图。在这里插入图片描述

这是具体的echart配置:

let option ={title:{text: provinceBaseData.value.province +"各地数据",left:"center",top:'5%',textStyle:{color:"#fff",},},tooltip:{trigger:'axis',axisPointer:{type:'shadow'}},dataZoom:[{type:'inside',},{show:true,yAxisIndex:0,filterMode:'empty',width:25,height:'70%',showDataShadow:false,left:'3%',top:"center"}],legend:{data:['累计数','治愈数','确诊数','较昨日新增','死亡数'],orient:"vertical",top:"15%",right:"2%",textStyle:{color:"#fff"},},grid:{left:'3%',right:'15%',bottom:'10%',containLabel:true},xAxis:{type:'category',data: echartData.cityName,axisLabel:{interval:0,rotate:50,color:"#fff"},},yAxis:{type:'value',axisLabel:{color:"#fff",},},series:[{name:'累计数',type:'bar',emphasis:{focus:'series'},itemStyle:{color:'#f59158'},data: echartData.conNum
            },{name:'治愈数',type:'bar',emphasis:{focus:'series'},itemStyle:{color:'#48c56b'},data: echartData.cureNum
            },{name:'确诊数',type:'bar',stack:'total',emphasis:{focus:'series'},itemStyle:{color:'#ffd889'},data: echartData.econNum
            },{name:'较昨日新增',type:'bar',stack:'total',emphasis:{focus:'series'},itemStyle:{color:'#794ebd'},data: echartData.asymptomNum
            },{name:'死亡数',type:'bar',stack:'total',emphasis:{focus:'series'},itemStyle:{color:'#ff6a6a'},data: echartData.deathNum
            },]};
  1. 省份历史疫情数据图表。在这里插入图片描述

这是该图表配置:

let option ={title:{text: provinceBaseData.value.province +"历史数据",left:"center",top:'5%',textStyle:{color:"#fff",},},tooltip:{trigger:'axis',axisPointer:{type:'cross',label:{backgroundColor:'#6a7985'}}},legend:{data:['累计数','确诊数','较昨日新增','治愈数','死亡数'],orient:"vertical",top:"15%",right:"2%",textStyle:{color:"#fff"},},grid:{left:'8%',},xAxis:[{type:'category',boundaryGap:false,axisLabel:{color:"#fff",},data: echatrData.time
            }],yAxis:[{type:'value',axisLabel:{color:"#fff",},}],dataZoom:[{startValue:''},{type:'inside'}],series:[{name:'累计数',type:'line',stack:'Total',smooth:true,lineStyle:{width:0},showSymbol:false,areaStyle:{opacity:0.8,color:"#f59158"},emphasis:{focus:'series'},itemStyle:{color:'#f59158'},data: echatrData.conNum
            },{name:'确诊数',type:'line',stack:'Total',smooth:true,lineStyle:{width:0},showSymbol:false,areaStyle:{opacity:0.8,color:"#ffd889"},itemStyle:{color:'#ffd889'},emphasis:{focus:'series'},data: echatrData.econNum
            },{name:'较昨日新增',type:'line',stack:'Total',smooth:true,lineStyle:{width:0},showSymbol:false,label:{show:true,position:'top'},areaStyle:{opacity:0.8,color:"#794ebd"},itemStyle:{color:'#794ebd'},emphasis:{focus:'series'},data: echatrData.asymptomNum
            },{name:'治愈数',type:'line',stack:'Total',smooth:true,lineStyle:{width:0},showSymbol:false,areaStyle:{opacity:0.8,color:"#48c56b"},itemStyle:{color:'#48c56b'},emphasis:{focus:'series'},data: echatrData.cureNum
            },{name:'死亡数',type:'line',stack:'Total',smooth:true,lineStyle:{width:0},showSymbol:false,areaStyle:{opacity:0.8,color:"#ff6a6a"},itemStyle:{color:'#ff6a6a'},emphasis:{focus:'series'},data: echatrData.deathNum
            },]};

报告生成与下载

报告生成利用的是docxtemplater,这是前端生成word比较方便的一个插件,具体使用方法可以看这里:https://blog.csdn.net/xi1213/article/details/127412672。

  • 这是生成的word报告示例:在这里插入图片描述

dataV修饰

结语

  • 最后我发现人的审美真的变化太快了。
  • 项目刚搞完:嗯不错!真漂亮!
  • 过去一周后:什么玩意!丑得一批!
  • 如果还有后续的话,我可能就要考虑添加自定义主题配色了。

本文转载自: https://blog.csdn.net/xi1213/article/details/127719364
版权归原作者 xi12 所有, 如有侵权,请联系我们删除。

“疫情可视化(后续)”的评论:

还没有评论