• 任务十七:零基础JavaScript编码(五)


    任务目的

    • 在上一任务基础上继续JavaScript的体验
    • 接触更加复杂的表单对象
    • 实现页面上的一个完整交互功能
    • 用DOM实现一个柱状图图表

    任务描述

    • 参考以下示例代码,原始数据包含几个城市的空气质量指数数据
    • 用户可以选择查看不同的时间粒度,以选择要查看的空气质量指数是以天为粒度还是以周或月为粒度
      • 天:显示每天的空气质量指数
      • 周:以自然周(周一到周日)为粒度,统计一周7天的平均数为这一周的空气质量数值,如果数据中缺少一个自然周的几天,则按剩余天进行计算
      • 月:以自然月为粒度,统一一个月所有天的平均数为这一个月的空气质量数值
    • 用户可以通过select切换城市
    • 通过在"aqi-chart-wrap"里添加DOM,来模拟一个柱状图图表,横轴是时间,纵轴是空气质量指数,参考图(点击打开)。天、周、月的数据只根据用户的选择显示一种。
      • 天:每天的数据是一个很细的矩形
      • 周:每周的数据是一个矩形
      • 月:每周的数据是一个很粗的矩形
    • 鼠标移动到柱状图的某个柱子时,用title属性提示这个柱子的具体日期和数据

    task.html

    <!DOCTYPE>
    <html>
      <head>
        <meta charset="utf-8">
        <title>IFE JavaScript Task 01</title>
        <script src="task.js"></script>
      </head>
    <body>
      <fieldset id="form-gra-time">
        <legend>请选择日期粒度:</legend>
        <label>日<input name="gra-time" value="day" type="radio" checked="checked"></label>
        <label>周<input name="gra-time" value="week" type="radio"></label>
        <label>月<input name="gra-time" value="month" type="radio"></label>
      </fieldset>
    
      <fieldset>
        <legend>请选择查看的城市:</legend>
        <select id="city-select">
          <option>北京</option>
        </select>
      </fieldset>
    
      <div class="aqi-chart-wrap">
      </div>
    </body>
    </html>
    

    task.js

    /* 数据格式演示
    var aqiSourceData = {
      "北京": {
        "2016-01-01": 10,
        "2016-01-02": 10,
        "2016-01-03": 10,
        "2016-01-04": 10
      }
    };
    */
    
    // 以下两个函数用于随机模拟生成测试数据
    function getDateStr(dat) {
      var y = dat.getFullYear();
      var m = dat.getMonth() + 1;
      m = m < 10 ? '0' + m : m;
      var d = dat.getDate();
      d = d < 10 ? '0' + d : d;
      return y + '-' + m + '-' + d;
    }
    function randomBuildData(seed) {
      var returnData = {};
      var dat = new Date("2016-01-01");
      var datStr = ''
      for (var i = 1; i < 92; i++) {
        datStr = getDateStr(dat);
        returnData[datStr] = Math.ceil(Math.random() * seed);
        dat.setDate(dat.getDate() + 1);
      }
      return returnData;
    }
    
    var aqiSourceData = {
      "北京": randomBuildData(500),
      "上海": randomBuildData(300),
      "广州": randomBuildData(200),
      "深圳": randomBuildData(100),
      "成都": randomBuildData(300),
      "西安": randomBuildData(500),
      "福州": randomBuildData(100),
      "厦门": randomBuildData(100),
      "沈阳": randomBuildData(500)
    };
    
    // 用于渲染图表的数据
    var chartData = {};
    
    // 记录当前页面的表单选项
    var pageState = {
      nowSelectCity: -1,
      nowGraTime: "day"
    }
    
    /**
     * 渲染图表
     */
    function renderChart() {
    
    }
    
    /**
     * 日、周、月的radio事件点击时的处理函数
     */
    function graTimeChange() {
      // 确定是否选项发生了变化 
    
      // 设置对应数据
    
      // 调用图表渲染函数
    }
    
    /**
     * select发生变化时的处理函数
     */
    function citySelectChange() {
      // 确定是否选项发生了变化 
    
      // 设置对应数据
    
      // 调用图表渲染函数
    }
    
    /**
     * 初始化日、周、月的radio事件,当点击时,调用函数graTimeChange
     */
    function initGraTimeForm() {
    
    }
    
    /**
     * 初始化城市Select下拉选择框中的选项
     */
    function initCitySelector() {
      // 读取aqiSourceData中的城市,然后设置id为city-select的下拉列表中的选项
    
      // 给select设置事件,当选项发生变化时调用函数citySelectChange
    
    }
    
    /**
     * 初始化图表需要的数据格式
     */
    function initAqiChartData() {
      // 将原始的源数据处理成图表需要的数据格式
      // 处理好的数据存到 chartData 中
    }
    
    /**
     * 初始化函数
     */
    function init() {
      initGraTimeForm()
      initCitySelector();
      initAqiChartData();
    }
    
    init();
    
    

    任务注意事项

    • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
    • 请注意代码风格的整齐、优雅
    • 代码中含有必要的注释
    • 示例图仅为参考,不需要完全一致
    • 点击select或者radio选项时,如果没有发生变化,则图表不需要重新渲染
    • 建议不使用任何第三方库、框架
    • 示例代码仅为示例,可以直接使用,也可以完全自己重写

    任务完成与总结:

     我看不懂的JS代码:

    // 以下两个函数用于随机模拟生成测试数据
    function getDateStr(dat) {
        var y = dat.getFullYear();
        var m = dat.getMonth() + 1;
        m = m < 10 ? '0' + m : m;
        var d = dat.getDate();
        d = d < 10 ? '0' + d : d;
        return y + '-' + m + '-' + d;
    }
    
    function randomBuildData(seed) {
        var returnData = {};
        var dat = new Date("2016-01-01");
        var datStr = '';
        for (var i = 1; i < 92; i++) {
            datStr = getDateStr(dat);
            returnData[datStr] = Math.ceil(Math.random() * seed);
            dat.setDate(dat.getDate() + 1);
        }
        return returnData;
    }
    
    var aqiSourceData = {
        "北京": randomBuildData(500),
        "上海": randomBuildData(300),
        "广州": randomBuildData(200),
        "深圳": randomBuildData(100),
        "成都": randomBuildData(300),
        "西安": randomBuildData(500),
        "福州": randomBuildData(100),
        "厦门": randomBuildData(100),
        "沈阳": randomBuildData(500)
    };
    
    var colors = ['#16324a', '#24385e', '#393f65', '#4e4a67', '#5a4563', '#b38e95',
                  '#edae9e', '#c1b9c2', '#bec3cb', '#9ea7bb', '#99b4ce', '#d7f0f8'];
    
    // 用于渲染图表的数据
    var chartData = {};
    
    // 记录当前页面的表单选项
    var pageState = {
        nowSelectCity: -1,
        nowGraTime: "day"
    }
    
    function getWidth(width, len) {
        var posObj = {};
        posObj.width = Math.floor(width / (len*2));
        posObj.left = Math.floor(width / len);
        posObj.offsetLeft = (width - posObj.left * (len - 1) - posObj.width) / 2;
        return posObj;
    }
    
    function getHintLfeft(posObj, i){
        if (posObj.left * i + posObj.offsetLeft + posObj.width / 2 - 60 <= 0) {
            return 5;
        } else if (posObj.left * i + posObj.offsetLeft + posObj.width / 2 + 60 >= 1200) {
            return (posObj.left * i + posObj.offsetLeft + posObj.width / 2 - 110);
        } else  {
            return (posObj.left * i + posObj.offsetLeft + posObj.width / 2 - 60);
        }
    }
    
    function getTitle() {
        switch (pageState.nowGraTime) {
            case "day":
                return "每日";
            case "week":
                return "周平均";
            case "month":
                return "月平均";
        }
    }
    
    /**
     * addEventHandler方法
     * 跨浏览器实现事件绑定
     */
    function addEventHandler(ele, event, hanlder) {
        if (ele.addEventListener) {
            ele.addEventListener(event, hanlder, false);
        } else if (ele.attachEvent) {
            ele.attachEvent("on"+event, hanlder);
        } else  {
            ele["on" + event] = hanlder;
        }
    }
    
    /**
     * 渲染图表
     */
    function renderChart() {
        var innerHTML = "", i = 0;
        var wrapper = document.getElementById("aqi-chart-wrap");
        var width = wrapper.clientWidth;
        var selectedData = chartData[pageState.nowGraTime][pageState.nowSelectCity];
        var len = Object.keys(selectedData).length;
        var posObj = getWidth(width, len);
        innerHTML += "<div class='title'>" + pageState.nowSelectCity + "市01-03月"+ getTitle() +"空气质量报告</div>"
        for (var key in selectedData) {
            innerHTML += "<div class='aqi-bar " + pageState.nowGraTime + "' style='height:" + selectedData[key] + "px;  " + posObj.width +"px; left:" + (posObj.left * i + posObj.offsetLeft) + "px; background-color:" + colors[Math.floor(Math.random() * 11)] + "'></div>"
            innerHTML += "<div class='aqi-hint' style='bottom: " + (selectedData[key] + 10) + "px; left:" + getHintLfeft(posObj, i++) + "px'>" + key + "<br/> [AQI]: " + selectedData[key] + "</div>"
        }
        wrapper.innerHTML = innerHTML;
    }
    
    /**
     * 日、周、月的radio事件点击时的处理函数
     */
    function graTimeChange(radio) {
        // 确定是否选项发生了变化
        var value = radio.value;
        var item = radio.previousElementSibling;
        var items = document.getElementsByTagName('span');
        for (var i = 0; i < items.length; i++) {
            items[i].className = "";
        }
        item.className = "selected";
        if (value !== pageState.nowGraTime) {
            // 设置对应数据
            pageState.nowGraTime = value;
            // 调用图表渲染函数
            renderChart();
        }
    }
    
    /**
     * select发生变化时的处理函数
     */
    function citySelectChange() {
        // 确定是否选项发生了变化
        var city = this.value;
        if (city !== pageState.nowSelectCity) {
            // 设置对应数据
            pageState.nowSelectCity = city;
            // 调用图表渲染函数
            renderChart();
        }
    }
    
    /**
     * 初始化日、周、月的radio事件,当点击时,调用函数graTimeChange
     */
    function initGraTimeForm() {
        var radio = document.getElementsByName('gra-time');
        for (var i = 0; i < radio.length; i++) {
            (function (m) {
                addEventHandler(radio[m], 'click', function () {
                    graTimeChange(radio[m])
                })
            })(i);
        }
        addEventHandler(document, 'mouseover', function(event){
            var ele = event.target;
            ele.className += " show";
        });
        addEventHandler(document, 'mouseout', function(event){
            var ele = event.target;
            ele.className = ele.className.replace(/show/, "");
        });
    }
    
    /**
     * 初始化城市Select下拉选择框中的选项
     */
    function initCitySelector() {
        // 读取aqiSourceData中的城市,然后设置id为city-select的下拉列表中的选项
        var select = document.getElementById("city-select");
        var cityArr = Object.getOwnPropertyNames(aqiSourceData);
        var htmlArr = cityArr.map(function(item) {
            return "<option>" + item + "</option>";
        });
        pageState.nowSelectCity = cityArr[0];
        select.innerHTML = htmlArr.join("");
        // 给select设置事件,当选项发生变化时调用函数citySelectChange
        addEventHandler(select, 'change', citySelectChange);
    
    }
    
    /**
     * 初始化图表需要的数据格式
     */
    function initAqiChartData() {
        // 将原始的源数据处理成图表需要的数据格式
        var week = {}, count = 0, singleWeek = {},
            month = {}, mcount = 0, singleMonth = {};
    
        for (var key in aqiSourceData) {
            var tempCity = aqiSourceData[key]
            var keyArr = Object.getOwnPropertyNames(tempCity);
            var tempMonth = keyArr[0].slice(5, 7);
            var weekInit = 4, weekCount = 0;
            for (var i = 0; i < keyArr.length; i++, weekInit++) {
                count += tempCity[keyArr[i]];
                mcount += tempCity[keyArr[i]];
                weekCount++;
                if ((weekInit+1) % 7 == 0 || i == keyArr.length - 1 || keyArr[i+1].slice(5, 7) !== tempMonth) {
                    var tempKey = keyArr[i].slice(0, 7) + "月第" + (Math.floor(weekInit / 7) + 1) + "周";
                    singleWeek[tempKey] = Math.floor(count / weekCount);
    
                    if (i != keyArr.length - 1 && keyArr[i+1].slice(5, 7) !== tempMonth) {
                        weekInit = weekCount % 7;
                    }
                    count = 0;
                    weekCount = 0;
    
                    if (i == keyArr.length - 1 || keyArr[i+1].slice(5, 7) !== tempMonth) {
                        tempMonth = (i == keyArr.length - 1) ? keyArr[i].slice(5, 7) : keyArr[i+1].slice(5, 7);
                        var tempMKey = keyArr[i].slice(0, 7);
                        var tempDays = keyArr[i].slice(-2);
                        singleMonth[tempMKey] = Math.floor(mcount / tempDays);
                        mcount = 0;
                    }
                }
            }
            week[key] = singleWeek;
            month[key] = singleMonth;
            singleWeek = {};
            singleMonth = {};
        }
        // 处理好的数据存到 chartData 中
        chartData.day = aqiSourceData;
        chartData.week = week;
        chartData.month = month;
        renderChart();
    }
    
    /**
     * 初始化函数
     */
    function init() {
        initGraTimeForm();
        initCitySelector();
        initAqiChartData();
    }
    
    init()

    效果展示

    到了这步,有点小绝望,心里有些打击。看来得继续加油,好好加油!

  • 相关阅读:
    centos7 安装mysql
    基于flask+requests 个人博客
    python csv、json、pickle数据持久化
    Python之容器、迭代器、生成器
    AJAX常用方法详解
    Python之format详解
    Flask使用MySql数据库
    git 公共服务器
    pci 记录
    检查ept
  • 原文地址:https://www.cnblogs.com/fengxiongZz/p/6837373.html
Copyright © 2020-2023  润新知