Morris.js和flot繪制折線圖的比較


【文章摘要】

最近用開源的AdminLTE做框架感覺效果特別好,其針對圖表庫Morris.js和flot都提供了不錯的支持,也都提供了這兩者的例子。不過Morris.js是基於Raphael.js來的,也就是其使用SVG和VML來繪制圖形,而flot則是使用Canvas進行繪制,在繪制效率和瀏覽器兼容性等方面會有出入,同時兩者需要的數據格式也不相同。本文中對兩者的使用和性能進行了比較。

 

【文章索引】

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

 

【一、Morris.js的使用】

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。

其數據格式要求如下:

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、r1、r2、r3)均放置於在同一個JS對象內,當該系列在該X軸數據上沒有數據時留空(如上第一個數據沒有r0、r1、r3)。之后需要指定X軸和Y軸的數據項,X軸只能指定一個數據項,而Y軸可以指定多個。除此之外,Morris.js自帶日期型字符串的支持,直接使用即可。例如這里指定time為X軸的數據,r0、r1、r2、r3為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         
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

 

【二、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

 

【三、性能比較】

性能測試當然不是用上述的這么稀少的數據了,實際的數據是從上午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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM