如何畫Flot橫條圖

橫條圖和直條圖一樣常被用來比較各組資料的相互關係, 差別在於橫條圖的長度越長, 所代表的值越大. 使用橫條圖的時機在於如果你有非常多組資料要放在一起比較, 這時用直條圖的話, 圖表的寬度就有可能超出螢幕寬度, 所以改用橫條圖後會不斷延伸的就是高度, 也方便使用者能夠一眼就看到整張圖表.

本章用貴金屬價格, 黃金、白金、白銀及鈀金的現價當作資料, 另外還會介紹如何控條圖的漸層色, 及控制圖表圖例的位置.


橫條圖範例(貴金屬價格)

橫條圖資料

一開始不免俗的一樣是放置定位點, 並且指定寬度和高度, 你可以直在用style設定, 或是指定一個CSS class給定位點.
   
        <style type="text/css">
        .mychart{
           width:300px;
           height:150px;
        }
        </style>
        <div id="flot-placeholder" class="mychart"></div>
        
這次資料我們只有7筆, 先建立一個叫rawData的陣列變數, 再把資料放進去. 還記得之前章節裡的資料格式嗎? 是像這樣的 [x, y],  我們以x軸放入時間格式資料(1325347200000, 1328025600000, ...), 或是按序號編碼(0, 1, 2, ....), 而y軸則放入資料的數值, 但這次我們做的是橫條圖, x軸和y軸資料位置必須對調如下面的rawData變數. 你可以看到陣列裡的第一組數字是1582.3, 這個是金價, 而第二組數字就是序號.
   
        var rawData = [
            [1582.3, 0], //Gold
            [28.95, 1],  //Silver
            [1603, 2],   //Platinum
            [774, 3],    //Palladium
            [1245, 4],  //Rhodium
            [85, 5],      //Ruthenium 
            [1025, 6]    //Iridium 
        ];

        var dataSet = [
            { label: "Precious Metal Price", data: rawData, color: "#AB5800" }
        ];
        
接著就是要建立刻度資料, 可能有人會認為因為我們做的是橫條圖, x軸和y軸資料對調了, 所以刻度資料也要跟著對調. 答案是錯的, 刻度資料並不需要跟著對調.
   
        var ticks = [
            [0, "Gold"], [1, "Silver"], [2, "Platinum"], [3, "Palldium"], [4, "Rhodium"], [5, "Ruthenium"], [6, "Iridium"]
        ];
        

橫條圖選項

當你繪製橫條圖時, bars.horizontal必須設定為true, 若沒有設定, 就會變成直條圖. 在此範例裡我們設定了bars.fillColor, 這屬性可以接受的值可以是單一顏色(如rgba(255, 255, 255, 0.8))或是漸層色, 我們用的是後者. Flot裡指定漸層色的方法可以是
   
        { colors: [ color1, color2, ... ] }
        
或是調整顏色的透明度如
   
        { colors: [ { opacity: 0.8 }, { opacity: 0.1 } ] }
        
另外我們還設定了bars.iineWidth, lineWidth是以像素為單位的線或輪廓的厚度, 在這範例裡我們設成1, bars的完整選項程式碼如下
   
        bars: {
            align: "center",
            barWidth: 0.5,
            horizontal: true,
            fillColor: { colors: [{ opacity: 0.5 }, { opacity: 1}] },
            lineWidth: 1
        }
        
我們所用的資料中, 價格最貴的是白金為$1,603美金, 所以圖表會以白金的條圖做為寬度, 但如果我們想要讓白金的條圖不要佔滿整張圖表的寬度的話, 就可以設定axis.max, 我們這在這設定2000, 如此一來白金的條圖部份就不會佔滿整個寬度, 你也可以設定axis.min, 作用與max相反. axis.tickColor是設定格線的顏色, 若不設定的話Flot會自動生成並且帶一些透明度為基色, axis.color則是設定刻度標籤的顏色.

在此我們為了美化刻度標籤的格式, 我們用了jQuery Number Formatter外掛, 讓x軸的值輸出成貨幣格式, 要改變刻度標籤可以複寫axis.tickFormatter, 此函式傳入了2個參數, tick value和axis object, 並且會傳回字串. 而Number Formatter可以到此下載.

而axis.axisLabel則是設定軸標籤, 此功能也是需要加入外掛程式jquery.flot.axislabels.js才能使用.
以下是軸選項的程式碼
   
        xaxis: {
            axisLabel: "Price (USD/oz)",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 10,
            max: 2000,
            tickColor: "#5E5E5E",                        
            tickFormatter: function (v, axis) {
                return $.formatNumber(v, { format: "#,###", locale: "us" });            
            },
            color:"black"
        }

        yaxis: {
            axisLabel: "Precious Metals",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 3,
            tickColor: "#5E5E5E",        
            ticks: ticks, 
            color:"black"
        }
        
