Morris.js和flot绘制折线图的比较

【文章摘要】javascript

最近用开源的AdminLTE作框架感受效果特别好,其针对图表库Morris.js和flot都提供了不错的支持,也都提供了这二者的例子。不过Morris.js是基于Raphael.js来的,也就是其使用SVG和VML来绘制图形,而flot则是使用Canvas进行绘制,在绘制效率和浏览器兼容性等方面会有出入,同时二者须要的数据格式也不相同。本文中对二者的使用和性能进行了比较。css

 

【文章索引】html

  1. Morris.js的使用
  2. flot的使用
  3. 性能比较

 

【1、Morris.js的使用】java

Morris.js最新版本是0.5.1,使用BSD协议,能够从官方网站 http://morrisjs.github.io/morris.js/ 或 GitHub https://github.com/morrisjs/morris.js 下载。Morris.js使用很是简单,其仅提供了折线图、面积图、柱形图和饼图四种类型的图表,不过也基本知足大部分需求。Morris.js基于Raphael,使用的是SVGVML绘制图表,直接支持IE 6+、FF 3+、Chrome 5+、Safari 3+和Opera 9.5+,不过在图表内容比较多时效率比较低,这个以后再分析。除此以外Morris.js还须要依赖jQuery。jquery

其数据格式要求以下:git

bathroomData = [
    { time: "2014-06-17T10:54:01", r2: 5 },
    { time: "2014-06-17T11:09:01", r0: 4, r1: 79, r2: 7, r3: 79 },
    { time: "2014-06-17T11:24:01", r0: 11, r1: 88, r2: 13, r3: 100 },
    { time: "2014-06-17T11:39:01", r0: 11, r1: 69, r2: 12, r3: 73 },
    ...
]

即按X轴对数据进行分类,X轴数据(如上的time)相同的全部系列(Series)的数据(如上的r0、r一、r二、r3)均放置于在同一个JS对象内,当该系列在该X轴数据上没有数据时留空(如上第一个数据没有r0、r一、r3)。以后须要指定X轴和Y轴的数据项,X轴只能指定一个数据项,而Y轴能够指定多个。除此以外,Morris.js自带日期型字符串的支持,直接使用便可。例如这里指定time为X轴的数据,r0、r一、r二、r3为Y轴数据,默认效果以下:github

其中完整代码以下:canvas

 1 <!DOCTYPE html>
 2 <html lang="zh-cn">
 3 <body>
 4     <div id="bathroom-chart"></div>
 5     
 6     <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
 7     <script type="text/javascript" src="raphael-2.1.2.min.js"></script>
 8     <script type="text/javascript" src="morris-0.5.1.min.js"></script>
 9     <script type="text/javascript">
10         var bathroomData = [
11             { time: "2014-06-17T10:54:01", r2: 5 },
12             { time: "2014-06-17T11:09:01", r0: 4, r1: 79, r2: 7, r3: 79 },
13             { time: "2014-06-17T11:24:01", r0: 11, r1: 88, r2: 13, r3: 100 },
14             { time: "2014-06-17T11:39:01", r0: 11, r1: 69, r2: 12, r3: 73 }
15         ];
16         var bathroomIDs = [ "r0", "r1", "r2", "r3" ];
17         var bathroomNames = [ "校本部学生浴室(男)", "校本部学生浴室(女)", "XX校区学生浴室(男)", "XX校区学生浴室(女)" ];
18         
19         Morris.Line({
20             element: "bathroom-chart",
21             data: bathroomData,
22             xkey: "time",
23             ykeys: bathroomIDs,
24             labels: bathroomNames
25         });
26     </script>
27 </body>
28 </html>
View Code

其中element为绘制到指定元素的元素ID,data为数据源,xKey为X轴的数据项名称,yKeys为Y轴的数据项名称数组,labels为每一个系列的名称数组,与yKeys的顺序对应。这样就能够实现基本的图表,并且其自带鼠标悬停的效果,即鼠标在图上悬停时,图表下方会有各个系列当前选中的值。数组

除此以外还能够对每一个系列的颜色进行设置(lineColors属性设置数组,与yKeys顺序对应)、线条粗细(lineWidth)、圆圈大小(pointSize)、Y轴最大值、最小值(ymax、ymin)、X轴数据间隔类型(xLabels)等等进行设置。此外还能够经过自定义函数来自定义X轴和Y轴的数据格式,或者自定义鼠标悬停时显示的内容。浏览器

稍加修改能够调整为更好看的效果,以下所示:

完整代码以下:

 1 <!DOCTYPE html>
 2 <html lang="zh-cn">
 3 <body>
 4     <div id="bathroom-chart"></div>
 5     
 6     <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
 7     <script type="text/javascript" src="raphael-2.1.2.min.js"></script>
 8     <script type="text/javascript" src="morris-0.5.1.min.js"></script>
 9     <script type="text/javascript">
