结对第二次作业——某次疫情统计可视化的实现

这个作业属于哪个课程班级的链接
这个作业要求在哪里 作业要求
结对学号 221701125 & 221701126
这个作业的目标 实现通过地图的形式来直观显示 疫情的大致分布情况,还可以查 看具体省份的疫情统计情况;点 击某个省份显示该省疫情的具体 情况;学习与队友进行合作;学 习使用github进行团队合作;学 习如何进行前后端数据交互。
作业正文 正文
其他参考文献 echarts官网 W3Cschool教程

1、仓库地址&代码规范

Github仓库地址

代码规范

2、展示作品

(1)首页如图所示,上半部分显示整体疫情,下半部分以中国地图来显示整体疫情,地图根据疫情显示不同颜色

img

 

(2)当鼠标移动到中国地图的某个省份,将会出现浮动窗口显示该省份的疫情,并且该省份地图会高亮显示。

2

 

(3)地图左边可查看根据确诊人数显示的不同颜色深浅,例如将鼠标移到100-999的部分,符合该部分的省份都将高亮显示

3

 

(4)鼠标点击100-999的图标,将重置所有疫情符合100-999的省份为白色,其他部分的颜色功能相同,点击即重置为白色,再次点击又会重新显示出颜色。

4

 

(5)中间的输入框可选择日期

5

 

(6)选择日期后,整个界面将统计该日期的疫情,地图的颜色也会根据疫情人数有所改变

6

 

(7)点击地图上某个省份,跳转到新页面显示该省份的疫情界面

7

 

(8)将鼠标移动到折线图上,将会跳出浮动窗显示具体数据(新增确诊趋势、新增疑似趋势、治愈趋势、死亡趋势)

8

 

(9)9.1折线图上方有四个标题,点击某个标题可隐藏该折线图,再次点击又可显示

9

 

(10)中间的输入框可选择日期,选择后将显示该省份该日期的具体疫情(现有确诊、累计确诊、累计治愈、累计死亡)

10

 

(11)折线图右上方有个下载的图标,点击可下载折线图界面

11

 

3、结对讨论过程描述

刚拿到题目后,和队友进行讨论,总结了以下问题:

(1)该用什么语言来写,需要能支持服务器(javaee还是php)?

(2)后端数据怎么获取?怎么处理?怎么统计?

(3)后端接口要如何返回数据?

(4)前端如何接收后端传来的数据?

(5)前端界面要如何规划?每个界面要如何划分模块?

(6)前端中国地图要如何绘制?前端折线图要如何绘制?

(7)前端如何实现不同省份不同疫情要显示不同颜色?鼠标移动如何显示浮窗?颜色高亮?

(8)前端如何实现日期选择?

 

经过讨论,并且上网查找资料后,基本解决了所有问题:

用javaee来做这个项目

后端读取日志文件,并写算法统计数据,讲数据封装到哈希表

后端接口返回int []类型的数组

前端用jsp来写,可直接写java代码调用后端接口传数据

前端首页和折线图页面都分为上下两部分,上半部分显示疫情数字,下半部分显示图表

中国地图和折线图都用echarts来绘制

echarts可设置不同数量显示不同颜色,中国地图echarts自带浮窗和显示高亮

前端日期选择用HTML5中的input标签,将属性type设置为date

echarts的用法可在官网找到使用教程

 

 

两人结对讨论截图:

21

22

23

 

4、设计实现过程

设计实现过程:后端处理数据后,前端调用后端接口获取数据,填充到echarts显示,中国地图点击某省份,跳转到折线图时,应该在跳转的URL后添加参数省份的id,调用方法request.getParameter()可获取input输入选择的日期,根据不同日期做相应的计算显示数据。

 

 

 

功能结构图:

 

 

 

5、关键代码

 

