背景及相关简介

在最近的BS新项目中需要用到绘图数据显示的功能。在进行充足的选择之后决定才去开源的Flot。Flot是一个jQuery绘图库。主要用于简单的绘制图表功能。具有吸引人的渲染外观和互操作的特性。其在Internet Explorer 6+, Chrome, Firefox 2+, Safari 3+ and Opera 9.5+浏览器下工作正常。目前的版本是Version0.8.3. 以下是相关链接。在官网的example中展示出了flot可以绘制的样例,并且我想这些样例的源代码也许是大家如何学习flot的最快的方法吧。嘿嘿。这里有一点要注意的地方: 在文档中都用plot来代替Flot,作者给出了回答瞬间无语。

What's with the name?

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.

官网

GitHub

内容

安装

和其他jquery库一样,我们只需要在html文档的末尾的jquery库的后面引入即可。这里要注意的是我们的浏览器必须支持HTML5 canvas标签。为了兼容IE9。我们可以使用canvas模拟库Excanvas来实现。我们在官网的demo中也可以发现如下的引入方式。

<!--[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。

基本使用 placeholder

创建一个占位div来放置绘出来的图:

<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中运行如下方法:

var plot = $.plot(placeholder, data, options)

我们来看看这三个参数和plot对象

  • placeholder:绘图要放置的div区域,为jquery对象或者DOM对象。
  • data: 绘图需要的数据集合,为一个数组
  • options: 自定义绘图的设置
  • plot: 该对象提供了一些方法来给我们使用返回值

这里是一个简单的例子:

$.plot($("#placeholder"), [ [[0, 0], [1, 1]] ], { yaxis: { max: 1 } });

数据格式 data

[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:  选择高亮的颜色。

每个字段都存在一个默认值。如果我们对其需要的属性进行再赋值则覆盖掉默认值如:

[ { 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的统一设置中来集体设置以上相关属性。

Options

所有的选项都是完全可选择的,我们可以单独的在文档中定义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属性

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. }

定制化 axes

  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可接受的值如下:

  • 数值: 我们可自行指定算法根据data源来生成多少条ticks,但是尽管你设置了数值假如为3,算法也会尽量去满足你的要求去生成适合的ticks数量,如果5条更加适合的话算法就会生成5条。
  • 0: 如果你不想显示任何的ticks, 你可以设置为0或者一个空的数组[].
  • 数组: 如果你想完全的覆盖 tick生成算法, 你可以给ticks指定任何的数组来绑定ticks.我们可以通过string来定制显示该tick.
    1. ticks: [[0, "zero"], [5, "one mark"], [10, "two marks"]]
  • function: 我们可以灵活的指定tick生成方法来通过其数组的返回值设定ticks。如下例子是通过方法的返回值来设置pi的倍数的ticks。
    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类型。默认的格式化器为:

  1. function formatter(val, axis) {
  2. return val.toFixed(axis.tickDecimals);
  3. }

这里有一个定制化的格式化器:

  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轴在左边另外一条在右边时,网格线可以自动的匹配他们对应的数值。

Multiple Axes

如果你需要不止一条x轴或者y轴来显示数据(如在data属性中设置yaxis: 2),你需要指定图中每条data对应使用的坐标轴。在这里我们通过xaxes:[] & yaxes: []来设置。

定制化Grid

  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

  1. 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) { alert("You clicked a point!");
  9. }
  10. });

当我们点击plot区域的point时,item对象不为空,其内部属性为:

  1. item: {
  2. datapoint: the point, e.g. [0, 2]
  3. dataIndex: the index of the point in the data array
  4. series: the series object
  5. seriesIndex: the index of the series
  6. pageX, pageY: the global screen coordinates of the point
  7. }

pageX & PageY: 为该点在整个屏幕中的坐标值。

autoHighlight: boolean.如果设置为true,则点会自动被highlight。

mouseActiveRadius: 设置鼠标触及该点多远的距离仍然可以触发事件,在两个点相隔很近的时候,plot默认传入最近的那个点的数据。对于柱状图,两个柱子相隔很近的时候鼠标触击默认自动选择最高的柱子。

keep updating!

