关于dygraphs JavaScript Visualization Library的学习笔记
主要内容
1.    笔者留言
2.    什么是dygraphs?
3.    Dygraphs原理的简单说明
4.    Dygraphs的使用
5.    IE兼容性、常见问题和建议
6.    自己写的一个例子mydemo(主要是为了说明Options的使用)
笔者留言
如果读者的英文很好,可以直接无视这个笔记的大部分内容(除了注意点,IE兼容性和常见问题和建议)。
这个笔记,只是描述怎么使用dygraphs。对其底层的原理,由于个人技术水平有限,没有做太多的叙述。
文中的加红部分的内容都是注意点。
如果发现文中有什么地方有误,请及时提出(回复)。
本文原创,转载请注明URL。
       感想:
1.  开源的框架,源码可以适当地修改,以符合我们的需求。
2.  多看看JS基础知识
3.  多用度娘,Google。要注意分辨,多问人
4.  多做笔记
一、什么是dygraphs?
Dygraphs是一个开源的JS库;用于生成可与用户交互的、可缩放的时间图表。主要用于显示密集的数据集合,用户能够很好的浏览和查看数据。
下面是相关的URL:
dygraphs JavaScript charting library
Copyright (c) 2006-, Dan Vanderkam.(感谢这个人)
Documentation(使用指南,demo位置等等): http://dygraphs.com/
Support: http://groups.google.com/group/dygraphs-users
Source(源码发布状态): http://github.com/danvk/dygraphs
Issues: http://code.google.com/p/dygraphs/
源文件下载地址:https://github.com/danvk/dygraphs/downloads/
两种格式:对应不同的操作系统
Zip    (window xp)
tar.gz    (linux )
我用的是window xp ,下了zip的
注意点:dygraph-combined.js — This is not the file you're looking for. Please use http://dygraphs.com/dygraph-combined.js instead   <1KB
下载的zip中的dygraph-combined.js文件相当于是空的,要用下载这个地址的JS替换:
http://dygraphs.com/dygraph-combined.js
另下
二、Dygraphs原理的简单说明
JavaScript and the HTML canvas tag:  js + <canvas>实现(在一个画布上画东东)
1.利用JS动态生成一个<canvas>添加到JS动态生成的DIV元素标签(graphDiv包含了解1,2的所有内容)中,然后在<canvas></canvas>显示数据(图表);
(<canvas></canvas>会用DIV包含加入graphDiv)
2.       利用JS动态生成一个多个DIV元素标签,分别包含X,Y轴,图表标题的内容。加到第1步中DIV元素(graphDiv)中;
3.         在html, jsp等页面中准备一个DIV元素标签,来包含graphDiv。
当然还有其他的一些事件处理机制等等。
Ctrl + F   graphDiv   可以在dygraph-combined.js找到相应的代码
三、Dygraphs的使用
3.1、学习的两种方式
进入dygraphs的首页:http://dygraphs.com/
1.       可以把首页的内容全部看完(在首页的左边的导航)
 载的文件是js压缩格式的 (compressed)
载的文件是js压缩格式的 (compressed)
2.直接看例子(在首页的左边的导航)
 

3.2、第一个例子
结果图:

图1
可以在首页的图表中操作:在图表中:
双击:还原;
按住左键,拖动选择的图表内容会放大;
在图表上移动,高亮点 并 右上角会显示相应时间点的数据。
在html,jsp 页面中导入dygraph-combined.js和实例化一个Dygraph对象。
HTML:
----------------------------------------------------------------------------------------------------------------
<html>
<head>
<script type="text/***"   src="http://www.tyblog.com/dygraph-combined.js"></script><!—用这一个js就OK,封装了这个框架所有基本的JS,不包括后面的excanvas.js  interaction.js-->
</head>
<body>
<div id="graphdiv2" style="width:500px; height:300px;"></div>
<script type="text/***">
  g2 = new Dygraph(
***.getElementById("graphdiv2"),//图表显示的位置
"temperatures.csv", // 数据的所在位置
    {}          // options 可选配置参数
  );
