zoukankan      html  css  js  c++  java
  • 结对第二次作业—某次疫情统计可视化的实现

    这个作业属于哪个课程 2020春|S班(福州大学)
    这个作业要求在哪里 结对第二次作业
    结对学号 221701336、221701331
    这个作业的目标 某次疫情统计可视化的实现
    作业正文 结对第二次作业博客
    其他参考文献 《腾讯web代码规范》、Echarts官方文档及教程、CSDN

    一、Github仓库与代码规范

    二、成品展示


    三、结对讨论

    最开始我们讨论并学习了Echarts的用法

    然后对是否使用爬虫技术获得数据进行了讨论

    获得了json数据文件

    需求讨论阶段



    后续编码过程



    四、设计实现

    功能结构图

    功能结构图

    • 数据部分
      • 此次实践的数据来自助教提供的文件,借助寒假第二次作业中实现的数据统计工具(进行了一些修改,并辅以手工调整),生成了上文第三部分中符合我们约定格式的json文件。由于纯前端无法方便的访问本地文件,我们把json格式的数据改写成js文件,这样页面就可以通过<script>标签直接访问数据。
      • 出于方便的考虑,我们用了两个工具函数getSpecifiedDatagetStatisticData(见下文第五部分)进行数据读取,提升了语义化。
    • 前端部分
      • 我们采用的是jQuery库原生html+css+js来编写网页。可视化的重任放在了优秀的图标库Echarts上,通过引入中国地图的china.js文件并在echarts的option.geo.map声明使用,实现了中国地图可视化部分的显示。有关可视化的细节请移步第五部分。
      • 以生成的中国地图作为首页,点击省份后跳转到该省份的趋势图页面。后来考虑到用户体验的问题,我们决定使用layer弹层,借助弹出窗口展示各省份的趋势图,优化用户操作的连贯性。
      • 用户可以通过切换时间查看不同时刻的疫情地图和统计数据,为此我们绑定了change/click事件,触发时自动取数据并更新到地图/趋势图上。得益于echarts可以异步加载或更新数据,这一过程还是比较轻松的。
      • 同样出于用户体验的考虑,在查看历史记录时,我们动态限制了比例尺的上限,避免了一个省份颜色太深而其他省份太浅的状况。
      • 最后完善样式和页面时,模仿了浏览器的标签页进行类型切换,并使用css3的transition,让切换变得更加平滑。
    • 后端&爬虫
      • 暂未实现

    五、代码说明

    首先是地图,主要还是依靠导入echarts.js以及China.js,然后对相应的类和属性注入数据

    • tooltip实现了鼠标悬浮在各省上,显示相应数据
    • visualMap则设置了页面左下角的颜色标注块的各项属性
    • geo设定了type为中国地图,并对各类缩放及文本格式进行设置
    let option = {
        title: {
            text: '2020-02-02累计确诊情况地图'
        },
        tooltip: {
            formatter: function (params, ticket, callback) {
                return params.seriesName + '<br />' + params.name + ':' + params.value
            } //数据格式化
        },
        visualMap: {
            min: 0,
            max: 1500,
            left: 'left',
            top: 'bottom',
            text: ['高', '低'], //取值范围的文字
            inRange: {
                color: ['#ffffff', '#974236'] //取值范围的颜色
            },
            show: true //图注
        },
        geo: {
            map: 'china',
            roam: false, //不开启缩放和平移
            zoom: 1.23, //视角缩放比例
            label: {
                normal: {
                    show: true,
                    fontSize: '10',
                    color: 'rgba(0,0,0,0.7)'
                }
            },
            itemStyle: {
                normal: {
                    borderColor: 'rgba(0, 0, 0, 0.2)'
                },
                emphasis: {
                    areaColor: '#F3B329', //鼠标选择区域颜色
                    shadowOffsetX: 0,
                    shadowOffsetY: 0,
                    shadowBlur: 20,
                    borderWidth: 0,
                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
            }
        },
        series: [{
            name: '确诊人数',
            type: 'map',
            geoIndex: 0,
            data: dataList
        }]
    }
    

    这一部分则是实现了点击省份弹窗曲线图窗口

    myChart.on('click', function (params) {
        console.log(params)
        const href = './province.html?province=' + params.data.name
        layer.open({
            type: 2,
            title: params.data.name + '省疫情详细情况',
            shadeClose: true,
            shade: 0.8,
            area: ['840px', '750px'],
            content: href 
          })
    })
    

    这是地图页面的时间选择部分,通过监听下拉菜单的选取事件,调用getSpecifiedData函数获取数据生成dataList并更新进echarts

    $('#date-picker').on('change', e => {
        const newDate = e.target.value,
              type = $('.type-btn--active')[0].dataset.index
              typeText = $('.type-btn--active')[0].innerText
        dataList = provinces.map(provinceName => ({
            name: provinceName,
            value: getSpecifiedData(type, provinceName, newDate).infected
        }))
        option.series[0].data = dataList
        let max = Math.max(...dataList.map(v => v.value), 50)
        max = max > 2000 ? 2000 : max // 避免差异过大
        option.visualMap.max = max
        option.title.text = newDate + typeText + '情况地图'
        myChart.setOption(option)
    })
    

    通过该部分代码,在曲线图页面鼠标悬浮显示相应数据,重点是掌握param的各项参数,常用的包含有:

    • param.name:X轴的值
    • param.data:Y轴的值
    • param.value:Y轴的值
    • param.type:点击事件均为click
    • param.seriesName:legend的名称(即'累计确诊''新增确诊''累计治愈''累计死亡')
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'cross',
                crossStyle: {
                    color: '#999'
                }
            },
            formatter: function(params) {
                let html = params[0].name + '<br>'
                for (const param of params) {
                    html += param.seriesName + '  ' + param.data + '<br>'
                }
                return html
            }
        },
    

    曲线图数据分配

    以湖北省新增感染为例:通过getStatisticData函数获得数据存储在augmentInfectedRecord里,并通过echarts的data属性获取数据

    const augmentInfectedRecord = getStatisticData(2, 'infected', province)
    
        data = [{
            name: '新增确诊',
            type: 'line',
            data: augmentInfectedRecord
        },
    

    两个用于读取数据的函数

    /**
     * 获取指定类型、日期、省份的数据(无合法性校验)
     * @param {String|Number} scale 1:累计, 2:当日
     * @param {String} province 省份名,默认全国
     * @param {String} date YYYY-MM-DD格式的日期(某日或截至某日的数量),默认最新
     * @returns {Object}
     */
    function getSpecifiedData (scale, province = '全国', date = '2020-02-02') {
        scale = scale == 1 ? 'aggregate' : 'augment'
        let result = {}
        const empty = {
            "infected": 0,
            "suspect": 0,
            "cure": 0,
            "death": 0
        }
        try {
            result = log[scale][date][province]
        } catch(e) {
            console.warn(e)
            result = empty
        }
        return result || empty
    }
    
    /**
     * 获取指定省份、类型的所有数据(无合法性校验)
     * @param {String|Number} scale 1:累计, 2:当日
     * @param {String} type 数据类型,infected|suspect|death|cure
     * @param {String} province 省份名,默认全国
     * @returns {Array}
     */
    function getStatisticData (scale, type, province = '全国') {
        scale = scale == 1 ? 'aggregate' : 'augment'
        let result = []
        Object.values(log[scale]).forEach(day => {
            if (day[province]) {
                result.push(day[province][type])
            } else {
                result.push(0)
            }
        })
        return result
    }
    

    统计数据的格式

    const log = Object.freeze({
        "aggregate": {
            "2020-01-19": {
                "广东": {
                    "infected": 1,
                    "suspect": 0,
                    "cure": 0,
                    "death": 0
                },
                ...
            },
            ...
        }
        "augment": {...}
    }
    

    六、心路历程和收获&评价结对队友

    • 心路历程和收获:一个全靠echarts支撑起的项目。echarts是个非常牛x的工具,用它可以非常方便地画图表,感谢开发团队为前端领域做出的贡献。
    • 评价结对队友:积极主动,阻止了我继续摸鱼下去的念头。配合高效、紧密,沟通顺畅,合作起来十分愉快。希望能选个专精的方向加大力度,也希望下次能继续深入合作,奥里给!
  • 相关阅读:
    二进制位运算
    Leetcode 373. Find K Pairs with Smallest Sums
    priority_queue的用法
    Leetcode 110. Balanced Binary Tree
    Leetcode 104. Maximum Depth of Binary Tree
    Leetcode 111. Minimum Depth of Binary Tree
    Leetcode 64. Minimum Path Sum
    Leetcode 63. Unique Paths II
    经典的递归练习
    案例:java中的基本排序
  • 原文地址:https://www.cnblogs.com/llddcc/p/12506911.html
Copyright © 2011-2022 走看看