Flot的圖例是自動產生的,不過你也可以控制圖例的細節,預設圖例會出現在右上角,不過有時候會擋到圖表,你可以設定legend.position讓圖例出現在4個角落的其中一個,可設定的值有"ne"、"nw"、"se"和"sw",分別代表右上角(north east)、左上角(north west)、右下角(south east)和左下角(south west). legend.noColumns代表圖例的table會被分成多少行,若設為0則表示只會分成單一一行. legend.labelBoxBorderColor則是設定圖例標籤盒邊框的顏色.
   
        legend: {
            noColumns: 0,
            labelBoxBorderColor: "#858585",
            position: "ne"
        }
        

呼叫$.plot完成繪圖

最後把上面建立的dataSet以及options帶入$.plot, 就完成了!
   
        $(document).ready(function () {
            $.plot($("#flot-placeholder"), dataSet, options);    
            $("#flot-placeholder").UseTooltip();
        });
        
在此範例裡有用了提示框, 這部份在往後會有專屬的一章講解, 在此就不詳細說明.

本範例完整程式碼

   
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="/js/lib/jquery-1.8.3.min.js" type='text/javascript'></script>  
    <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="/js/flot/excanvas.min.js"></script><![endif]-->
    
    <script type="text/javascript" src="/js/flot/jquery.flot.min.js"></script>        
    <script type="text/javascript" src="/js/flot/jquery.flot.axislabels.js"></script>
    <script type="text/javascript" src="/js/flot/jshashtable-2.1.js"></script>    
    <script type="text/javascript" src="/js/flot/jquery.numberformatter-1.2.3.min.js"></script> 
    <script type="text/javascript">
        //******* Precious Metal Price - HORIZONTAL BAR CHART
        var rawData = [[1582.3, 0], [28.95, 1],[1603, 2],[774, 3],[1245, 4], [85, 5],[1025, 6]];
        var dataSet = [{ label: "Precious Metal Price", data: rawData, color: "#E8E800" }];
        var ticks = [[0, "Gold"], [1, "Silver"], [2, "Platinum"], [3, "Palldium"], [4, "Rhodium"], [5, "Ruthenium"], [6, "Iridium"]];

        var options = {
            series: {
                bars: {
                    show: true
                }
            },
            bars: {
                align: "center",
                barWidth: 0.5,
                horizontal: true,
                fillColor: { colors: [{ opacity: 0.5 }, { opacity: 1}] },
                lineWidth: 1
            },
            xaxis: {
                axisLabel: "Price (USD/oz)",
                axisLabelUseCanvas: true,
                axisLabelFontSizePixels: 12,
                axisLabelFontFamily: 'Verdana, Arial',
                axisLabelPadding: 10,
                max: 2000,
                tickColor: "#5E5E5E",
                tickFormatter: function (v, axis) {
                    return $.formatNumber(v, { format: "#,###", locale: "us" });
                },
                color: "black"
            },
            yaxis: {
                axisLabel: "Precious Metals",
                axisLabelUseCanvas: true,
                axisLabelFontSizePixels: 12,
                axisLabelFontFamily: 'Verdana, Arial',
                axisLabelPadding: 3,
                tickColor: "#5E5E5E",
                ticks: ticks,
                color: "black"
            },
            legend: {
                noColumns: 0,
                labelBoxBorderColor: "#858585",
                position: "ne"
            },
            grid: {
                hoverable: true,
                borderWidth: 2,
                backgroundColor: { colors: ["#171717", "#4F4F4F"] }
            }
        };

        $(document).ready(function () {
            $.plot($("#flot-placeholder"), dataSet, options);
            $("#flot-placeholder").UseTooltip();
        });

        var previousPoint = null, previousLabel = null;

        $.fn.UseTooltip = function () {
            $(this).bind("plothover", function (event, pos, item) {
                if (item) {
                    if ((previousLabel != item.series.label) ||
                 (previousPoint != item.dataIndex)) {
                        previousPoint = item.dataIndex;
                        previousLabel = item.series.label;
                        $("#tooltip").remove();

                        var x = item.datapoint[0];
                        var y = item.datapoint[1];

                        var color = item.series.color;
                        //alert(color)
                        //console.log(item.series.xaxis.ticks[x].label);                

                        showTooltip(item.pageX,
                        item.pageY,
                        color,
                        "<strong>" + item.series.label + "</strong><br>" + item.series.yaxis.ticks[y].label +
                        " : <strong>" + $.formatNumber(x, { format: "#,###", locale: "us" }) + "</strong> USD/oz");
                    }
                } else {
                    $("#tooltip").remove();
                    previousPoint = null;
                }
            });
        };

        function showTooltip(x, y, color, contents) {
            $('<div id="tooltip">' + contents + '</div>').css({
                position: 'absolute',
                display: 'none',
                top: y - 10,
                left: x + 10,
                border: '2px solid ' + color,
                padding: '3px',
                'font-size': '9px',
                'border-radius': '5px',
                'background-color': '#fff',
                'font-family': 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
                opacity: 0.9
            }).appendTo("body").fadeIn(200);
        }
    </script>
</head>
<body>
    <div style="width:450px;height:300px;text-align:center;margin:10px">        
        <div id="flot-placeholder" style="width:100%;height:100%;"></div>        
    </div>
</body>
</html>
        

練習

本章的完整範例程式碼可以在這裡找到並做線上練習 Go to Example Tester