</script>
</body>
</html>
---------------------------------------------------------------------------------------------------
3.2.1代码说明
这是一个最简单,最基本的例子。这里主要讲Dygraph对象的实例化:
构造函数有三个参数:
第一参数:图表要显示的位置(好像都是DIV元素)
第二参数:要显示的数据
第三参数:可选配置参数
这里最需要说明的是第二和第三个参数。
3.2.1.1第二参数:要显示的数据
数据有5种表现形式:
3.2.1.1.1 CSV data
CSV data又有三种表现形式:本质一样
(1) csv文件:这个有专门的软件可以生成,没有用过,不过我无意发现SQL Server数据库查询的结果可以保存成CSV文件。也可以直接TXT保存成CSV文件(应该可以,格式OK就行)。
(2)  TXT文件 记事本文件(这个很容易得到,从数据库中读到数据,再用IO流写到TXT)
(3)字符串
共同点:内容都必须符合一定的CSV格式
每条数据只占一行,第一行一般是用来确定每一列的含义,每行中每个数据值用逗号分隔,如下:
Date,High,Low
20070101,62,39
20070102,62,44
20070103,62,42
20070104,57,45
从上面的数据可以看出:
第一列表示时间,第二列和第三列分别是High,Low在相应时间的数值。
在图表显示如上图1所示。如果没有第一行(Date,High,Low),就要用可选参数labels来指定每列数据的含义。如:
new Dygraph(el,
                  "2009/07/12,100,200\n" +
                  "2009/07/19,150,201\n",
                  { labels: [ "Date", "Series1", "Series2" ] });
而"Date", "Series1", "Series2"分别对应图表的X轴,Y1轴,Y2轴。(Y轴数据一般是number,其他没有什么要求)。
而X轴一般用来表示时间。它有两种类型:
(1)日期格式字符串,支持以下几种:
l  2009-07-12
l  2009/07/12
l  2009/07/12 12
l  2009/07/12 12:34
l  2009/07/12 12:34:56
上面的数据格式字符串,会被自动解析成相应的时间
(2)数值格式(number)则是一个长整型(long),单位为ms 。不能直接解析成一个时间对象,要作相应的配置。如:
   new Dygraph(el,
                  "Date,Series1,Series2\n" +
                  "1247382000,100,200\n" +
                  "1247986800,150,201\n",
                  {//将long型转换成Date
                    xValueFormatter: Dygraph.dateString_,
                    xValueParser: function(x) { return 1000*parseInt(x); },
                    xTicker: Dygraph.dateTicker
                  });
3.2.1.1.2  URL
 通过一个URL访问远程的数据。
3.2.1.1.3  array (native format)  
一个js中的Array对象;如:
[
        [ new Date("2009/07/12"), 100, 200 ],
        [ new Date("2009/07/19"), 150, 220 ]
      ]
这种数据格式,可以看到没有指定(如:“Date,High,Low”)每列的含义。所以Array数据格式需要可选参数labels来指定每列的含义。例如:
new Dygraph(***.getElementById("graphdiv2"),
                  [
                    [1,10,100],
                         [2,20,80],
                    [3,50,60],
                    [4,70,80]
                 ],
                  {
                    labels: [ "x", "A", "B" ]
                  });