10         var bathroomData = [
11             { time: "2014-06-17T10:54:01", r2: 5 },
12             { time: "2014-06-17T11:09:01", r0: 4, r1: 79, r2: 7, r3: 79 },
13             { time: "2014-06-17T11:24:01", r0: 11, r1: 88, r2: 13, r3: 100 },
14             { time: "2014-06-17T11:39:01", r0: 11, r1: 69, r2: 12, r3: 73 }
15         ];
16         var bathroomIDs = [ "r0", "r1", "r2", "r3" ];
17         var bathroomNames = [ "校本部学生浴室(男)", "校本部学生浴室(女)", "XX校区学生浴室(男)", "XX校区学生浴室(女)" ];
18         var bathroomMaxs = [ 100, 100, 113, 137 ];
19         var bathroomMax = 137;
20         var bathroomColors = [ "#5B9BD5", "#ED7D31", "#A5A5A5", "#FFC000" ];
21         
22         Morris.Line({
23             element: "bathroom-chart",
24             data: bathroomData,
25             xkey: "time",
26             ykeys: bathroomIDs,
27             labels: bathroomNames,
28             lineColors: bathroomColors,
29             lineWidth: 3,
30             pointSize: 4,
31             ymax: bathroomMax,
32             ymin: 0,
33             hoverCallback: function (index, options, content) {
34                 var row = options.data[index];
35                 var result = '<div class="morris-hover-row-label">' + row.time.replace("T", " ") + '</div>';
36 
37                 for (var i = 0; i < bathroomNames.length; i++) {
38                     result += '<div class="morris-hover-point" style="color: ' + bathroomColors[i] + '">' +
39                         bathroomNames[i] + " : " + (row["r" + i] == undefined ? "-" : row["r" + i]) + " / " + bathroomMaxs[i] + "</div>";
40                 }
41 
42                 return result;
43             },
44             xLabels: "5min",
45             yLabelFormat: function (y) { return parseInt(y).toString(); }
46         });
47     </script>
48 </body>
49 </html>
View Code

 

【2、flot的使用】

flot也是很是常见的图表库,最新版本是0.8.3,采用MIT协议,能够从官方网站 http://www.flotcharts.org/ 或 GitHub https://github.com/flot/flot 下载。flot使用也很简单,其支持在一个图表中同时叠加折线图、面积图、柱形图/条形图等不一样的形式,并且其支持扩展插件,经过扩展插件还能够支持堆积柱形图和饼图等以及支持缩放和选区等功能。flot使用Canvas绘制图表,在借助excanvas的状况下,能够支持IE 6+、FF 2+、Chrome、Safari 3+和Opera 9.5+。

仍是以上面的数据为例,flot的数据要求与Morris.js不一样,对于上述的数据,flot要求以下:

bathroomData = [
    { data: [ [1402974541000, 4], [1402975441000, 11], [1402976341000, 11], ... ] },
    { data: [ [1402974541000, 79], [1402975441000, 88], [1402976341000, 69], ... ] },
    { data: [ [1402973641000, 5], [1402974541000, 7], [1402975441000, 13], [1402976341000, 12], ... ] },
    { data: [ [1402974541000, 79], [1402975441000, 100], [1402976341000, 73], ... ] }
]

能够看到,与Morris.js不一样主要有两点,第一点是flot不支持日期型字符串的使用,须要转换为JavaScript的Date对象,而后使用getTime获取时间(距1970年1月1日 UTC时区的毫秒数)才可。第二点是Morris以X轴对数据进行分类,而flot则以系列(Series)对数据进行分类,每个系列为一个JS对象,包括一个名为data的数组,其中该数组包含该系列的全部数据,每个数组又使用一个二维数组表示,其中第一维表示X轴的数据,第二维为Y轴的数据。默认效果以下:

