结对作业(二):某次疫情统计的可视化实现
这个作业属于哪个课程 | 2020软件工程W班 |
---|---|
这个作业要求在哪里 | 结对作业(二)要求 |
结对学号 | <221701436><181700141> |
这个作业的目标 | 使用Echarts等框架和技术做出像模像样的疫情统计页面 |
作业正文 | 本文链接在这里! |
其他参考文献 | bilibili的教学视频 |
1.成品展示
光标移动到地图上方显示高亮和数据
点击某省份跳转至趋势图页面
点击滚动新闻的“查看详情”进入详情页
2、结对讨论及设计思路
延续上次结对作业的思路,我们打算用Echarts来显示地图和趋势图,关于数据来源,我们用爬虫爬取了丁香园网站的数据
基本思路:利用fetch来获取data.json文件内容,然后将数据填入echarts图中。设置点击事件,当点击某一省份的时候跳转页面到province.html来显示该省份具体情况(趋势图等)
-
讨论截图
虽然讨论思路之路曲曲折折,我们最终形成了上述设计思路
3、代码说明
+功能结构模式图
- spider.js
const superagent = require('superagent');
const cheerio = require('cheerio');
const fs = require('fs');
const path = require('path');
const url = `https://ncov.dxy.cn/ncovh5/view/pneumonia`;
superagent
.get(url)
.then(res => {
//console.log(res.text); //响应的内容,浏览器可以解析html 但是node端不行
const $ = cheerio.load(res.text);
//获取全国疫情数据
var $getListByCountryTypeService1 = $('#getListByCountryTypeService1').html();
//获取统计数据
var $getStatisticsService = $('#getStatisticsService').html();
//console.log($getListByCountryTypeService1);
//使用eval
var dataObj = {};
eval($getListByCountryTypeService1.replace(/window/g, 'dataObj'));
eval($getStatisticsService.replace(/window/g, 'dataObj'));
//console.log(dataObj);
//将获取到的数据写入本地
fs.writeFile(path.join(__dirname, './data.json'), JSON.stringify(dataObj), err => {
if (err) throw err;
console.log("数据写入成功");
})
})
设计思路:利用superagent包(一个http方面的库,可以发起get和post请求)和cheerio包(为服务器特别定制的、快速、灵活、实施的jQuery)来爬取数据,使用eval函数来处理数据最后将数据保存到data.json文件中。
- 新型冠状病毒全国分布.html
<!--将图标配置应用到容器里-->
<script>
//存储获取到的数据
var epidemicData = [];
fetch('./server/data.json')
.then(res => res.json())//把可读的数据流转为json格式
.then(res => {
//console.log(res);
//获取各省数据
var getListByCountryTypeService1 = res.getListByCountryTypeService1;
//处理返回的数据,转为echarts可直接使用的数据
getListByCountryTypeService1.forEach(element => {
epidemicData.push({
name: element.provinceShortName,
value: element.currentConfirmedCount,//当前确诊人数(显示)
confirmedCount: element.confirmedCount,//累计确诊人数
deadCount: element.deadCount,//死亡人数(显示)
curedCount: element.curedCount,//治愈人数(显示)
time: element.modifyTime//时间(不显示)
});
//获取全国数据,以及和昨日对比的数据
var getStatisticsService = res.getStatisticsService;
//console.log(getStatisticsService.confirmedIncr);
//更新网页上全国数据以及和昨日对比的数据
document.getElementById('currentConfirmedCount').innerHTML = "现有确诊" + getStatisticsService.currentConfirmedCount;
document.getElementById('confirmedCount').innerHTML = "累计确诊" + getStatisticsService.confirmedCount;
document.getElementById('suspectedCount').innerHTML = "疑似人数" + getStatisticsService.suspectedCount;
document.getElementById('curedCount').innerHTML = "治愈人数" + getStatisticsService.curedCount;
document.getElementById('deadCount').innerHTML = "死亡人数" + getStatisticsService.deadCount;
document.getElementById('seriousCount').innerHTML = "现存重症" +getStatisticsService.seriousCount;
document.getElementById('suspectedIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.suspectedIncr);
document.getElementById('currentConfirmedIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.currentConfirmedIncr);
document.getElementById('confirmedIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.confirmedIncr);
document.getElementById('curedIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.curedIncr);
document.getElementById('deadIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.deadIncr);
document.getElementById('seriousIncr').innerHTML = "较昨日" + signedNum(getStatisticsService.seriousIncr);
//更新网页上关于疫情的描述,如潜伏期、宿主等
document.getElementById('susceptiblePop').innerHTML = getStatisticsService.remark1;
document.getElementById('incubationPeriod').innerHTML = getStatisticsService.remark2;
document.getElementById('parasitifer').innerHTML = getStatisticsService.remark3;
document.getElementById('virus').innerHTML = getStatisticsService.note1;
document.getElementById('source').innerHTML = getStatisticsService.note2;
document.getElementById('route').innerHTML = getStatisticsService.note3;
//更新时间
var date = new Date(parseInt(getStatisticsService.modifyTime));
document.getElementById('time').innerHTML = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
//最新资讯
var breaknews =getStatisticsService.marquee;
利用fetch来获取data.json文件内容,然后将数据填入echarts图中。设置点击事件,当点击某一省份的时候跳转页面到province.html来显示该省份具体情况
myChart.on('click', function (params) {
//南海诸岛不跳转
if (typeof (params.data) == typeof (undefined)) {
alert("暂无详细数据");
return;
}
if (params.data.name == "台湾" || params.data.name == "香港" || params.data.name == "澳门") {
alert("暂无详细数据");
return;
}
//console.log(params.data);
//跳转页面,同时对参数进行编码
window.location.href = `./province.html?` +
window.btoa(window.encodeURIComponent(`name=${params.data.name}¤tConfirmedCount=${params.data.value}
&confirmedCount=${params.data.confirmedCount}&deadCount=${params.data.deadCount}&curedCount=${params.data.curedCount}
&time=${params.data.time}`));
});
})
设置点击事件,南海诸岛、港澳台不提供详细数据。利用window.location.href来实现页面跳转,利用window.bota对传递的参数进行编码使得参数值不可直接看出。传递的参数有:点击的省份名、该省的当前确诊人数、累计确诊人数、死亡和治愈人数以及这些数据最近更新的时间。
- province.html
<script>
//获得参数字符串
var paramsString = window.location.search.substring(1);
//解码
paramsString = window.decodeURIComponent(window.atob(paramsString));
//存储个参数及其值
var params = {};
//以&为边界将参数字符串拆分为数组
var parameters = paramsString.split('&');
for (var i = 0; i < parameters.length; i++) {
var s = parameters[i];
var l = s.length;
var index = s.indexOf('=');
var key = s.substring(0, index);
var value = s.substring(index + 1);
params[key] = value;
}
//省份
var province = params.name;
//存放该省份的确诊数据
var confirmData = [];
//存放该省份的治愈数据
var cureData = [];
//存放该省份的死亡数据
var deathData = [];
//更新页面上关于省份、现存确诊等的描述
document.getElementById('province').innerHTML = province+"疫情趋势图";
document.getElementById('currentConfirmedCount').innerHTML = "现存确诊\n" + params.currentConfirmedCount;
document.getElementById('confirmedCount').innerHTML = "累计确诊\n" + params.confirmedCount;
document.getElementById('deadCount').innerHTML = "死亡人数\n" + params.deadCount;
document.getElementById('curedCount').innerHTML = "治愈人数\n" + params.curedCount;
//更新时间
var date = new Date(parseInt(params.time));
//console.log(date);
document.getElementById('time').innerHTML = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
//获得确诊数据并画出趋势图
fetch(`./confirmData/${province}.txt`)
.then(res => res.text())
.then(res => {
confirmData = JSON.parse(res);
var myChart = echarts.init(document.getElementById("confirmData"));
var option = {
title: {
text: `${province}确诊人数趋势图`,
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
},
legend: {
data: ['确诊人数'],
left: 'right',
top: '5%'
},
xAxis: {
//设置x轴为时间轴
type: 'time'
},
yAxis: {
name: '人'
},
series: [{
name: '确诊人数',
type: 'line',
data: confirmData,
symbolSize: 8, //拐点圆的大小
color: ['red'],//折线条的颜色
itemStyle: {
normal: {
lineStyle: {
width: 3
}
}
},
}]
};
myChart.setOption(option);
});//end of then
基本思路:通过传递过来的参数读取相应的数据文件然后显示。
通过fetch获取数据文件并处理后可直接将将数据赋予echarts图,txt文件内容为[[“XXXX-XX-XX”,Y],[“XXXX-XX-XX”,Y],…]其中XXXX-XX-XX为日期,Y为人数(如果是在confirmData文件夹里,就是确诊人数),文件名为省份名。
心路历程及队友评价
本次作业算是有一些挑战性的,因为我们一开始不知道实现这次作业需要什么技术,但是在经过讨论之后,加上有教学视频,通过对新知识的学习摸索,我们逐渐拓宽道路,分工合作。在这期间,我们碰到了一些印象比较深的困难:
-
1、fetch获取本地数据
未安装LiveServer前,通过fetch读取本地文件报错:Fetch APT cannot load XXXX URL scheme must be "http" or "https" for CORS request.
然后就去寻找解决方法,刚开始通过tomcat将data.json文件放到服务器上,然后在再去获取,还是报错;通过百度发现是因为浏览器安全限制不允许跨域访问,然后就百度修改了web.xml文件,ok可以运行。最后百度的时候看到可以安装LiveServer来实现fetch访问本地文件。
-
2、跳转页面时隐藏参数
刚开始直接通过window.bota直接编码来实现隐藏参数,但是对于中文乱码。百度发现window.bota只能针对ANSI然后看到一篇博客说可以先采用window.encodeURIComponent编码再是利用window.bota就可对中文编码。
队友评价:
-
221701436林晟:没想到队友在写代码的时候可以那么投入,而且思维还很敏捷,是我值得学习的对象;经过与队友的合作我认为我可以磨炼协商技巧,还应该克服拖延症。
-
181700141吴鸿敬:本次合作最终还是在截止日期前完成,与队友的合作虽然有时在一些问题上看法不相同;但是在经过交流后还是可以取得一致。从本次与队友合作开发项目的过程中学到了:对项目的完成应该设置多个时间节点,同时要按时完成。