3.2.1.1.4   function
Functions can return strings, arrays, data tables, URLs, or any other data type.
一个函数:返回字符串,Array对象,DataTable ,URL 和其他符合CSV 数据格式的数据类型。
3.2.1.1.5  DataTable
Google Visualization Library DataTable object: 谷歌可视化库的数据表对象
3.2.1.2第三个参数:可选配置参数
第三个参数:框架中已经有相应的默认值,不过一般为了达到自己的需求,都会配置一些参数。由于参数太多,这里不做翻译了。用的时候,可以结合相应的例子和Options reference来学习。文章最后是我写的一个例子Mydemo(里面对我用到的可选配置参数的作了一些注释)。
3.3、Dygraph常用方法
g: 表示Dygraph对象实例
1.   g.***Options({可选配置参数}) 
生成g对象后,用来更新可选配置参数,来改变图表的某些状态。下面是几个函数,帮助理解:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
 * 右击,缩小图表
 *
 */
function zoomGraph() {
  var minDate = g.xAxisRange()[0]*(1.0000001); //x轴的最大和最小值(显示出来的部分):long型
  var maxDate = g.xAxisRange()[1]*(0.9999999);
    g.***Options({    //更新可选配置参数
      dateWindow: [minDate, maxDate]
    });
  }
  /**
   * 鼠标的滚轮的缩小图表
   *
   */
function zoomOutGraph() {
  var minDate = g.xAxisRange()[0]*(0.9999999);
  var maxDate = g.xAxisRange()[1]*(1.0000001);
    g.***Options({
      dateWindow: [minDate, maxDate]
    }); 
  }
/**
 * 鼠标的滚轮的放大图表
 */
function zoomInGraph() {
  var minDate = g.xAxisRange()[0]*(1.0000001);
  var maxDate = g.xAxisRange()[1]*(0.9999999);
 // var minValue = g.yAxisRange()[0]*(1.01);//y轴的最大和最小值(显示部分的)
  //var maxValue = g.yAxisRange()[1]*(1.01);
    g.***Options({
      dateWindow: [minDate, maxDate]
     // valueRange: [minValue, maxValue]
    })
  }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
2.       g.setSelection(row)
定位图表上的一点:参数row:将要选择点的数据在CSV文件(如果第一行是:Date,series1,series2,则不包括这一行)的第几行,从0开始。
(也就是图表数据中第几行(最小行为0))
如下所示:
Date,High,Low     (labels)
20070101,62,39     (row=0)
20070102,62,44     (row=1)
20070103,62,42     (row=2)
20070104,57,45   (row=3)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
 *:通过地图定位图表上的一点
 * @param time
 * @param row
 */
function ***(time,row){
         var minDate = dygraphTime-300000;// x轴是long类型,这里保持该点的左右各5分钟
         var maxDate = dygraphTime+300000;// 这个就是X轴的时间的long类型
         g.***Options( {
                    dateWindow: [minDate, maxDate]// 这里只能用键值对,不用函数。
          });
         var annotations = []; //清除所有点的注释
         g.setAnnotations(annotations);
         g.setSelection(row);
}      
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
四、IE的兼容性、常见问题和建议
对于IE兼容性问题:
最简单的办法:把http://dygraphs.com/tests/ 中随便一个例子的<body>前面的内容复制就行。
一般要加:
<!DOCTYPE html> <!—IE本身不支持HTML5<canvas>;  这个是为了在IE9中用微软自己实现的canvas  -->
<html>
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9"> <!—兼容IE6-IE8 -->
    <!--[if IE]><script src="path/to/excanvas.js"></script><![endif]-->   <!--微软自己实现的canvas -->
  </head>
注意点:即使加了上面的内容;IE8可能会不支持HTML5<canvas>。(原因: <!DOCTYPE html>会破坏excanvas)
 