完整代码以下:

 1 <!DOCTYPE html>
 2 <html lang="zh-cn">
 3 <head>
 4     <style>
 5         .chart-container {
 6             height: 330px;
 7         }
 8         .bathroom-chart {
 9             width: 100%;
10             height: 100%;
11         }
12     </style>
13 </head>
14 <body>
15     <div class="chart-container">
16         <div id="bathroom-chart" class="bathroom-chart"></div>
17     </div>
18     
19     <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
20     <script type="text/javascript" src="jquery.flot-0.8.3.min.js"></script>
21     <script type="text/javascript" src="jquery.flot-0.8.3.time.min.js"></script>
22     <script type="text/javascript">
23         var bathroomData = [
24             { data: [ [1402974541000, 4], [1402975441000, 11], [1402976341000, 11] ], label: "校本部学生浴室(男)" },
25             { data: [ [1402974541000, 79], [1402975441000, 88], [1402976341000, 69] ], label: "校本部学生浴室(女)" },
26             { data: [ [1402973641000, 5], [1402974541000, 7], [1402975441000, 13], [1402976341000, 12] ], label: "XX校区学生浴室(男)" },
27             { data: [ [1402974541000, 79], [1402975441000, 100], [1402976341000, 73] ], label: "XX校区学生浴室(女)" }
28         ];
29         
30         $.plot("#bathroom-chart", bathroomData, {
31             xaxis: { mode: "time", timezone: "browser" }
32         });
33     </script>
34 </body>
35 </html>
View Code

其中数据里每一个系列还支持设置label参数,即设置这个系列的名称。与Morris.js不一样的是,对于日期类型须要手动设置轴的类型,例如这里须要设置X轴的类型为time(设置为time类型时须要添加jquery.flot.time.js这个插件),除了设置类型为时间外,还须要设置时区,若是服务器、客户端的时区均为同一个,那么能够将时区设置为“browser”(与浏览器相同)。

除此以外,flot默认显示图表的边框,能够经过grid参数里的borderWidth为0取消;flot默认的图表margin也太小,能够设置grid的marigin和labelMargin;还能够在series参数里对lines(折线)、points(点)以及bars(柱形)进行设置,每一项都可同时显示或隐藏,具体设置方法能够参考文档,再也不赘述。此外,Morris.js的图例默认都在图表内,能够设置legend的container来将图例设置在其余的地方。另外,因为flot没有默认的鼠标悬停效果,因此须要本身手动去定义,flot提供了一个叫“plothover”和“plotclick”的事件,能够绑定这两个事件实现悬停和点击的效果,其中事件处理函数包括三个参数,分别是event、pos以及item,能够经过item.seriesIndex获取系列的索引,或者直接经过item.series.label直接获取系列的名称,或者经过item.datapoint[0]或[1]获取当前X轴或Y轴的数据等等。最终实现效果以下:

完整代码以下:

 1 <!DOCTYPE html>
 2 <html lang="zh-cn">
 3 <head>
 4     <style>
 5         .chart-container {
 6             height: 330px;
 7         }
 8         .chart-tooltip {
 9             position: absolute;
10             display: none;
11             padding: 5px;
12             max-width: 200px;
13             font-size: 12px;
14             text-align: center;
15             color: #fff;
16             background-color: #000;
17             border-radius: 4px;
18             opacity: 0.8;
19         }
20         .bathroom-chart {
21             width: 100%;
22             height: 100%;
23         }
24     </style>
25 </head>
26 <body>
27     <div class="chart-container">
28         <div id="bathroom-chart" class="bathroom-chart"></div>
29     </div>
30     <div id="bathroom-chart-tooltip" class="chart-tooltip"></div>
31     <div id="bathroom-legend"></div>
32     
33     <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
34     <script type="text/javascript" src="jquery.flot-0.8.3.min.js"></script>
35     <script type="text/javascript" src="jquery.flot-0.8.3.time.min.js"></script>
36     <script type="text/javascript">
37         var bathroomData = [
38             { data: [ [1402974541000, 4], [1402975441000, 11], [1402976341000, 11] ], label: "校本部学生浴室(男)" },
39             { data: [ [1402974541000, 79], [1402975441000, 88], [1402976341000, 69] ], label: "校本部学生浴室(女)" },
40             { data: [ [1402973641000, 5], [1402974541000, 7], [1402975441000, 13], [1402976341000, 12] ], label: "XX校区学生浴室(男)" },
41             { data: [ [1402974541000, 79], [1402975441000, 100], [1402976341000, 73] ], label: "XX校区学生浴室(女)" }
42         ];
43         var bathroomMaxs = [ 100, 100, 113, 137 ];
44         var bathroomMax = 137;
45         var bathroomColors = [ "#5B9BD5", "#ED7D31", "#A5A5A5", "#FFC000" ];
46         
47         $.plot("#bathroom-chart", bathroomData, {
48             xaxis: { mode: "time", timezone: "browser", timeformat: "%H:%S", tickLength: 0 },
49             yaxis: { min: 0, max: bathroomMax, color: "#EAEAEA" },
50             legend: { container: "#bathroom-legend" },
51             colors: bathroomColors,
52             series: { 
53                 lines: { show: true, lineWidth: 3, fillColor: bathroomColors }, 
54                 points: { show: true } },
55             grid: { hoverable: true, borderWidth: 0, margin: 10, labelMargin: 10 }
56         });
57             
58         $("#bathroom-chart").bind("plothover", function(event, pos, item) {
59             if (item) {
60                 $("#bathroom-chart-tooltip").html(item.series.label + " : " + item.datapoint[1] + " / " + bathroomMaxs[item.seriesIndex])
61                     .css({ top: item.pageY + 8, left: item.pageX + 8 })
62                     .fadeIn(200);
63             } else {
64                 $("#bathroom-chart-tooltip").hide();
65             }
66         });
67     </script>
68 </body>
69 </html>
View Code

 