Entry.java 读取日志文件,处理数据,封装到哈希表中

     /*
* 处理每一个文件
*/
  public static void solveTheFile(String[] fileList) {
  Province nationwide = map.get("全国");
  // TODO Auto-generated method stub
  for(String aFile : fileList) {
  String fileDate = aFile.substring(0, aFile.indexOf("."));
Date nationwideDate = new Date();
nationwideDate.setDate(fileDate);

try {
  File file = new File(path + "\\" + aFile);
  InputStreamReader inputReader = new InputStreamReader(new FileInputStream(file), "GB2312");
  BufferedReader bf = new BufferedReader(inputReader);
  String str;
 
  while ((str = bf.readLine()) != null && str.indexOf("//") != 0) {
  if(str.length() == 0)
  continue;
  String[] information = str.split("\\s+");
  String provinceName = information[0];//先取到省份
  int number = getNumber(information);//取出各行人数
 
  if(map.get(provinceName) != null) {
  Province province = map.get(provinceName);
  Map<String, Date> dateMap = province.getDateMap();
  Date date = new Date();
 
  if(dateMap.get(fileDate) != null) {
  date = province.getDateMap().get(fileDate);
  }
  else {
  date = new Date();
  date.setDate(fileDate);
  }
 
  switch (information[1]) {
case "新增":
if(information[2].equals("感染患者")) {
int ip = date.getIp();
ip += number;
date.setIp(ip);

int nationwideIp = nationwideDate.getIp();
nationwideIp += number;
nationwideDate.setIp(nationwideIp);
}
else {//疑似患者的情况
int sp = date.getSp();
sp += number;
date.setSp(sp);

int nationwideSp = nationwideDate.getSp();
nationwideSp += number;
nationwideDate.setSp(nationwideSp);
}
break;
case "治愈":
int cure = date.getCure();
int ip1 = date.getIp();
cure += number;
ip1 -= number;
date.setCure(cure);
date.setIp(ip1);

int nationwideCure = nationwideDate.getCure();
nationwideCure += number;
nationwideDate.setCure(nationwideCure);
break;
case "死亡":
int dead = date.getDead();
int ip2 = date.getIp();
dead += number;
ip2 -= number;
date.setDead(dead);
date.setIp(ip2);

int nationwideDead = nationwideDate.getDead();
nationwideDead += number;
nationwideDate.setDead(nationwideDead);
break;
default:
break;
}
  dateMap.put(fileDate, date);
  nationwide.getDateMap().put(fileDate, nationwideDate);
  }
  }
  bf.close();
  // bw.close();
  inputReader.close();
 
}
  catch (IOException e) {
  e.printStackTrace();
}
}
}

 

index.jsp 首页,调用接口获取数据,在script中绘制中国地图

    
  var dataMap = [{id:1, name: '北京',value:beijing }, {id:2, name: '天津',value:tianjin}, {id:3, name: '上海',value:shanghai }, {id:4, name: '重庆',value:chongqing },
  {id:5, name: '河北',value:hebei }, {id:6, name: '河南',value:henan }, {id:7, name: '云南',value:yunnan }, {id:8, name: '辽宁',value:liaoning },
  {id:9, name: '黑龙江',value:heilongjiang }, {id:10, name: '湖南',value:hunan }, {id:11, name: '安徽',value:anhui }, {id:12, name: '山东',value:shandong },
  {id:13, name: '新疆',value:xinjiang }, {id:14, name: '江苏',value:jiangsu }, {id:15, name: '浙江',value:zhejiang }, {id:16, name: '江西',value:jiangxi },
  {id:17, name: '湖北',value:hubei }, {id:18, name: '广西',value:guangxi }, {id:19, name: '甘肃',value:gansu }, {id:20, name: '山西',value:shanxi },
  {id:21, name: '内蒙古',value:neimenggu }, {id:22, name: '陕西',value:shanxi2 }, {id:23, name: '吉林',value:jilin }, {id:24, name: '福建',value:fujian },
  {id:25, name: '贵州',value:guizhou }, {id:26, name: '广东',value:guangdong }, {id:27, name: '青海',value:qinghai }, {id:28, name: '西藏',value:xizang },
  {id:29, name: '四川',value:sichuan }, {id:30, name: '宁夏',value:ningxia }, {id:31, name: '海南',value:hainan }, {id:32, name: '台湾',value:"none" },
  {id:33, name: '香港',value:"none"}, {id:34, name: '澳门',value:"none" }]
  // 需要在页面上直接标记出来的城市
  //var specialMap = ['浙江', '云南', '陕西'];
  var specialMap = [];
  // 对dataMap进行处理,使其可以直接在页面上展示
  for (var i = 0; i < specialMap.length; i++) {
      for (var j = 0; j < dataMap.length; j++) {
          if (specialMap[i] == dataMap[j].name) {
              dataMap[j].selected = true;
              break;
          }
}
}
// 绘制图表,准备数据