3.       在实例Dygraph对象的第三个参数(options)中
最后一个 name : value不要加” , ”。因为IE不支持,会报错(其他浏览器OK)。
如:
new Dygraph(el, data, {  rollPeriod: 5,
  showRoller: true, // 最后一个配置,不要加逗号
})
4.       如果图表不显示,可以查看JS错误控制台,dygraph本身封装了日志记录功能:如error warning等
5.       CSV文件必须是可读的,否则XMLHttpRequest会取不到CSV文件。
6.       CSV文件内容的格式正确。当用到errorBars时的CSV内容格式要注意。
7.       不要把要显示图表的DIV放到一个<center>标签中,也不用CSS的样式:text-align:center来使图表居中。而是要用<table align=”center”><table>居中。
8.        dateWindow属性是一个Array对象,它的元素是long类型的,单位是ms。
dateWindow不要直接使用符合Date对象的字符串或Date对象赋值,要做相应的处理得到日期的ms值:Date.pase(string str)可以搞定)如:
g1 = new Dygraph(
             ***.getElementById("div_g1"),
             data, {
               dateWindow: [ Date.parse("2009/09/29 12:00:00"),
                             Date.parse("2009/10/10 12:00:00") ],
               labels: [ 'Date', 'Y1', 'Y2' ]
             }
           );
五、Mydemo
使用:把下面的代码复制到一个HTML页面中,然后放到下载的ZIP解压后的danvk-dygraphs-681a215\tests文件夹,就可以使用了。
这个例子的特点是:
1.  交互:与百度地图的操作相似
2.  在上面移动实时显示数据注释
测试:在IE firefox中测试OK
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9">
    <title>mydemo</title>
    <!--[if IE]>
    <script type="text/***" src="../excanvas.js"></script>
    <![endif]-->
    <!--
    For production (minified) code, use:压缩格式的dygraphs的JS库
    <script type="text/***" src="http://www.tyblog.com/dygraph-combined.js"></script>
    -->
 
    <script type="text/***" src="../dygraph-dev.js"></script><!--要注意加载JS的顺序,excanvas.js要在dygraph-dev.js的前面-->
       <script type="text/***" src="http://www.tyblog.com/interaction.js"></script> <!--用户与图表交互方式:如放大,缩小图表的方式-->
  </head>
  <body>
    <h2>mydemo</h2>
   <div id="my_chart"   style="height:400px; border:1px solid black;"></div>
 
 <script type="text/***">
 
/**
 * 判断系列名是series1还是series2,用不同的单位
 * @param name
 * @returns {String}
 */
function checkSerialName(name)
  {
     if(name=='series2')
     {
            return ' R/M';
     }
     else
     {
            return ' km/h';
     }
  }
     var data = [];//这里定义了一个Array对象,这里只显示3个数据
        data.push([1351571661000,0.0,678
                  ]);
       data.push([1351571672500,3.8,697
                  ]);
       data.push([1351571722500,31.0,1224
                  ]);