【3、性能比较】

性能测试固然不是用上述的这么稀少的数据了,实际的数据是从上午11点到晚上11点这12个小时每5分钟一次的数据,显示出现大约以下图,其实也没多少。

性能测试采用在网页开始时记录当前时间,全部代码均执行完后求当前时间与开始时间的差,其中测试代码均使用上述提到的完整代码(即一种默认样式、一种自定义样式),测试平台选用我手头的几个设备Lenovo Thinkpad T420(i5-2520 2.5Ghz/8GB/Win8.1 x64)、一台服务器虚拟机(E5-4650 2.7Ghz/4GB/Server 2003 x64)、Dell Venue 8 Pro(Atom 3740D 1.33Ghz/2GB/Win8.1 x86)、小米1青春版(Qualcomm MSM8260 1.2Ghz/768MB/MIUI on Android 4.1.2)、小米2S(Snapdragon 600 1.7Ghz/2GB/MIUI on Android 4.1.1),分辨率都是设备默认的全屏分辨率,其中服务器上使用IE8,使用excanvas实现Canvas效果。测试结果以下:

看来SVG相对Canvas还真不是通常的慢呢。

附,原始测试结果:

Morris 0.5.1 基本样式
设备类型 浏览器 第一次 第二次 第三次 第四次 第五次 平均
Thinkpad T420 IE11 桌面版 656 621 744 608 607 647.2
Thinkpad T420 搜狗浏览器(Webkit 537.36) 361 339 334 320 332 337.2
服务器虚拟机 IE8 2343 2421 2375 2391 2390 2384
Dell Venue 8 Pro IE11 Metro版 1966 2151 2057 1978 2117 2053.8
小米1青春版 UC 9.7国际版(Webkit 533.1) 4407 4335 4233 4309 4442 4345.2
小米2S UC 9.8(Webkit 533.1) 2892 2536 2481 2509 2558 2595.2

 

Morris 0.5.1 自定义样式
设备类型 浏览器 第一次 第二次 第三次 第四次 第五次 平均
Thinkpad T420 IE11 桌面版 1196 1139 1206 1113 1189 1168.6
Thinkpad T420 搜狗浏览器(Webkit 537.36) 602 585 631 632 620 614
服务器虚拟机 IE8 4468 4735 4797 4750 4703 4690.6
Dell Venue 8 Pro IE11 Metro版 3897 4039 4207 4165 4380 4137.6
小米1青春版 UC 9.7国际版(Webkit 533.1) 8246 8472 8765 9003 8517 8600.6
小米2S UC 9.8(Webkit 533.1) 5219 4920 5674 4727 5152 5138.4

 

Flot 0.8.1 基本样式
设备类型 浏览器 第一次 第二次 第三次 第四次 第五次 平均
Thinkpad T420 IE11 桌面版 67 52 48 52 50 53.8
Thinkpad T420 搜狗浏览器(Webkit 537.36) 63 34 32 38 42 41.8
服务器虚拟机 IE8 94 110 94 109 109 103.2
Dell Venue 8 Pro IE11 Metro版 131 147 146 168 159 150.2
小米1青春版 UC 9.7国际版(Webkit 533.1) 351 471 379 393 409 400.6
小米2S UC 9.8(Webkit 533.1) 349 260 201 221 195 245.2

 

Flot 0.8.1 自定义样式
设备类型 浏览器 第一次 第二次 第三次 第四次 第五次 平均
Thinkpad T420 IE11 桌面版 87 89 87 78 83 84.8
Thinkpad T420 搜狗浏览器(Webkit 537.36) 40 38 40 44 44 41.2
服务器虚拟机 IE8 1234 1219 1282 1234 1235 1240.8
Dell Venue 8 Pro IE11 Metro版 256 290 269 352 312 295.8
小米1青春版 UC 9.7国际版(Webkit 533.1) 719 600 775 749 622 693
小米2S UC 9.8(Webkit 533.1) 357 273 281 335 340 317.2

 

【相关连接】

  1. morris.js:http://morrisjs.github.io/morris.js/
  2. Flot:http://www.flotcharts.org/
  3. Flot API:https://github.com/flot/flot/blob/master/API.md
相关文章
相关标签/搜索