在最近的BS新项目中需要用到绘图数据显示的功能。在进行充足的选择之后决定才去开源的Flot。Flot是一个jQuery绘图库。主要用于简单的绘制图表功能。具有吸引人的渲染外观和互操作的特性。其在Internet Explorer 6+, Chrome, Firefox 2+, Safari 3+ and Opera 9.5+浏览器下工作正常。目前的版本是Version0.8.3. 以下是相关链接。在官网的example中展示出了flot可以绘制的样例,并且我想这些样例的源代码也许是大家如何学习flot的最快的方法吧。嘿嘿。这里有一点要注意的地方: 在文档中都用plot来代替Flot,作者给出了回答瞬间无语。
First: it's pronounced with a short o, like "plot". Not like "flawed".
So "Flot" rhymes with "plot".
And if you look up "flot" in a Danish-to-English dictionary, some of the words that come up are "good-looking", "attractive", "stylish", "smart", "impressive", "extravagant". One of the main goals with Flot is pretty looks.
和其他jquery库一样,我们只需要在html文档的末尾的jquery库的后面引入即可。这里要注意的是我们的浏览器必须支持HTML5 canvas标签。为了兼容IE9。我们可以使用canvas模拟库Excanvas来实现。我们在官网的demo中也可以发现如下的引入方式。
1 <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]-->
在这里要说明IE6是不被支持的。Excanvas实现仿真绘图的原理是依赖VML矢量标记语言。另外我们也可以尝试着使用Flashcanvas库来通过Flash实现仿真。尽管Flash对比VML加载起来会显得慢一点,但是当在绘制很多点的图时,Flash版本在整体的加载上会更加的快。在jquery库的要求上至少是需要jquery1.2.6。
创建一个占位div来放置绘出来的图:
1 <div id="placeholder"></div>
在这里我们只需要简单的设置div的id,plot将会修改很多属性来呈现绘制的图像。我们无需自己设置该div的样式,比如在IE7下如果设置该div的背景图就会引发问题。
然后我们需要设置placeholder的高度和宽度,因为plot库不知道如何绘制图的大小。这里我们采取直接在html中定义css:
1 <div id="placeholder" style="width:600px;height:300px"></div>
同时你也可以在外部的stylesheet中定义大小,确保该div placeholder没有被display:none来标记,这样可能会导致混乱的结果。
然后在js中运行如下方法:
1 var plot = $.plot(placeholder, data, options)
我们来看看这三个参数和plot对象
这里是一个简单的例子:
1 $.plot($("#placeholder"), [ [[0, 0], [1, 1]] ], { yaxis: { max: 1 } });
[series1, series2, ...]
这一系列的数据即可是原始的二维坐标点数组(内部x和y值必须为数字--我们在从数据库检索出数据序列化为JSON提交至前台时要注意数据格式,如果发生一些神秘错误请确保你的输入数据为数字类型而不是字符串类型),也可以是一个对象的属性。
当输入进去的坐标值为空或者不能转换成为数字,那么该数据点就不予以绘制出。存在一个特殊的例子即如果绘制一条线时遇到坐标为空的点则该点将成为这条绘制线的截至点。后面的点将不能和前面的点相连。我们可以指定第三个坐标值来设置绘制线或者栅栏下方填充的面积值(默认是0);
1 var d1 = []; 2 for (var i = 0; i < 14; i += 0.5) { 3 d1.push([i, Math.sin(i)]); 4 } 5 6 var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]]; 7 8 // A null signifies separate line segments 9 10 var d3 = [[0, 12], [7, 12], null, [7, 2.5], [12, 2.5]]; 11 12 $.plot("#placeholder", [ d1, d2, d3 ]);
得到的效果是这样的
红线处存在断截。
对于数据为对象类型时应当满足如下格式内容:
1 { 2 color: color or number 3 data: rawdata 4 label: string 5 lines: specific lines options 6 bars: specific bars options 7 points: specific points options 8 xaxis: number 9 yaxis: number 10 clickable: boolean 11 hoverable: boolean 12 shadowSize: number 13 highlightColor: color or number 14 }
下面我来一一介绍以上的属性:
color: 绘制出来的图中线条或者柱状的颜色,如果不指定将自动生成格式为CSS color规则的颜色值。
data: 为绘制的坐标点的值。
label: 用来指示图中该段数据对应的名字,如“Line1”。
lines: 设置如果绘图为折线图时的相关属性,如show, fill, fillColor等
bars: 设置如何绘图为柱状图时的相关属性, 如show, fill, fillColor等
points: 设置绘图中的每个点的相关属性,如形状(默认为circle)还有半径大小
xaxis, yaxis: 这两属性的意思是对应的该条折线或者柱子所采用的坐标轴,默认为一,如果不设定则所有的数据都采用相同一个坐标轴,如果设置其他值(2~n)则采用图像上显示的第n个坐标轴显示。如下图所示:
(d2采用的坐标轴为外围的坐标轴)
clickable, hoverable: 用来设置互操作的属性,取值为bool类型。类似事件机制。false则静止该点的互操作功能。
shadowSize: 该段线条的阴影大小。为阿拉伯数字
highlightColor: 选择高亮的颜色。
每个字段都存在一个默认值。如果我们对其需要的属性进行再赋值则覆盖掉默认值如:
1 [ { label: "Foo", data: [ [10, 1], [17, -14], [30, 5] ] }, { label: "Bar", data: [ [11, 13], [19, 11], [30, -7] ] } ]
如下是数据为对象时的例子:(options设置为空)
1 ar d1 = []; 2 for (var i = 0; i < 14; i += 0.5) { 3 d1.push([i, Math.sin(i)]); 4 } 5 6 var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]]; 7 8 var d3 = []; 9 for (var i = 0; i < 14; i += 0.5) { 10 d3.push([i, Math.cos(i)]); 11 } 12 13 var d4 = []; 14 for (var i = 0; i < 14; i += 0.1) { 15 d4.push([i, Math.sqrt(i * 10)]); 16 } 17 18 var d5 = []; 19 for (var i = 0; i < 14; i += 0.5) { 20 d5.push([i, Math.sqrt(i)]); 21 } 22 23 var d6 = []; 24 for (var i = 0; i < 14; i += 0.5 + Math.random()) { 25 d6.push([i, Math.sqrt(2*i + Math.sin(i) + 5)]); 26 } 27 28 $.plot("#placeholder", [{ 29 data: d1, 30 lines: { show: true, fill: true } 31 }, { 32 data: d2, 33 bars: { show: true } 34 }, { 35 data: d3, 36 points: { show: true } 37 }, { 38 data: d4, 39 lines: { show: true } 40 }, { 41 data: d5, 42 lines: { show: true }, 43 points: { show: true } 44 }, { 45 data: d6, 46 lines: { show: true, steps: true } 47 }]);
注意:我们即可以在每个data集合中单独的设置以上的属性来实现每个折线或者条形柱的不同之处,同时也可以在option的统一设置中来集体设置以上相关属性。
所有的选项都是完全可选择的,我们可以单独的在文档中定义option对象,然后在$.plot方法中传入option值:
1 var options = { 2 series: { 3 lines: { show: true }, 4 points: { show: true } 5 } 6 }; 7 8 $.plot(placeholder, data, options);
在options内部有很多属性。以下我们一一来说明:
legend属性是来定义折线图的label标签信息属性
1 legend: { 2 show: boolean 3 labelFormatter: null or (fn: string, series object -> string) 4 labelBoxBorderColor: color 5 noColumns: number 6 position: "ne" or "nw" or "se" or "sw" 7 margin: number of pixels or [x margin, y margin] 8 backgroundColor: null or color 9 backgroundOpacity: number between 0 and 1 10 container: null or jQuery object/DOM element/jQuery expression 11 sorted: null/false, true, "ascending", "descending", "reverse", or a comparator 12 }
show:设置是否显示该label,
labelFormatter: 设置点击该label对应的事件。举例如下:
labelFormatter: function(label, series){ //alert(label); return '<a href="#' + label + '">' + label + '</a>'; }
labelBoxBorderColor: 设置label的边框颜色。
noColumns: 设定图中的label组排成多少列,默认为1.则表明每行只排列一个label.设置为n则每行排列n个label. 如下是noColumns:2的情况。
Position: 有4个选项"ne", "nw", "se", "sw"分别表示将label组显示在 ↗, ↖, ↘, ↙。
margin: 设置其与绘图div边缘的距离,可以像素值表示,也可用[x margin, y margin]表示。 如[50,50]
backgroundColor与backgroundOpacity:设置label块的背景颜色颜色值。默认是透明色。
container:
sorted: 允许设置为null/false/true/"ascending"/"descending"/"reverse"/function(). 默认label的排序是通过默认的series数组内部的序列号来排序的。如上d2的data在d1的data前push进数组,所以d2显示在前面。"reverse":颠倒默认的排序。 "descending": 按照label名字降序排列。true&"ascending":按照label的名字的升序排列。 false&null: 按照默认排列。同时我们还能自定义排序内部比较方法通过传递两个data对象来对比其label或者color.如下是一个例子:看过排序算法的应该理解不多说了。
1 sorted: function(a, b) { 2 // sort alphabetically in ascending order 3 return a.label == b.label ? 0 : ( 4 a.label > b.label ? 1 : -1 5 ) 6 }
1 xaxis, yaxis: { 2 show: null or true/false 3 position: "bottom" or "top" or "left" or "right" 4 mode: null or "time" ("time" requires jquery.flot.time.js plugin) 5 timezone: null, "browser" or timezone (only makes sense for mode: "time") 6 7 color: null or color spec 8 tickColor: null or color spec 9 font: null or font spec object 10 11 min: null or number 12 max: null or number 13 autoscaleMargin: null or number 14 15 transform: null or fn: number -> number 16 inverseTransform: null or fn: number -> number 17 18 ticks: null or number or ticks array or (fn: axis -> ticks array) 19 tickSize: number or array 20 minTickSize: number or array 21 tickFormatter: (fn: number, object -> string) or string 22 tickDecimals: null or number 23 24 labelWidth: null or number 25 labelHeight: null or number 26 reserveSpace: null or true 27 28 tickLength: null or number 29 30 alignTicksWithAxis: null or number 31 }
以上的属性是用来设置坐标轴相关。x轴和Y轴通用。我来一一解释:
show: 取值为bool 是否显示坐标轴。默认值为true.
position: 设置坐标轴所处图的位置。x轴取值"top" / "bottom", y轴取值"left" / "right"。
mode: 设置对应的数值应该如何解析。默认值或者null值则认为对应的数值用小数来解析, 设置"time" 来解析时间戳类型的数值(需要引入jquery.flot.time.js插件来支持时间戳转换)
timezone: 设置时区。取值有null、"browser",或者具体的时区设置。
color: 设置坐标线的颜色
tickColor:设置坐标线的颜色。貌似和上者一样。官网说可以得到更加有细密纹路的控制。
font:设置坐标轴上的值的字体样式,如下所示:
1 { 2 size: 11, 3 lineHeight: 13, 4 style: "italic", 5 weight: "bold", 6 family: "sans-serif", 7 variant: "small-caps", 8 color: "#545454" 9 }
在这里size和lineHeight属性必须用像素值定义。
min && max: 设定坐标轴的最大值和最小值。如果未设定则选择绘图数据源中的最大值和最小值。
autoscaleMargin:此属性用在未指定坐标轴最大值和最小值的时候来指定该坐标轴最大的延伸值(感觉就是在压缩或者放大图)。x轴的默认值为null,y轴的默认值为0.02这样能够适应大部分用例的正常大小。
transform & inverseTransForm: 设置更改你绘图出来的数值。例如原始值需要做一些压缩或者扩张(eg.需要对小数值转换为百分数的时候)。接受的值为function.其大致运行过程是当Flot开始绘图时,每一个data源首先通过该转换函数。如下例子:x 坐标轴的值转换成为自然对数:
1 xaxis: { 2 transform: function (v) { return Math.log(v); }, 3 inverseTransform: function (v) { return Math.exp(v); } 4 }
inverseTransform是transform方法的反方法。 v == inverseTransform(transform(v))。这个方法在转换canvas坐标为数据原始坐标是需要用到的。前提是你如果想使用互操作功能的话。假如你点击一个点想得到该点的原始数据。你就需要该转换方法来还原canvas坐标为原始坐标。
ticks: 在英语中为十字叉的意思。在这里我们可以理解为网格线的起点坐标。前面我们可以设置ticks的颜色。这里是设置ticks的具体属性。为何我们不设置时绘制出来的图能够恰如其分的生成适当数量的坐标线来美化图呢。这是因为tick 生成器算法来完成的,这个算法有两个步骤,首先算法根据数据的max和min来估算需要多少条ticks然后根据这个数量计算出一个能够很好的均分ticks的间隔大小。然后再生成ticks. 如下两张图前者是没有设置tick时系统自动生成(0.0~15.0)均等分割的7条tick。而后者是通过设置ticks: [[0, "zero"], [5, "one mark"], [10, "two marks"]]来显示3条ticks.
这里需要注意的是ticks可接受的值如下:
ticks: [[0, "zero"], [5, "one mark"], [10, "two marks"]]
1 function piTickGenerator(axis) { 2 var res = [], i = Math.floor(axis.min / Math.PI); 3 do { 4 var v = i * Math.PI; 5 res.push([v, i + "\u03c0"]); 6 ++i; 7 } while (v < axis.max); 8 return res; 9 }
tickSize: 如果你希望跳过算法自动计算的间隔来手动设置tick的间隔大小。你可以设置该属性。如上图的算法设置的间隔为2.5,我在此处设置tickSize: 5, 则得到如下图
minTickSize: 如果你想设置一个不确定的tick的大小的话,可以设置这个属性。
tickFormatter: 设置tick的格式。可接受function或者string。function(val, axis)接受两个参数为tick值和axis坐标对象(该对象中保存着从数据源收集来的最大值和最小值等),返回string类型。默认的格式化器为:
function formatter(val, axis) { return val.toFixed(axis.tickDecimals); }
这里有一个定制化的格式化器:
1 function suffixFormatter(val, axis) { 2 if (val > 1000000) 3 return (val / 1000000).toFixed(axis.tickDecimals) + " MB"; 4 else if (val > 1000) 5 return (val / 1000).toFixed(axis.tickDecimals) + " kB"; 6 else 7 return val.toFixed(axis.tickDecimals) + " B"; 8 }
tickDecimals: 设置tick的数值的小数点位数。为number。
labelWidth & labelHeight: 设置tick中label的大小
reserveSpace:
tickLength: 设置tick线的长度。默认ticks长度延伸到整个plot, 设置0为则完全的隐藏线条。
alignTicksWithAxis: 当设置折线图相同轴的坐标轴不止一条时,设置该属性可以美化数据对应的外观,设置为1,当你存在一条Y轴在左边另外一条在右边时,网格线可以自动的匹配他们对应的数值。
如果你需要不止一条x轴或者y轴来显示数据(如在data属性中设置yaxis: 2),你需要指定图中每条data对应使用的坐标轴。在这里我们通过xaxes:[] & yaxes: []来设置。
1 grid: { 2 show: boolean 3 aboveData: boolean 4 color: color 5 backgroundColor: color/gradient or null 6 margin: number or margin object 7 labelMargin: number 8 axisMargin: number 9 markings: array of markings or (fn: axes -> array of markings) 10 borderWidth: number or object with "top", "right", "bottom" and "left" properties with different widths 11 borderColor: color or null or object with "top", "right", "bottom" and "left" properties with different colors 12 minBorderMargin: number or null 13 clickable: boolean 14 hoverable: boolean 15 autoHighlight: boolean 16 mouseActiveRadius: number 17 } 18 19 interaction: { 20 redrawOverlayInterval: number or -1 21 }
网格是图的基本架构,我们可以在grid属性中设置更多的参数。
show: boolean. 设置为false时绘制的图不显示网格,ticks也不显示。
aboveData: 如果设置为true, 则网格线处于图的上方。
color: 设置网格的颜色。
backgroundColor: 设置网格的背景色。
margin: {top: pixels, bottom:pixels, left: pixels, right: pixels}设置图对于placeholder的外边距值。
labelMargin: 设置tick的label和坐标线的空间,取值为pixels.
axisMargin: 当我们设置两条同轴的坐标轴在同一边时设置其之间的边距。
markings: 数组值或者方法。用来在plot的背景中绘画出简单的线条或者矩形,你可以指定数组来规定x轴和y轴的范围{xaxis: {from, to}, yaxis{from, to}, color: ##}或者用一个方法来返回如上格式的数组。
如果你想要着重渲染某一块区域的或者某一条坐标线,可以使用from a to a
markings: [ { xaxis: { from: 0, to: 2 }, yaxis: { from: 0, to: 0.5 }, color: "#bb0000" }, ... ]
1 markings: function (axes) { 2 var markings = []; 3 for (var x = Math.floor(axes.xaxis.min); x < axes.xaxis.max; x += 2) 4 markings.push({ xaxis: { from: x, to: x + 1 } }); 5 return markings; 6 }
borderWidth & borderColor: 用来设置网格边框的颜色和宽度。
minBorderMargin: 设置默认最小的网格的外边距。
clickable & hoverable: 设置该属性为true, plot会监听鼠标在plot区域发生的事件并执行"plotclick"和“plothover”事件。该两个事件的参数为function(position, dataItem)。如下是plotclick和plothover事件的用例:
1 $.plot($("#placeholder"), [ d ], { grid: { clickable: true } }); 2 3 $("#placeholder").bind("plotclick", function (event, pos, item) { 4 alert("You clicked at " + pos.x + ", " + pos.y); 5 // axis coordinates for other axes, if present, are in pos.x2, pos.x3, ... 6 // if you need global screen coordinates, they are pos.pageX, pos.pageY 7 8 if (item) {10 alert("You clicked a point!"); 11 } 12 });
当我们点击plot区域的point时,item对象不为空,其内部属性为:
item: { datapoint: the point, e.g. [0, 2] dataIndex: the index of the point in the data array series: the series object seriesIndex: the index of the series pageX, pageY: the global screen coordinates of the point }
pageX & PageY: 为该点在整个屏幕中的坐标值。
autoHighlight: boolean.如果设置为true,则点会自动被highlight。
mouseActiveRadius: 设置鼠标触及该点多远的距离仍然可以触发事件,在两个点相隔很近的时候,plot默认传入最近的那个点的数据。对于柱状图,两个柱子相隔很近的时候鼠标触击默认自动选择最高的柱子。
keep updating!