【文章摘要】javascript
最近用開源的AdminLTE作框架感受效果特別好,其針對圖表庫Morris.js和flot都提供了不錯的支持,也都提供了這二者的例子。不過Morris.js是基於Raphael.js來的,也就是其使用SVG和VML來繪製圖形,而flot則是使用Canvas進行繪製,在繪製效率和瀏覽器兼容性等方面會有出入,同時二者須要的數據格式也不相同。本文中對二者的使用和性能進行了比較。css
【文章索引】html
Morris.js最新版本是0.5.1,使用BSD協議,能夠從官方網站 http://morrisjs.github.io/morris.js/ 或 GitHub https://github.com/morrisjs/morris.js 下載。Morris.js使用很是簡單,其僅提供了折線圖、面積圖、柱形圖和餅圖四種類型的圖表,不過也基本知足大部分需求。Morris.js基於Raphael,使用的是SVG或VML繪製圖表,直接支持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>
其中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>
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>
其中數據裏每一個系列還支持設置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>
性能測試固然不是用上述的這麼稀少的數據了,實際的數據是從上午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 |
【相關連接】