var g = new Dygraph(
                    ***.getElementById("my_chart"),//图表显示位置
                 data,   //'dygraphs/dygraphs.txt',
                  {
                      rollPeriod: 5,//放大的倍数,不知道放大什么,线看起来更圆滑
                      showRoller: true,//显示原点旁边的小文本框:rollPeriod的值//legend:'always',//总是显示右上角的数据
                      title:'title',//标题
                         titleHeight:50,//标题高度
                         avoidMinZero: true,//y轴的最小值不为0,相当于y=0那条线上升了。
                   axisLabelWidth:100,//X Y轴的标题的宽度
                width : 1500,//图表的宽度
               height: 350,//图表的宽度和高度
                         xValueFormatter: Dygraph.dateString_,//对x轴的long类型数据进行格式化成日期
                        xValueParser: function(x) { return parseInt(x); },
                          xTicker: Dygraph.dateTicker,
                        axisTickSize: 10,//与时间轴的时间高度有关//pixelsPerLabel:50,//指定每个x y轴的label的显示大小              
                          axisLabelColor:'green',//坐标轴的刻度值颜色
                   highlightCircleSize: 6,//高亮点显示的大小
                   axisLineWidth:1,//太小会看不到Y轴,默认为0.3,以为没有画出来
                   labels: [ 'Date', 'series1','series2'],//这里确定每列数据的含义
                         'series1': {//用两个y轴,这里是指定用哪一个y轴
                                          axis: {}
                                 },
                          axes: {
                                                  y: {
                                               valueRange: [500, 2600]//Y轴的值范围
                                                 },
                                          y2: {
                                             //set axis-related properties here 设置与Y1轴上每段值的相应的值(labelsKMB)
                                             axisLabelFormatter: function(y2){//对Y轴的刻度取整
                                             return y2.toFixed(0);},
                                             valueRange: [0, 100],
                                                       labelsKMB: true  //设置与Y1轴上每段值的相应的值(labelsKMB)
                                         },
                                              x: {       //显示时分秒,不用也行,如果显示MS,有个demo中,有d.getMilliSeconds();
                                              axisLabelFormatter: function(d, gran) {
                                                return Dygraph.zeropad(d.getHours()) + ":"
                                                    + Dygraph.zeropad(d.getMinutes()) + ":"
                                                    + Dygraph.zeropad(d.getSeconds());
                                             }
                                     }
                                 },
                                 ylabel: 'series2',//y1轴的标题
                              y2label: 'series1', //y2轴的标题 //rightGap:0,//这里把y轴的名称,顶没了。
                              yLabelWidth:30,        //Y轴标题的宽度,可以作用所有Y轴                           
                              yAxisLabelWidth: 60,  //这个是Y轴刻度的宽度。
                      interactionModel : {  //用户与图表的交互方式,第一个例子中的方式是默认方式,
                                   //而现在配置这种是跟百度地图等的操作方式相似的。
                                    'mousedown' : downV3,  //注意这些事件的大小写都不能写错。格式:'事件名称':事件发生时调用的函数
                                    'mousemove' : moveV3,  //这些函数在interaction.js中
                                    'mouseup' : upV3,
                                    'click' : clickV3,
                                    'mousewheel' : scrollV3,  //IE
                                    'DOMMouseScroll' : scrollV3,//这个是FireFox的鼠标滑轮事件名称,上面的是IE的,两个都要
                                    'dblclick' : dblClickV3
                             },
                           highlightCallback: function(e, x, pts, row){          //除了高亮回调,
                              //还有drawCallback clickCallback dblclickCallback用到时,可以去看
                              //,形式是一样的
                                      addAnnotations(e, x, pts, row);//加注释
                               ***MapPoint(pts[0]);//聚焦地图的相应点
                           }
                                          }//end of dygraphs options
                          );//end of dygraphs
                         
 
 
/**
 * 为图表中的线添加注释
 * @param e 鼠标移动事件
 * @param x 高亮点对应的x的值(这个不确定)
 * @param pts 高亮的点,有几条线,就有几个点
 * @param row 该点数据在CSV文件(如果第一行是:Date,series1,series2,则不包括这一行)的第几行,从0开始(也就是图表数据中第几行(最小行为0))
 */
function addAnnotations(e, x, pts, row) {
          annotations = [];
           annotations.push( {
              series: 'series2',//在哪条线上加注释
              x: x,
              width: 60,//注释的宽
              height: 20,//注释的高
              tickHeight: 5,//线与注释之间的距离,大的话,可以看到他们之间有条线连接
              text:Math.round(pts[1].yval)+checkSerialName(pts[1].name),//相当于一个DIV的title(源码如此),鼠标在上,显示这个
              shortText: Math.round(pts[1].yval)+checkSerialName(pts[1].name)//这个小文本直接显示在注释框内
 
               } );
           annotations.push( {
              series: 'series1',
              x: x,
              width: 60,
              height: 20,
              tickHeight: 5,//注释框和线之前的线长
              text:Math.round(pts[0].yval)+checkSerialName(pts[0].name),//注释的title
              shortText: Math.round(pts[0].yval)+checkSerialName(pts[0].name)
             
               } );
              g.setAnnotations(annotations); //设置注释
}
 
                  
             
    </script>
</body>
</html>
-------------------------------------------------------------