var option = {
  tooltip: {
      formatter: function (params) {
          var info = '<p style="font-size:18px">' + params.name + '</p><p style="font-size:14px">'+'确诊:'+params.value+'人'+'</p>'
          return info;
      },
      //提示标签背景颜色
      backgroundColor:"rgba(0,0,255,0.5)",
      textStyle: { color: "#fff" } //提示标签字体颜色
  },
  series: [
      {
          name: '中国',
          type: 'map',
          mapType: 'china',
          selectedMode: 'multiple',
          label: {
              normal: {
                  show: true,//显示省份标签
                  // textStyle:{color:"#c71585"}//省份标签字体颜色
              },
              emphasis: {
                  show: true,//对应的鼠标悬浮效果
                  //textStyle:{color:"#00FFFF"}
              }
          },
          itemStyle: {
              normal: {
                  borderWidth: .5,//区域边框宽度
                  // borderColor: '#009fe8',//区域边框颜色
                  // areaColor:"#ffefd5",//区域颜色
              },
              emphasis: {
                  borderWidth: .5,
                  borderColor: '#4b0082',
                  areaColor: "#00FFFF",
              }
          },
          data: dataMap
      }
  ],
   
visualMap: {
  show : true,
  x: 'left',
  y: 'bottom',
  splitList: [
      {start: 10000},
      {start: 1000, end: 9999},
      {start: 100, end: 999},
      {start: 10, end: 99},
      {start: 1, end: 9},
      {start: 0, end: 0},
  ],
  color: ['#660208', '#8C0D0D', '#CC2929','#FF7B69' ,'#FFAA85' , '#F8F9FA']
},
};
//初始化echarts实例
var myChart = echarts.init(document.getElementById('container'));
//使用制定的配置项和数据显示图表
myChart.setOption(option);
myChart.on('click', function (params) {
  console.log(params.data.id);
  window.location.href="statistics.jsp?id="+params.data.id;
   
});

 

