如何画Flot分区图

分区图就是将折线图的空白部份用颜色填满的图表, 分区图和折线图一样, 是用来看某一段时间数据的趋势走向, 不过分区图比较容易看出数据间的比例大小. 本章用历年世界人口估计做为范例数据, 统计从1800 ~ 2010年间世界六大洲的人口成长变化.


分区图范例(历年世界人口估计)

分区图资料

我们先建立一个<div>, 并且指定一个id, 且设定长度及宽度, 这将会成为Flot绘图的定位点.
   
        <div id="flot-placeholder" style="width:400px;height:300px"></div>
        
接下来建立一个叫rawData1的数组变量,并插入格式如[x,y]的数组数据,因为我们要画的是时间数据格式, 而Flot要做时间数据格式的图表就必须把时间转成javascript timestamps,所以x轴的数据我们用了一只自定义函式year()来代替, year(1800)表示这是公元1800年的资料. 而y轴就放当年度的人口数,之后依序插入各年度的人口数资料. 这里我们只放Oceania的数据, 其它五大洲的数据建立的方式都是一样的, 以下是程序代码.
   
        //Oceania
        var rawData1 = [
            [year(1800), 200], [year(1850), 200], [year(1900), 600], [year(1950), 1281], [year(1955), 1426],
            [year(1960), 1589], [year(1965), 1766], [year(1970), 1944], [year(1975), 2156], [year(1980), 2283],
            [year(1985), 2467], [year(1990), 2668], [year(1995), 2892], [year(2000), 3104], [year(2005), 3299],
            [year(2010), 3510]
        ];
        //North America
        var rawData2 = [
            //skip
        ];

        //rawData3 rawData4...

        function year(year) {    
            return new Date(year, 1, 1).getTime();
        }
        
六大洲的原始数据建立好之后,接着建立一个叫dataSet的数组变量,这个变量在后面会当成数据源使用.我们在数组里插入对象,label属性表示该笔数据的卷标名称,data属性就设定我们上面所建立的rawData,为了让分区图更有辨识性,我们还设定了color属性,每笔数据的颜色都设定成不一样的, 这样Flot在绘图时会依照你所设定的颜色去绘制每一笔数据.
   
        var dataSet = [
            { label: "Asia", data: rawData6, color: "#0077FF" },
            { label: "Africa", data: rawData5, color: "#7D0096" },
            { label: "Europe", data: rawData4, color: "#DE000F" },
            { label: "Latin America", data: rawData3, color: "#00B503" },
            { label: "North America", data: rawData2, color: "#ED7B00" },
            { label: "Oceania", data: rawData1, color: "#E8E800" }
        ];
        

分区图选项

分区图和折线图其实只差在series.lines.fill的设定, 若设定为true, 就会以分区图绘制, 如果没有设定或是设成false,就会以折线图绘制. 而series.lines.show则是设定线条要不要显示.
   
        series: {            
            lines: {
                show: true,
                fill: true
            }
        }
        
由于我们做的是时间格式数据, 以xaxis.mode必须设定为"time", 并且需要加入jquery.flot.time.js插件,如此一来Flot就会把x轴的刻度以日期型态编译.另外我们还设定了xaxis.timeformat,设定此属性时可用Flot提供的参数代入如"%Y/%m/%d", 这样会输出日期格式为"2013/03/05", 在这范例里我们设定成"%Y",因为我们只要显示年份. 可以参考更多的timeformat参数

另外为了控制x轴刻度标签, 设定了xaxis.tickSize, tickSize为刻度之间的间隔大小,格式为[value, unit],我们设定为[20, "year"],表示年份会依每20年的间隔出现, 而unit也可以设定为"day"、"hour"等, 不过要特别注意, 如果你设定的unit太小如"hour"而你的数据源且是以年计算的话,可能会因为Flot在绘图时做得计算过久而造成浏览器无响应.

因为Flot没有内建轴卷标的功能,所以需要加入jquery.flot.axislabels.js插件来达成,加入后就可以设定,axis.axisLabel为要显示的名称axis.axisLabelPadding则设定标签填充的空间大小,另外还可以设定字型及文字大小等.

为了让刻度标签更美观, 可以用axis.tickFormatter自定义函式,这函式传入了2个参数, tick value和axis object, 并且会传回字符串.要让y轴的数字显示货币格式,我们用了number formatter,如此一来y轴刻度标签就能够更易读.
   
        xaxis: {
            axisLabel: "Year",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 10,            
            mode: "time",
            tickSize: [20, "year"],
            timeformat: "%Y"
        }

        yaxis: {
            axisLabel: "Population (multiply by 10,000)",
            axisLabelUseCanvas: true,
            axisLabelFontSizePixels: 12,
            axisLabelFontFamily: 'Verdana, Arial',
            axisLabelPadding: 3,
            tickFormatter: function (v, axis) {
                return $.formatNumber(v, { format: "#,###", locale: "us" });
            }
        }
        
因为图例默认位置会出现在图表的右上角,但这样会遮住我们要看的图表,所以设定legend.position为"nw", "nw"为north west,也就是左上角的意思.我们还设定了legend.noColumns, noColumns表示图例需要分成多少列, 在这里我们设定为3列.
   
        legend: {
            noColumns: 3,
            labelBoxBorderColor: "#858585",
            position: "nw"
        }
        
默认的图表背景颜色是白色,为了让图表不那么单调,可以设定grid.backgroundColor,可以设定成单一颜色如backgroundColor:"#A12858",也可以设定成渐层色,程序代码如下.

另外因为我们会用到提示框功能,所以grid.hoverable要设定true,当hoverable为true时,Flot会监听鼠标事件并触发"plothover"事件.
   
        grid: {
            hoverable: true,
            borderWidth: 2,
            backgroundColor: { colors: ["#ffffff", "#EDF5FF"] }
        }
        

提示框(tooltip)

由于Flot并没有内建提示框功能,所以必须自行建置,以下是提示框功能完整程序代码,详细的说明在往后的章节会提到.
   
        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;                        
                
                        showTooltip(item.pageX,
                                item.pageY,
                                color,
                                "<strong>" + item.series.label + "</strong><br>" + new Date(x).getFullYear() +
                                " : <strong>Population : " + $.formatNumber(y, { format: "#,###", locale: "us" }) + "</strong>  (multiply by 10,000)");                
                    }
                } 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);
        }
        

完成绘图

最后把上面建立的dataSet以及options带入$.plot, 并把$.plot函式放到document.ready里,防止dom还未完全加载Flot就开始绘图所造成的错误.最后再用UseTooltip()建立提示框的功能.
   
        $(document).ready(function () {
            $.plot($("#flot-placeholder"), dataSet, options);    
            $("#flot-placeholder").UseTooltip();
        });
        


timeformat参数
   
        %a: weekday name (customizable)
        %b: month name (customizable)
        %d: day of month, zero-padded (01-31)
        %e: day of month, space-padded ( 1-31)
        %H: hours, 24-hour time, zero-padded (00-23)
        %I: hours, 12-hour time, zero-padded (01-12)
        %m: month, zero-padded (01-12)
        %M: minutes, zero-padded (00-59)
        %q: quarter (1-4)
        %S: seconds, zero-padded (00-59)
        %y: year (two digits)
        %Y: year (four digits)
        %p: am/pm
        %P: AM/PM (uppercase version of %p)
        %w: weekday as number (0-6, 0 being Sunday)
        

练习

本章的完整范例程序代码可以在这里找到并做在线练习 Go to Example Tester