Flot chart学习笔记的更多相关文章

  1. 操作系统学习笔记(五)--CPU调度

    由于第四章线程的介绍没有上传视频,故之后看书来补. 最近开始学习操作系统原理这门课程,特将学习笔记整理成技术博客的形式发表,希望能给大家的操作系统学习带来帮助.同时盼望大家能对文章评论,大家一起多多交 ...

  2. 【工作笔记】BAT批处理学习笔记与示例

    BAT批处理学习笔记 一.批注里定义:批处理文件是将一系列命令按一定的顺序集合为一个可执行的文本文件,其扩展名为BAT或者CMD,这些命令统称批处理命令. 二.常见的批处理指令: 命令清单: 1.RE ...

  3. AForge学习笔记(列表)

    AForge学习笔记(11):AForge.Imaging.Textures Clouds texture:具有云彩的纹理效果,示例如下:             CloudsTexture text ...

  4. Scrum 学习笔记

    Scrum 学习笔记 敏捷火了非常长一段时间了,可是一直没有机会实践,如今開始组队实践了,哈哈,先好好研习下规则~~ 什么是 scrum Scrum是一个敏捷开发框架,是一个增量的.迭代的开发过程.在 ...

  5. IOS学习笔记07---C语言函数-printf函数

    IOS学习笔记07---C语言函数-printf函数 0 7.C语言5-printf函数 ------------------------- ----------------------------- ...

  6. VSTO学习笔记(二)Excel对象模型

    原文:VSTO学习笔记(二)Excel对象模型 上一次主要学习了VSTO的发展历史及其历代版本的新特性,概述了VSTO对开发人员的帮助和效率提升.从这次开始,将从VSTO 4.0开始,逐一探讨VSTO ...

  7. vue中添加Echarts图表的使用,Echarts的学习笔记

    项目中需要使用一些折线图.柱状图.饼状图等等,之前使用过heightCharts(关于heightCharts请看我的另一篇 http://www.cnblogs.com/jasonwang2y60/ ...

  8. PowerDesigner 15学习笔记:十大模型及五大分类

    个人认为PowerDesigner 最大的特点和优势就是1)提供了一整套的解决方案,面向了不同的人员提供不同的模型工具,比如有针对企业架构师的模型,有针对需求分析师的模型,有针对系统分析师和软件架构师 ...

  9. amazeui学习笔记一(开始使用5)--藏品collections

    amazeui学习笔记一(开始使用5)--藏品collections 一.总结 1.藏品collections:一些 Amaze UI 中没有的功能.amazeui认为好的解决方案.像图表绘制里面的百 ...

随机推荐

  1. struts2 s:textfield

    初学struts2,在头脑中一直在想一个问题,就是对于struts2 ,当应用其自身的标签时,例如: <s:form> <s:textfield name="a" ...

  2. python基础之语句结束

    1 2 3 4 5 if a :     if b:          # 这里是if b的作用区间     #这里是if a的作用区间 #这里不在if 区间 python 是按缩进来识别代码块的.

  3. getpwuid()函数

    linux getpwuid 得到指定用户信息 和系统数据相关的passwd 结构 和系统数据相关的一个结构passwd定义如下 /* The passwd structure. */ struct ...

  4. DBubtil的使用

    1.什么是O-R Mapping(对象-关系映射) 常用O-R Mapping映射工具 Hibernate(全自动框架) Ibatis(半自动框架/SQL) Commons DbUti ls(只是对J ...

  5. HTTP中的URL长度限制(资料整理)

    HTTP中的URL长度限制   首先,其实http 1.1 协议中对url的长度是不受限制的,协议原文: The HTTP protocol does not place any a priori l ...

  6. 6 支持向量机SVM

    注:理论部分参考:http://blog.csdn.net/v_july_v/article/details/7624837 (1)SVM是现成最好的分类器,这里“现成”指的是分类器不加修改即可直接使 ...

  7. 分支-15. 日K蜡烛图

    /* * Main.c * 分支-15. 日K蜡烛图 * Created on: 2014年6月18日 * Author: Boomkeeper ****测试通过***** */ #include & ...

  8. Congos

    http://hi.baidu.com/tag/cognos%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86/feeds http://www.blogjava.net/mlh ...

  9. 论山寨手机与Android联姻 【6】MTK手机的基带芯片

    MTK的硬件技术的核心,在于它的基带芯片.为了降低成本,同时缩减手机主板的面积,基带芯片中除了CPU以外,还集成了很多外设控制器.Feature Phone的功能,基本上取决于基带芯片所支持的外设功能 ...

  10. 假数据自我添加测试--NSArray object

    一.列表假数据 //在.h文件里面定义node所包含实体类---1 struct listTestNode { NSString *image; NSString *name; }; //在.m实现文 ...