statistics.jsp 绘制折线图

     var option = {
title: {
      text: '<%=province%> 疫情趋势', // 标题名称
  },
  xAxis: {
      type: 'category',
      data: ['01-19', '01-20', '01-21', '01-22', '01-23', '01-24', '01-25','01-26','01-27','01-28','01-29','01-30','01-31','02-01','02-02']
  },
  yAxis: {
      type: 'value',
      name: '单位:例',
  },
  tooltip: {
      trigger: 'axis'
  },
      legend: {
          data: ['新增确诊趋势', '新增疑似趋势', '治愈趋势', '死亡趋势']
      },
      toolbox: {
          feature: {
              saveAsImage: {}
          }
      },
  series: [
{
  name:"新增确诊趋势",
      data: [<%=dateMap.get("2020-01-19")[0]%>, <%=dateMap.get("2020-01-20")[0]%>,
          <%=dateMap.get("2020-01-21")[0]%>, <%=dateMap.get("2020-01-22")[0]%>,
          <%=dateMap.get("2020-01-23")[0]%>, <%=dateMap.get("2020-01-24")[0]%>,
          <%=dateMap.get("2020-01-25")[0]%>,<%=dateMap.get("2020-01-26")[0]%>,
          <%=dateMap.get("2020-01-27")[0]%>,<%=dateMap.get("2020-01-28")[0]%>,
          <%=dateMap.get("2020-01-29")[0]%>,<%=dateMap.get("2020-01-30")[0]%>,
          <%=dateMap.get("2020-01-31")[0]%>,<%=dateMap.get("2020-02-01")[0]%>,
          <%=dateMap.get("2020-02-02")[0]%>],
      type: 'line',
       
      symbol:'star',//拐点样式
      symbolSize: 5,//拐点大小
      smooth: true,
      itemStyle : {
          normal : {
              lineStyle:{
                  color:"#EE3B3B",//折线颜色
                  borderColor:'#EE3B3B',
              }
          }
      },
  },
  {
  name:"新增疑似趋势",
      data: [<%=dateMap.get("2020-01-19")[1]%>, <%=dateMap.get("2020-01-20")[1]%>,
          <%=dateMap.get("2020-01-21")[1]%>, <%=dateMap.get("2020-01-22")[1]%>,
          <%=dateMap.get("2020-01-23")[1]%>, <%=dateMap.get("2020-01-24")[1]%>,
          <%=dateMap.get("2020-01-25")[1]%>,<%=dateMap.get("2020-01-26")[1]%>,
          <%=dateMap.get("2020-01-27")[1]%>,<%=dateMap.get("2020-01-28")[1]%>,
          <%=dateMap.get("2020-01-29")[1]%>,<%=dateMap.get("2020-01-30")[1]%>,
          <%=dateMap.get("2020-01-31")[1]%>,<%=dateMap.get("2020-02-01")[1]%>,
          <%=dateMap.get("2020-02-02")[1]%>],
      type: 'line',
      symbol:'star',//拐点样式
      symbolSize: 5,//拐点大小
      smooth: true,
      itemStyle : {
          normal : {
              lineStyle:{
                  color:"#EE7942",//折线颜色
                  borderColor:'#EE7942',
              }
          }
      },
  },
   
  {
  name:"治愈趋势",
      data: [<%=dateMap.get("2020-01-19")[2]%>, <%=dateMap.get("2020-01-20")[2]%>,
          <%=dateMap.get("2020-01-21")[2]%>, <%=dateMap.get("2020-01-22")[2]%>,
          <%=dateMap.get("2020-01-23")[2]%>, <%=dateMap.get("2020-01-24")[2]%>,
          <%=dateMap.get("2020-01-25")[2]%>,<%=dateMap.get("2020-01-26")[2]%>,
          <%=dateMap.get("2020-01-27")[2]%>,<%=dateMap.get("2020-01-28")[2]%>,
          <%=dateMap.get("2020-01-29")[2]%>,<%=dateMap.get("2020-01-30")[2]%>,
          <%=dateMap.get("2020-01-31")[2]%>,<%=dateMap.get("2020-02-01")[2]%>,
          <%=dateMap.get("2020-02-02")[2]%>],
      type: 'line',
      symbol:'star',//拐点样式
      symbolSize: 5,//拐点大小
      smooth: true,
      itemStyle : {
          normal : {
              lineStyle:{
                  color:"#20B2AA",//折线颜色
                  borderColor:'#20B2AA',
              }
          }
      },
  },
  {
  name:"死亡趋势",
      data: [<%=dateMap.get("2020-01-19")[3]%>, <%=dateMap.get("2020-01-20")[3]%>,
          <%=dateMap.get("2020-01-21")[3]%>, <%=dateMap.get("2020-01-22")[3]%>,
          <%=dateMap.get("2020-01-23")[3]%>, <%=dateMap.get("2020-01-24")[3]%>,
          <%=dateMap.get("2020-01-25")[3]%>,<%=dateMap.get("2020-01-26")[3]%>,
          <%=dateMap.get("2020-01-27")[3]%>,<%=dateMap.get("2020-01-28")[3]%>,
          <%=dateMap.get("2020-01-29")[3]%>,<%=dateMap.get("2020-01-30")[3]%>,
          <%=dateMap.get("2020-01-31")[3]%>,<%=dateMap.get("2020-02-01")[3]%>,
          <%=dateMap.get("2020-02-02")[3]%>],
      type: 'line',
      symbol:'star',//拐点样式
      symbolSize: 5,//拐点大小
      smooth: true,
      itemStyle : {
          normal : {
              lineStyle:{
                  color:"#36648B",//折线颜色
                  borderColor:'#36648B',
              }
          }
      },
  },
   
  ]
};
//初始化echarts实例
var myChart = echarts.init(document.getElementById('container'));
//使用制定的配置项和数据显示图表
myChart.setOption(option);

 

