zoukankan      html  css  js  c++  java
  • 20、任务十七——页面交互功能、柱状图的实现

    0、题目

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

    1、解答过程

    task17.html

     1 <!DOCTYPE html>
     2 <html>
     3   <head>
     4     <meta charset="utf-8">
     5     <title>IFE JavaScript Task 17</title>
     6     <style>
     7     #aqi-chart-wrap{
     8       width:90%;
     9       height:500px;
    10       display: flex;
    11       justify-content: center;
    12       align-content: center;
    13       align-items: flex-end;
    14       margin:10px auto;
    15     }
    16     .div{
    17       display:inline-block;
    18       width:20px;
    19       margin-left:3px;
    20     }
    21   </style>
    22   </head>
    23 <body>
    24   <fieldset id="form-gra-time">
    25     <legend>请选择日期粒度:</legend>
    26     <label><input name="gra-time" value="day" type="radio" checked="checked"></label>
    27     <label><input name="gra-time" value="week" type="radio"></label>
    28     <label><input name="gra-time" value="month" type="radio"></label>
    29   </fieldset>
    30  <fieldset>
    31     <legend>请选择查看的城市:</legend>
    32     <select id="city-select">
    33     </select>
    34   </fieldset>
    35  <div id="aqi-chart-wrap">  // 柱状图显示区
    36 
    37   </div>
    38 <script src="task17.js"> </script>
    39 </body>
    40 </html>

    task17.js

      1 /* 数据格式演示
      2 var aqiSourceData = {
      3   "北京": {
      4     "2016-01-01": 10,
      5     "2016-01-02": 10,
      6     "2016-01-03": 10,
      7     "2016-01-04": 10
      8   }
      9 };
     10 */
     11 // 以下两个函数用于随机模拟生成测试数据
     12 function getDateStr(dat) {
     13   var y = dat.getFullYear();    //返回表示当前年份的四位数字
     14   var m = dat.getMonth() + 1;   //getMonth()返回0-11的数来表示当前月份
     15   m = m < 10 ? '0' + m : m;
     16   var d = dat.getDate();         //返回月份中的某一天,1-31之间的数
     17   d = d < 10 ? '0' + d : d;
     18   return y + '-' + m + '-' + d;
     19 }
     20 function randomBuildData(seed) {
     21   var returnData = {};
     22   var dat = new Date("2016-01-01");
     23   var datStr = '';
     24   for (var i = 1; i < 92; i++) {
     25     datStr = getDateStr(dat);
     26     returnData[datStr] = Math.ceil(Math.random() * seed);   //得到与每天相对应的随机空气质量指数数据
     27     dat.setDate(dat.getDate() + 1);
     28   }
     29   return returnData;
     30 }
     31 
     32 var aqiSourceData = {
     33   "北京": randomBuildData(500),
     34   "上海": randomBuildData(300),
     35   "广州": randomBuildData(200),
     36   "深圳": randomBuildData(100),
     37   "成都": randomBuildData(300),
     38   "西安": randomBuildData(500),
     39   "福州": randomBuildData(100),
     40   "厦门": randomBuildData(100),
     41   "沈阳": randomBuildData(500)
     42 };
     43 // 用于渲染图表的数据
     44 var chartData = {};
     45 // 记录当前页面的表单选项
     46 var pageState= {
     47   nowSelectCity: "北京",
     48   nowGraTime: "day",
     49   20
     50 }
     51 var aqiChartWrap=document.getElementById("aqi-chart-wrap"),
     52     formGraTime=document.getElementById("form-gra-time"),
     53     citySelect=document.getElementById("city-select");
     54 /* 
     55 渲染图表 
     56  */
     57 function renderChart() {
     58   var content=" ";
     59   for(var item in chartData){
     60     var bg="#" + Math.random().toString(16).substring(2, 8);   //得到背景的随机颜色
     61     content+='<div class="div"style="height:'+chartData[item]+'px;'+pageState.width+'px;background-color:'+bg+';"'+'title="'+item+'  空气质量指数:'+chartData[item]+'">'+
     62    '</div>';
     63    }
     64    aqiChartWrap.innerHTML=content;
     65 }
     66 /**
     67  * 初始化日、周、月的radio事件,当点击时,调用函数graTimeChange
     68  */
     69 function initGraTimeForm() {
     70   formGraTime.addEventListener("click",graTimeChange);
     71 }
     72 /**
     73  * 日、周、月的radio事件点击时的处理函数
     74  */
     75 function graTimeChange() {
     76   // 确定是否选项发生了变化 
     77   var input=document.getElementsByTagName("input");
     78   for(var i=0;i<input.length;i++){
     79     if(input[i].checked){     //确定选中的粒度
     80       pageState.nowGraTime=input[i].value;  // 设置对应数据
     81     }
     82   }
     83   initAqiChartData();   // 调用图表渲染函数
     84 }
     85 /**
     86  * 初始化城市Select下拉选择框中的选项 
     87  */
     88 function initCitySelector() {
     89   // 读取aqiSourceData中的城市,然后设置id为city-select的下拉列表中的选项
     90     var content=" ";
     91     for(var city in aqiSourceData ){
     92         content+='<option value="'+city+'" >'+city+'</option>';
     93     }  
     94      citySelect.innerHTML=content;
     95     // 给select设置事件,当选项发生变化时调用函数citySelectChange
     96      citySelect.addEventListener("change",citySelectChange);
     97 }
     98 /**
     99  * select发生变化时的处理函数
    100  */
    101 function citySelectChange() {
    102   var options=document.getElementsByTagName("option");
    103   for(var i=0;i<options.length;i++){
    104     if(options[i].selected){      // 确定被选中的城市
    105       pageState.nowSelectCity=options[i].value;   // 设置对应数据
    106     }
    107   }     
    108   initAqiChartData();     // 调用原始数据处理函数
    109 }
    110 /**
    111  * 初始化图表需要的数据格式
    112  */
    113 function initAqiChartData() {
    114  //将选中城市的数据先放在chart中
    115   var chart=aqiSourceData[pageState.nowSelectCity];
    116   switch(pageState.nowGraTime){     //根据选择的粒度计算数据并保存至chartData
    117     case "day":{
    118       chartData={};
    119       chartData=chart;
    120       pageState.width=10;       //设置每个显示出来的柱子的宽度
    121       break;
    122     }
    123     case "week":{
    124       chartData={};
    125       var sum=0,i=0,week=0;
    126       for(var item in chart){
    127         sum+=chart[item];
    128         i++;
    129         if(new Date(item).getDay()==6) {
    130           week++;
    131           chartData['2016年第'+week+'周']=Math.round(sum/i);
    132           sum=0;i=0;
    133         }
    134      }
    135       if(sum!=0){
    136          week++;
    137          chartData['2016年第'+week+'周']=Math.round(sum/i);
    138       }
    139       pageState.width=100;
    140       break;
    141     }
    142     case "month":{
    143       chartData={};
    144       var sum=0,i=0,month=0;
    145       for(var item in chart){
    146         if((new Date(item)).getMonth()==month) {
    147           sum+=chart[item];
    148           i++;
    149         }
    150         else{
    151           month++;
    152           chartData['2016年'+month+'月']=Math.round(sum/i);
    153           sum=0;i=0;
    154           sum+=chart[item];
    155           i++;
    156         }
    157       }
    158       if(sum!=0){
    159         month++;
    160         chartData['2016年'+month+'月']=Math.round(sum/i);
    161       }
    162       pageState.width=300;
    163       break;
    164     }
    165   }
    166   renderChart();       //调用图表渲染函数
    167 }
    168 // 初始化函数
    169  function init() {
    170   initGraTimeForm()
    171   initCitySelector();
    172   initAqiChartData();
    173   renderChart();
    174 }
    175 init();

    2、遇到的问题

    (1)title属性:

      title 属性规定关于元素的额外信息。

      这些信息通常会在鼠标移到元素上时显示一段工具提示文本(tooltip text)。

    (2)onchange事件在数据变化时才会发生

      为了得到用户选择查看的城市并处理对应数据,给select设置事件,当选项发生变化时调用函数citySelectChange,修改pageState.nowSelectCity(记录当前页面表单的城市选项)的值,由于题目中给的pageState.nowSelectCity:-1;与后续的数据处理函数没有绑定,所以页面被打开时并不会渲染柱状图,又因为这里用到onchange事件监听选项变化,而onchange事件必须在数据有变化的时候才会发生,所以一开始默认选择的是北京,接着再点北京是不会触发事件的,必须先点其他城市,再点回北京才会出现柱状图,这里有两种方法避免这种情况:

      A、将pageState.nowSelectCity 最初默认值设置为“北京”,这样页面打开时就会呈现北京市的柱状图,之后选择其他的城市,onchange事件就会发生。

      B、在北京前面加一个option,选项名可以为“城市名”,之后用户无论选择什么城市,都会触发事件渲染图表;

      支持onchange事件的 HTML 标签:

      <input type="text">, <select>, <textarea>

      支持onchange事件的 JavaScript 对象:

       select, text, textarea,fileUpload(FileUpload 控件显示一个文本框控件和一个浏览按钮,使用户可以选择客户端上的文件并将它上载到 Web 服务器。)

    (3)自然周/月

      题目中要求用户选择 “周” 时要以自然周(周一到周日)为粒度,开始做的方法是从第一个数据开始,每7个数据求一个平均数,后来发现第一个数据也就是2016-01-01并不一定是一周的第一天,所以这种方法行不通。具体可行的方法如下:

      将所有的日期放在一个新的Date对象中,之后利用getDay()方法,该方法返回值是 0(周日) 到 6(周六) 之间的一个整数,所以当new Date.getDay()=6时就意味着一个自然周结束了,所以将每次new Date.getDay()=6之前的<=7个数据求平均即可,同时只要最后的求和!=0就说明最后一组不到7个数据,也应该求平均值。

      “月”要以自然月为粒度做法和上面类似,利用getMonth()方法,该方法返回值是 0(一月) 到 11(十二月) 之间的一个整数。

  • 相关阅读:
    AVAYA语音通知管理
    如何打出强烈低杆
    iSCSI存储技术全攻略
    域控制器的管理注意事项
    Ogre的ExampleApplication阅读
    CEImagesetEditor编译过程
    Ogre基础教程遇到的问题
    SQLServer中进行sql除法运算结果为小数时显示0的解决方案
    【全面解禁!真正的Expression Blend实战开发技巧】第五章 从最常用ButtonStyle开始 ImageButton
    silverlight,WPF动画终极攻略之白云飘,坐车去旅游篇(Blend 4开发)
  • 原文地址:https://www.cnblogs.com/cjlalala/p/5837976.html
Copyright © 2011-2022 走看看