6、心路历程与收获

221701125张家榜:

一开始拿到这个作业我是觉得很困难,因为看到作业要求后,我觉得有很多功能难以实现,并且我也没有学过一些框架,一些技术上的问题难以解决,并且,我也没尝试过用web进行前后端数据交互。不过在后来在实现的过程中,不断上网查找资料解决难题,学习新技术,解决难题。这次作业让我意识到,光靠本科课程所学的知识是远远不够的,还要课外学习常用的技术。在这次作业,我负责写前端,队友负责写后端,最后由我整合,让我体会到团队合作的重要性。 我的队友是一位全能型选手,不管什么难题,只要交给他,他总能高效率地去完成。在此之前,我们经常一起讨论问题,一起分享成果,彼此十分熟悉,配合也很默契。即使这次作业对我来说十分困难,但是只要一想到与他合作,我就信心十足。一个优秀的队友在团队中是十分重要 ,我很庆幸能与他合作。在本次作业中,我们互相帮助,有困难一起解决。我希望今后还能有机会与他在此合作!

 

221701126 唐靖钧:

这次结对作业中我主要负责后端数据的读取、处理和接口的编写,本来想尝试使用python进行实时数据的爬取,但是由于水平有限,最终还是采用导入静态文件的方式来进行处理,这也是一个遗憾,借此机会也勉励自己一定要努力提升自己的技术,这样未来不会因为某些技术受限而无法实现某些需求。 我们两个人先确定了代码规范,这是编程的基础,也是一个良好习惯的养成,一个好的代码规范在团队协作中起到了至关重要的作用。 接着我们进行需求分析和代码设计,得出结论即为我负责后端读入文件,讲文件中的数据进行处理,接着编写接口返回这些以数组为结构的数据,前端调用我的接口即可绘制地图、折线图等。 无数次的QQ聊天交流,互相汇报两个人的进度以及当前困难遇到的困难,我想团队开发的魅力就体现于此吧。 每完成一个部分就上传至我们两个人的团队仓库,虽然这次结对作业只有两个人,但是也让我感受到团队协作的魅力,同伴需要什么接口,我就提供给他,也让我有了成就感,未来的软工实践团队项目应该会具挑战,但是我认为遇到困难不可怕,大家不沟通不交流才可怕,我也对未来的真正的项目团队协作充满了期待,也具有一定的正向压力。 我认为我的同伴是一个具有领导力的人,他能够清晰的分析任务的需求和所需技术,并且能够进行很好的分工,在我遇到一些困难无法实现的时候,我都会去求助于他,而他也会很耐心的为我找寻解决办法,我认为这次结对作业的核心在于结对,在于同伴,一个优秀的同伴会让自己在开发过程中不会惧怕困难,正如我上面所述,在这次任务中,我遇到了许多后端方面的问题,还有前后端交互的认识障碍,但是我们两个人能够互相帮助,共享资源,也就使得这些技术上的困难没有那么可怕了,我不担心麻烦他,我也希望他也能够在遇到困难时多麻烦我,希望我的同伴在未来的项目实践中能够一帆风顺,将来有机会一定会选择与他再次组队!

 

 

 

posted @ 2020-03-16 18:58  zi凡  阅读(196)  评论(0编辑  收藏  举报