JavaScript 图表入门指南(五)
十三、jqPlot 散点图和气泡图
Abstract
在这一章中,我将讨论一类在表示数据分布时特别有用的图表。您可能会经常发现自己对一组数据如何沿两个不同参数定义的空间分布感兴趣,这两个参数沿 x 轴和 y 轴显示。这种数据分布可以暗示相关性或聚类。
在这一章中,我将讨论一类在表示数据分布时特别有用的图表。您可能会经常发现自己对一组数据如何沿两个不同参数定义的空间分布感兴趣,这两个参数沿 x 轴和 y 轴显示。这种数据分布可以暗示相关性或聚类。
散点图是显示数据分布的最佳选择,尤其是当需要分析大量数据时。因此,您将首先使用一个简单的示例来学习如何实现这种图表。随后,您将看到,一旦定义了两个不同的数据组(聚类),就可以通过趋势线突出显示 x 和 y 变量之间的相关性。
最后,您将分析另外两种类型的图表:气泡图和块状图。这些可以被认为是散点图的变体,其中数据点被气泡或方块取代。当您需要用三个不同的参数来表示数据时,可以使用气泡图(散点图只适用于两个参数);第三个参数由气泡的半径表示。方块图是一种特殊的散点图,在其中,您使用包含标签的方框来代替数据点。
散点图(xy 散点图)
乍一看,您可能认为散点图(也称为散点图或 xy 图)是一种点不相连的折线图,但这将是一个错误。事实上,散点图、气泡图和块状图都是一种特殊的图表。在散点图中,点由(x,y)对表示,但是您可以获得许多具有相同 x 值的点,这使得用线将它们连接起来既困难又不必要。折线图的目的是跟踪 x 值范围内 y 值的进度。散点图的目的是显示一组点,这些点可能有也可能没有某种关系(可以是非线性的)。此外,您可能希望分析这些点及其在(x,y)空间中的分布,例如,当它们分布在空间上独立的组中时。
您使用默认设置(如在折线图中),禁用点之间的线。例如,让我们看两个(x,y)数据集合,它们可能呈现某种形式的关系,如清单 13-1 所示。
清单 13-1。ch13_04a.html
var data = [[400, 35], [402, 37], [650, 55], [653, 56], [650, 50],
[700, 55], [600, 37], [601, 43], [450, 38], [473, 37],
[480, 42], [417, 37], [510, 41], [553, 44], [570, 39],
[527, 41], [617, 41], [625, 49]];
var data2 = [[100, 40], [600, 80], [200, 50], [300, 55], [400, 60],
[500, 70], [123, 43], [110, 41], [157, 45], [160, 48],
[237, 49], [248, 55], [287, 50], [321, 59], [359, 52],
[387, 62], [466, 68], [533, 74], [344, 60], [323, 51],
[430, 65]];
与折线图不同,您输入的点没有任何顺序。如前所述,您使用默认设置,通过将showLine属性设置为“””来禁用点之间的线(参见清单 13-2)。
清单 13-2。ch13_04a.html(使用'false'禁用点之间的线)
var options = {
title: 'Scatter Chart',
seriesDefaults: {
showLine: false,
showMarkers: true
}
};
$.jqplot('myChart', [data, data2], options);
这样你就得到图 13-1 中的散点图,其中两组数据覆盖了图表的两个不同区域。这些点被分成定义明确的组。
图 13-1。
A scatter chart
只有当两个数据集合被表示出来时,确定它们是否遵循线性或指数趋势才有意义。在这里,您可以使用 jqPlot 的趋势线功能。因此,您包括了趋势线插件:
<script type="text/javascript" src="../src/plugins/jqplot.trendline.min.js"></script>
或者,如果您更喜欢使用内容交付网络(CDN)服务,您可以按照以下方式进行:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.trendline.min.js
然后,激活两个系列的趋势线插件,给每条线分配不同的颜色(见清单 13-3)。
清单 13-3。ch13_04b.html
var options = {
title: 'Scatter Chart',
seriesDefaults: {
showLine: false,
showMarkers: true
} ,
series: [{
trendline: {
show: true,
color: '#0000ff',
type: 'exponential'
}
},{
trendline: {
show:true,
color: '#ff0000'
}
}]
};
结果,你得到一个散点图,有两个不同的序列,每个序列都有自己的趋势线,如图 13-2 所示。
图 13-2。
A scatter chart with trend lines
泡泡图
当您需要以三维方式显示数据时,可以使用气泡图。因此,每个实体由独立值的三元组(v1,v2,v3)表示。这些值中的两个通过绘制以(x,y)点为中心的圆盘来表示。第三个值由圆盘半径(r)表示。因此,(v1,v2,v3)三元组必须转换为(x,y,r)。三个(v1,v2,v3)值中的哪一个是半径,哪一个是 x 或 y 取决于图表设计者的技能。
与 xy 图表类似,气泡图通常用于确定所表示的数据之间的可能关系,甚至用于查看它们是否属于不同的组。这种方法在科学、医学和经济数据分析中很常见。
jqPlot 中有一个专门针对气泡图的插件:BubbleRenderer。因此,有必要在您的网页中包含这个插件:
<script type="text/javascript" src="../src/plugins/jqplot.bubbleRenderer.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.bubbleRenderer.min.js
输入数据数组每项有四个值:
[x, y, radius, <label or object>]
前两个值代表(x,y)坐标,第三个值(注意!)与气泡半径成正比,最后一个值代表引用标签(实际上也可以传递一个对象;稍后会有更多相关内容)。清单 13-4 定义了一个包含七个欧洲国家特征值的数组:作为 x 的值,你将插入表面积;对于 y,人口;半径代表经济价值。第四个值是报告州名的标签。
清单 13-4。ch13_01a.html
var data = [[301,60,29392,"Italy"], [675,65,34205,"France"],
[506,46,30625,"Spain"], [357,81,37896,"Germany"],
[450,9,37333,"Sweden"], [30,11,37736,"Belgium"],
[132,11,27624,"Greece"]];
现在,让我们分析如何设置options变量(见清单 13-5)。您需要激活seriesDefault对象中的 BubbleRenderer 插件,并将bubbleGradients属性设置为“true”。这将使“气泡”充满颜色渐变,给人一种深度感:这样圆盘看起来就像球体一样。正如您所看到的,对于这个插件,您不需要创建一个包含气泡标签的数组,然后将它显式分配给options中的一个对象;标签由相同的输入数据阵列自动读取。在options中指定的设置很少且简单。
清单 13-5。ch13_01a.html(设置options变量)
var options = {
title: 'Bubble Chart with Gradient Fills',
seriesDefaults:{
renderer: $.jqplot.BubbleRenderer,
rendererOptions: {
bubbleGradients: true
},
shadow: true
},
axes: {
xaxis: {
label: "Total area [*1000 km3]"
},
yaxis: {
label: "Population [million]"
}
}
};
$.jqplot('myChart', [data], options);
最后,通过这几行代码,你得到了如图 13-3 所示的精彩气泡图。
图 13-3。
A bubble chart
前面,我们提到了将一个对象作为输入数据数组中的第四个值进行传递的可能性。在这里,你可以详细地看到这涉及到什么。您可以同时传递一个对象,该对象允许您定义每个单独元素(气泡)的标签和颜色。使用前面的例子(见清单 13-5),你可以附加不同于默认序列的颜色。例如,假设你想强调一个国家的价值高于其他国家。你拿瑞典为例,把它指定为红色。你给其他国家分配各种深浅不同的棕色。然后将瑞典的数据移到一个新的数组中,data2;这是为了确保“瑞典”气泡总是在前景中,并且不会被其他气泡覆盖(见清单 13-6)。
清单 13-6。ch13_02.html
var data = [[301, 60, 29392, {label: 'Italy',color:'#b39524'}],
[675, 65, 34205, {label: 'France', color:'#c39564'}],
[506, 46, 30625, {label: 'Spain',color:'#a39544'}],
[357, 81, 37896, {label: 'Germany', color:'#b39524'}],
[30, 11, 37736, {label: 'Belgium',color:'#c39544'}],
[132, 11, 27624, {label: 'Greece', color:'#a39564'}]];
var data2 = [[450, 9, 37333, {label: 'Sweden', color:'#ff2524'}]];
使用相同的options,你只需要修改jqplot()函数,如清单 13-7 所示。您采用这个小捷径,知道最右边的数组项是最后绘制的项,因此它会出现在前景中。
清单 13-7。ch13_02.html(修改jqplot()功能)
$.jqplot('myChart',data,``data2
图 [13-4 给出了结果。
图 13-4。
A bubble chart with a selected state in the foreground
默认的颜色顺序很适合你,但是你决定将渐变填充改为透明效果。要做到这一点,你必须添加bubbleAlpha属性,并给它指定所需的透明度值,如清单 13-8 所示。
清单 13-8。ch13_01b.html
seriesDefaults:{
renderer: $.jqplot.BubbleRenderer,
rendererOptions: {
bubbleGradients: true,
bubbleAlpha: 0.6
},
shadow: true
},
图 13-5 显示了带有透明效果的渐变填充气泡,提供了底层气泡的一瞥。
图 13-5。
A bubble chart with transparency
方块图
块图(也称为块图)与气泡图非常相似,但它使用的不是圆盘,而是矩形。这里,矩形的大小没有任何意义,除了为那些将标签应用于给定(x,y)对的矩形提供空间。
与气泡图一样,有必要在网页中包含 BlockRenderer 插件:
<script type="text/javascript" src="../src/plugins/jqplot.blockRenderer.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.blockRenderer.min.js
在本例中,您将使用三组数据。输入数据数组应该具有以下格式:
[x, y, 'Label'],
现在,定义三个不同的数组,如清单 13-9 所示。
清单 13-9。ch13_03.html
var data1 = [[10, 30, 'Copper'], [100, 40, 'Gold'], [50, 50, 'Silver'],
[12, 78, 'Lead'], [44, 66, 'Brass']];
var data2 = [[68, 15, 'Maple'], [33, 22, 'Oak'],[10, 90, 'Ebony'],
[94, 30, 'Beech'],[70, 70, 'Ash']];
var data3 = [[22, 16, 'PVC'], [56, 76, 'PE'], [33, 78, 'PET'],
[27, 60, 'PC'], [70, 44, 'PU']];
在options中,你只需要激活seriesDefault对象中的 BlockRenderer 插件(见清单 13-10)。
清单 13-10。ch13_03.html(激活BlockRenderer插件)
var options = {
seriesDefaults:{
renderer: $.jqplot.BlockRenderer
}
};
$.jqplot ('myChart', [data1, data2, data3], options);
图 13-6 给出了您刚刚定义的框图,其中每个系列用不同的颜色标记。
图 13-6。
A block chart
摘要
在这一章中,你已经学会了如何表示一个分布。您可能会经常发现自己对研究数据在空间中的分布感兴趣,以便发现任何可能的趋势或聚类。根据您更想突出什么,您可以选择通过散点图、气泡图或方块图来表示数据。此外,您已经看到了如何突出一个分布的趋势。
在下一章中,我将收集其他类型的图表,这些图表您还没有看过,但是属于 jqPlot 库的标准类型。首先,您将学习漏斗图以及如何通过options设置其属性。然后,您将发现贝塞尔曲线——它们是什么,以及 jqPlot 如何实现它们。
十四、jqPlot 漏斗图
Abstract
漏斗图用于显示数据从一个级别到下一个级别的逐渐减少。图表由一个倒金字塔或漏斗组成,分为不同的层次。每个级别都有自己的面积,与给定的百分比值成比例。漏斗图与饼图相似,都是将一个整体分成几个组成部分来表达。但是,漏斗图指定了级别,它们以非常精确的顺序一个接一个。这个序列可以表示层次顺序、过程的步骤等等。饼图不能做到这一点。
漏斗图用于显示数据从一个级别到下一个级别的逐渐减少。图表由一个倒金字塔或漏斗组成,分为不同的层次。每个级别都有自己的面积,与给定的百分比值成比例。漏斗图与饼图相似,都是将一个整体分成几个组成部分来表达。但是,漏斗图指定了级别,它们以非常精确的顺序一个接一个。这个序列可以表示层次顺序、过程的步骤等等。饼图不能做到这一点。
创建漏斗图
即使对于这个专门的图表,jqPlot 也提供了一个特定的插件:FunnelRenderer。因此,您需要包含它:
<script type="text/javascript" src="../src/plugins/jqplot.funnelRenderer.min.js"></script>
或者,如果您更喜欢使用内容交付网络(CDN)服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.funnelRenderer.min.js
使用 jqPlot,您必须注意特定于该渲染器插件的行为:FunnelRenderer 以降序对数据进行重新排序。最大值显示在漏斗的顶部,较小值显示在下方。每个漏斗部分的面积对应于其数据点的值,相对于所有值的总和(百分比)。使用此渲染器,您需要对输入数据数组使用以下格式:
['label',value]
因此,在本例中,您将数据数组定义如下:
var data = [['Sony', 1], ['Samsung', 13], ['LG', 14], ['Philips', 5]];
对于options,您必须激活seriesDefaults对象中的漏斗渲染器插件,并且,可选地,您可以添加一个报告系列标签的图例,如清单 14-1 所示。
清单 14-1。ch14_01a.html
var options = {
seriesDefaults: {
renderer: $.jqplot.FunnelRenderer
},
title: {
text: 'Basic Funnel Chart'
},
legend: {
location: 'e',
show: true
}
};
$.jqplot('myChart', [data], options);
图 14-1 是基本的漏斗图。
图 14-1。
A simple funnel chart
如您所见,项目的顺序已经改变,具有最高值的元素在顶部,依此类推,直到具有最低值的项目。这是基本的图表,但是您可以丰富它,例如,通过添加报告百分比的标签。为此,您必须添加dataLabel属性,将其设置为“percent,然后使用设置为“true”的showDataLabel启用它(参见清单 14-2)。
清单 14-2。ch14_01b.html
seriesDefaults: {
renderer: $.jqplot.FunnelRenderer,
rendererOptions: {
dataLabels: 'percent',
showDataLabels: true
}
},
正如您在图 14-2 中看到的,百分比值现在在漏斗图的相应部分中报告。
图 14-2。
A funnel chart with a legend and percentages
您可以做进一步的更改。例如,假设你想减小漏斗截面之间的间距,如图 14-3 所示。您可以通过传递给sectionMargin属性的值来实现这一点。通过将值 0 赋给sectionMargin属性,你完全消除了部分之间的空间(见清单 14-3)。
清单 14-3。ch14_01c.html
rendererOptions: {
dataLabels: 'percent',
showDataLabels: true ,
sectionMargin: 0
}
图 14-3。
A funnel chart without spaces between sections
或者,你可能想将不同的扇区表示为未填充的,并增加其边界线的宽度,如图 14-4 所示。为此,需要使用两个属性:fill和lineWidth。首先,您将fill属性设置为“false”,这将导致 jqPlot 绘制带有空白区域的截面;然后,将lineWidth属性设置为 4,从而增加部分边缘的厚度,使它们更加可见(见清单 14-4)。
清单 14-4。ch14_01d.html
rendererOptions: {
dataLabels: 'percent',
showDataLabels: true,
fill: false,
lineWidth: 4
}
图 14-4。
A funnel chart with no filled sections
摘要
在这一章中,你学习了如何制作某些类型的漏斗图,以及如何通过options改变它们的属性。
在下一章中,我将讨论我在前面章节中提到过的一个主题:控件。我将描述在图表中引入控件的重要性,理解每个控件背后都隐藏着一个属性options。这为用户提供了实时选择属性的机会。
十五、将控件添加到图表
Abstract
有时,在运行时直接从浏览器更改设置,然后用这些新设置重新绘制图表会很有用。一种典型的方法是添加活动控件。这些控件使图表具有交互性,允许用户实时做出选择,例如决定图表应该如何表示。通过插入控件,用户可以控制图表的属性值,这通常需要在options中设置。
有时,在运行时直接从浏览器更改设置,然后用这些新设置重新绘制图表会很有用。一种典型的方法是添加活动控件。这些控件使图表具有交互性,允许用户实时做出选择,例如决定图表应该如何表示。通过插入控件,用户可以控制图表的属性值,这通常需要在options中设置。
在这一章中,你将会看到在你的网页中引入控件。您还将考虑导致选择一种控制类型而不是另一种控制类型的因素。以三个最常用的控件为特色的一系列示例将带您更深入地了解这个主题。
添加控件
对控件进行分组的一种方法是根据它们的功能。一些控件(例如,按钮、菜单)作为开关(命令控件)工作,用户可以用其触发特定事件或启动命令。其他控件(例如,复选框、单选按钮、组合框、滑块)绑定到特定的值或属性。使用这种类型的控件,用户可以通过文本字段(文本区域)进行选择或输入值。还有一些控件(例如滚动条)具有导航功能,尤其适用于需要移动对象的情况,例如列表中的选定项或包含在框架或网页中的大图像。
在这里,您将研究那些与值相关联的控件,这些控件允许用户通过选择与图表进行交互。这些控件应该以某种方式图形化地表示特定属性可以采用的值(通常分配给options对象中的属性的相同值,仅限于您希望提供给用户的值)。您对控件的选择将取决于要设置的属性及其可能采用的值:
图 15-1。
Three of the most commonly used controls: (a) radio buttons, (b) check boxes, (c) sliders
- 为了使用户能够从一组值(例如,三种可能的颜色之一)中进行单一选择,选择互斥的单选按钮作为控件是最佳的(参见图 15-1a )。
- 为了让用户选择哪个系列应该在图表中可见,你需要使用复选框(见图 15-1b )。
- 为了允许用户在特定属性的值范围内进行选择(例如,通过调整定义颜色的红绿蓝(RGB)值来改变对象的颜色),滑块通常是最佳选择(参见图 15-1c )(在这种情况下,您将使用三个滑块作为控件,分别对应于红色、绿色和蓝色)。
可能的控制列表并没有到此为止。但是,对这些控件背后的机制的理解使图表开发人员能够处理绝大多数情况,包括最复杂的情况。
在下面的示例中,您将发现如何将这三个控件应用于您的图表。
使用单选按钮
为了说明控件的用法,让我们先来看看单选按钮。单选按钮是以列表形式分组的一组小按钮(参见图 15-1a )。它们通常被表示为小而空的圆圈,旁边有文字。如前所述,这种类型的控制与某个值或属性相关联。单选按钮的特殊性在于它们的值是互斥的;因此,用户只能选择其中之一。
举例来说,让我们以一个简单的多系列折线图为例,在该图中,不是显示所有的系列,而是让用户决定显示哪个系列。要进行选择,用户将单击其中一个单选按钮,用圆点填充圆圈。对应于该控件的系列将被绘制在图表上。
添加单选按钮控件
首先,你需要编写 HTML 页面,导入所有必要的库(见清单 11-1)。
清单 15-1。ch15_01.html
<HTML>
<HEAD>
<TITLE>Selection series with controls</TITLE>
<!--[if lt IE 9]>
<script type="text/javascript" src="../src/excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="../src/jquery.min.js"></script>
<script type="text/javascript" src="../src/jquery.jqplot.min.js"></script>
<link rel="stylesheet" type="text/css" href="../src/jquery.jqplot.min.css" />
<script>
$(document).ready(function(){
//add your code here
});
</script>
</HEAD>
<BODY>
<div id="myChart" style="height: 300px; width: 500px;"></div>
<!-- add the table with the controls here -->
</BODY>
</HTML>
或者,如果您更喜欢使用内容交付网络(CDN)服务,您可以使用以下代码:
<!--[if lt IE 9]>
<script src="http://cdn.jsdelivr.net/excanvas/r3/excanvas.js
<![endif]-->
<script src="http://code.jquery.com/jquery-1.9.1.min.js
<script type="text/javascript"
src="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.js
<link rel="stylesheet" type="text/css"
href="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.css
您从一个折线图开始,在折线图中,您将表示四组值。每个序列中的每个元素将由一对(x,y)值表示;您将这四个序列的值插入到 jQuery $(document).ready()函数中定义的数据集中,如清单 15-2 所示。
清单 15-2。ch15_01.html
var dataSet = {
data1: [[1, 1], [2, 2], [3, 3], [4, 2], [5, 3], [6, 4]],
data2: [[1, 3], [2, 4], [3, 5], [4, 6], [5, 5], [6, 7]],
data3: [[1, 5], [2, 6], [3, 8], [4, 9], [5, 7], [6, 9]],
data4: [[1, 7], [2, 8], [3, 9], [4, 11], [5, 10], [6, 11]]
};
但是,不是像前面看到的那样用不同颜色的线条显示所有四个系列,而是让用户一次只显示一个系列。一旦图表加载到浏览器中,用户将能够选择四个系列中的任何一个并在它们之间切换,而不必加载新的页面。
首先,只表示第一个序列(data1)(见清单 15-3)。
清单 15-3。ch15_01.html
var options = {
seriesDefaults: {
showMarker: false
},
title: 'Series selection',
axes: {
xaxis: {},
yaxis: {
min: 0,
max: 12
}
}
};
var plot1 = $.jqplot('myChart', [dataSet.data1], options);
Note
在这个例子中,您将由$.jqplot()函数返回的值存储在plot1变量中。这允许您访问jqplot对象的内容,更改值,并调用它的方法,包括replot()函数,它允许您再次绘制图表,包括新的更改。
用户将从一组可能的选项中选择一个选项;单选按钮是实现这一目的的最佳选择。因此,让我们为每个单选按钮分配一个系列。正如你在清单 15-4 中看到的,所有的控件(按钮)都包含在一个表格的内部列表中。每个按钮由一个<input>元素指定,其中四个系列也被指定为值。
清单 15-4。ch15_01.html
<table>
<tr>
<td>
<div>
<ul>
<li><input name="dataSeries" value="data1" type="radio" checked />First Series</li>
<li><input name="dataSeries" value="data2" type="radio" />Second Series</li>
<li><input name="dataSeries" value="data3" type="radio" />Third Series</li>
<li><input name="dataSeries" value="data4" type="radio" />Fourth Series</li>
</ul>
</div> </td>
</tr>
</table>
然而,在 HTML 页面中设置控件定义是不够的;您还必须创建将单选按钮与 jqPlot 图表相关联的函数。根据哪个单选按钮处于checked状态,图表中将加载不同于数据集的集合。
在选择不同的单选按钮时,用户将选中的属性从'false'更改为'true'。单选按钮的状态改变涉及到change()功能的激活,该功能检测到该事件。该函数将数据集中的一个新集合分配给plot1变量(包含关于 jqPlot 图表的所有信息),并最终强制重新绘制图表。这样,新数据就显示在图表中,而不必重新加载页面(见清单 15-5)。
清单 15-5。ch15_01.html
$(document).ready(function(){
...
var plot1 = $.jqplot ('myChart', [dataSet.data1], options);
$("input[type=radio][name=dataSeries]").attr("checked", false);
$("input[type=radio][name=dataSeries][value=data1]").attr("checked", true);
$("input[type=radio][name=dataSeries]").change(function(){
var val = $(this).val();
plot1.series[0].data = dataSet[val];
plot1.replot();
});
});
要定制控件表中的元素,可以添加一点层叠样式表(CSS)样式,如清单 15-6 所示。
清单 15-6。ch15_01.html
<style>
li {
font-family: "Verdana";
font-size: 16px;
font-weight: bold;
text-shadow: 1px 2px 2px #555555;
margin: 3px;
list-style: none;
}
</style>
如果您在浏览器中加载此网页,您将获得图 15-2 中的图表。
图 15-2。
With radio buttons it is possible to select only one series of data
现在,用户可以选择在图表中显示哪个系列。选择单选按钮作为控件后,图表一次将只显示一组数据。
绘制图表后访问属性
到目前为止,您已经使用了options对象来定义图表的属性值(通过更改默认值),然后将其作为参数传递给$.jqplot()函数。但是,这仅适用于您希望在绘制图表之前描述其特征的情况。如果随后需要访问属性值,该怎么办?
事实上,通过引入控件作为参数,您也引入了在绘制图表后更改这些属性的可能性。因此,必须有一种方法来访问这些值,编辑它们,然后运行命令来重绘图表(就像使用replot()函数时一样)(见清单 15-5)。
您已经看到,您可以接收整个jqplot对象作为由$.jqplot()函数返回的值,并将它存储在一个变量中(在前面的例子中,是plot1变量),以便您可以在以后访问它的内容。
一个jqplot对象实际上包含了定义整个 jqPlot 库的所有对象——它们的属性和方法,并且每个特定的实例(例如plot1)都在特定图表的表示中实现。
因此,当您编写 JavaScript 代码来定义处理特定事件(如用户使用控件)的函数时,您可以访问这些值,并在页面设计完图表后更改它们,然后运行命令以所需的更改重新绘制图表。这增加了图表中所需的交互性。
继续前面的例子(参见清单 15-1 到 15-6),您会注意到这些线条都是用蓝色绘制的。现在让我们做一些更改,这样这次用户可以选择绘制系列的颜色。
要做到这一点,你要在表格中添加另一组控件:第二列单选按钮,每一列代表一种颜色(见清单 15-7)。
清单 15-7。ch15_02.html
<table>
<tr>
<td>
<div>
<ul>
<li><input name="dataSeries" value="data1" type="radio" checked />First series</li>
<li><input name="dataSeries" value="data2" type="radio" />Second series</li>
<li><input name="dataSeries" value="data3" type="radio" />Third series</li>
<li><input name="dataSeries" value="data4" type="radio" />Fourth series</li>
</ul>
</div>
</td>
<td>
<div>
<ul>
<li><input name="colors" value="#4bb2c5" type="radio" checked />Blue</li>
<li><input name="colors" value="#ff3333" type="radio" />Red</li>
<li><input name="colors" value="#44bb44" type="radio" />Green</li>
<li><input name="colors" value="#ffaa22" type="radio" />Orange</li>
</ul>
</div>
</td>
</tr>
</table>
接下来,将清单 15-8 中用粗体突出显示的行添加到 JavaScript 代码中。
清单 15-8。ch15_02.html
$("input[type=radio][name=dataSeries]").attr("checked", false);
$("input[type=radio][name=dataSeries][value=data1]").attr("checked", true);
$("input[type=radio][name=dataSeries]").change(function(){
var val = $(this).val();
plot1.series[0].data = dataSet[val];
plot1.series[0].renderer.shapeRenderer.strokeStyle = col;
plot1.replot();
});
var col = "#4bb2c5";
$("input[type=radio][name=colors]").change(function(){
col = $(this).val();
});
图 15-3 展示了用户如何在四种不同的颜色中进行选择来决定要表现的系列。这是一个添加控件如何增加用户和图表之间的交互性的例子。
图 15-3。
The user can select a different combination of colors and series
使用滑块
在前面的示例中,用户首先通过选中第二列中的一个单选按钮来设置颜色,然后从第一列中选择要用该颜色表示的系列。因此,这一过程包括在两个不同的时间做出的两个选择。这一次,您将保持第一列不变,用户从中选择要显示的系列(互斥),但是在单选按钮列的位置,您将插入一组三个滑块。在这种情况下,用户选择要显示的系列,一旦以预定义的颜色绘制在图表上,他或她就可以通过调整组成它的三个 RGB 值来修改该颜色。现在,你有一个选择,然后进行微调。
当需要通过滚动给定范围内的连续值来更改属性值时,滑块就是所需的控件。在这种情况下,需要三个滑块,每种颜色(红、绿、蓝)一个,以便用户可以调整 RGB 值来获得所需的颜色。
使用前面的例子(参见清单 15-7 和 15-8),首先选择 jQuery 接口库(jQuery UI)来获得滑块(关于如何使用 jQuery UI 小部件实现滑块的详细信息,参见第二章)。因此,在将滑块添加到网页之前,必须导入属于此库的所有必要文件:
<link rel="stylesheet"
href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js
Note
如果您在随本书提供的源代码可用的工作空间中工作(参见附录 A),您可以通过使用以下参考来访问工作空间中已经包含的库:
<link rel="stylesheet" href="../src/css/smoothness/jquery-ui-1.10.3.custom.min.css" />
<script type="text/javascript" src="../src/js/jquery-ui-1.10.3.custom.min.js"></script>
一旦导入了所有文件,就可以开始在 HTML 表格中插入三个滑块了。正如您在清单 15-9 中看到的,您删除了包含单选按钮的第二列,代之以一组<div>元素(如果您直接从这里开始,您可以复制整个清单,而不仅仅是粗体文本)。jQuery UI 会将它们转换成滑块(参见第二章)。
清单 15-9。ch15_04.html
<table>
<tr>
<td>
<div>
<ul>
<li><input name="dataSeries" value="data1" type="radio" checked />First series</li>
<li><input name="dataSeries" value="data2" type="radio" />Second series</li>
<li><input name="dataSeries" value="data3" type="radio" />Third series</li>
<li><input name="dataSeries" value="data4" type="radio" />Fourth series</li>
</ul>
</div>
</td>
<td>
<div id="red">
<div id="slider-text">
<div id="0">0</div>
<div id="1">255</div>
</div>
</div>
<div id="green">
<div id="slider-text">
<div id="0">0</div>
<div id="1">255</div>
</div>
</div>
<div id="blue">
<div id="slider-text">
<div id="0">0</div>
<div id="1">255</div>
</div>
</div>
</td>
</tr>
</table>
此外,您还使用slider-text id向每个滑块添加了两个数值。这些值只不过是用于显示三个滑块所覆盖的值范围(0–255)的最小值和最大值的标签。当您必须表示网页中每张幻灯片的比例时,这种方法非常有用。
现在让我们添加所有的 CSS 样式指令,以确保这些新控件可以在现有页面的上下文中正确显示(见清单 15-10)。
清单 15-10。ch15_04.html
<style>
...
#red, #green, #blue {
float: left;
margin: 15px;
left: 50px;
}
#red .ui-slider-range {
background: #ef2929;
}
#red .ui-slider-handle {
border-color: #ef2929;
}
#green .ui-slider-range {
background: #8ae234;
}
#green .ui-slider-handle {
border-color: #8ae234;
}
#blue .ui-slider-range {
background: #729fcf;
}
#blue .ui-slider-handle {
border-color: #729fcf;
}
#slider-text div {
font-family: "Verdana";
font-size: 10px;
position: relative;
left: 17px;
}
</style>
关于 JavaScript 中的代码部分,您只保留管理用于选择所需系列的单选按钮的部分,将其与处理 RGB 值的新代码部分集成,通过三个滑块进行调整,如清单 15-11 所示。然后,这三个 RGB 值通过适当的函数转换为十六进制数,并组合形成 HTML 颜色代码,用井号(#)表示,后跟六个十六进制字符('rrggbb'),其中每一对代表一个从 0 到 255 的值,转换为十六进制格式。
清单 15-11。ch15_04.html
$(document).ready(function(){
...
$("input[type=radio][name=dataSeries]").attr("checked", false);
$("input[type=radio][name=dataSeries][value=data1]").attr("checked", true);
$("input[type=radio][name=dataSeries]").change(function(){
var val = $(this).val();
plot1.series[0].data = dataSets[val];
plot1.series[0].renderer.shapeRenderer.strokeStyle = "#" + col;
plot1.replot();
});
var col = "4bb2c5";
function hexFromRGB(r, g, b) {
var hex = [
r.toString( 16 ),
g.toString( 16 ),
b.toString( 16 )
];
$.each( hex, function( nr, val ) {
if ( val.length === 1 ) {
hex[ nr ] = "0" + val;
}
});
return hex.join( "" ).toUpperCase();
};
$( "#red, #green, #blue" ).slider({
orientation: "vertical",
range: "min",
max: 255,
change: refreshPlot
});
// set col to default "#4bb2c5";
$( "#red" ).slider( "value", 255 );
$( "#green" ).slider( "value", 140 );
$( "#blue" ).slider( "value", 60 );
function refreshPlot() {
var r = $( "#red" ).slider( "value" );
var g = $( "#green" ).slider( "value" );
var b = $( "#blue" ).slider( "value" );
var col = hexFromRGB(r, g, b);
plot1.series[0].renderer.shapeRenderer.strokeStyle = "#" + col;
plot1.replot();
}
$("[id=0]").css('top','90px');
$("[id=1]").css('top','-20px');
});
清单 15-11 中的最后两行代码使用 jQuery css()函数将 CSS 样式分配给特定的 HTML 元素(参见第二章)。在所有带有id = 0和id = 1的元素上进行选择,也就是说,<div>元素包含滑块刻度的标签。您可以设置 CSS top 属性,将每个刻度标签放置在相应滑块旁边的特定高度。
在图 15-4 中,用户可以通过三个滑块修改 RBG 值来决定要显示和更改的系列。
图 15-4。
A chart with three slider widgets added to adjust the RGB levels
使用复选框
在前面的例子中,用户只能从可以显示的系列中选择一个。然而,典型地,用户将希望能够决定哪些系列应该被显示,哪些不应该被显示,例如,选择同时显示两个或更多组。这需要处理同一组中的多种选择。为了让用户做出这种选择,你必须选择复选框。
通常,复选框被分组在一个列表中,由空框表示(见图 15-1 )。与单选按钮不同,这些控件不是互斥的,而是多项选择。因此,您可以选择它们所代表的全部、部分值,或者不选择任何值(而对于单选按钮,必须选择一个项目)
与单选按钮类似,每个系列都有一个复选框,如果复选框被选中,相应的系列将显示在图表中。然而,与单选按钮不同,复选框是相互独立的:它们的状态(选中或未选中)不会影响其他复选框的状态。
通常,当您有一个复选框列表时,添加两个具有“全部选中/取消选中”功能的按钮会非常有用,从而允许通过一次单击来选择/取消选择所有复选框。
使用前面的例子(见清单 15-9 到 15-11),数据集和选项设置是相同的;您唯一需要更改的是在$.jqplot()函数中传递的数据。在这种情况下,整个数据集将作为参数传递。
var plot1 = $.jqplot ('myChart', [dataSet.data1, dataSet.data2, dataSet.data3, dataSet.data4], options);
让我们删除包含先前控件(单选按钮、滑块)的表格,并用一个包含复选框的新表格来替换它,如清单 15-12 所示(如果你直接从这里开始,你可以复制整个列表而不考虑先前的控件)。此外,除了用于多个系列的四个控件之外,您还可以在末尾添加一个按钮来管理“全部选中/取消选中”功能
清单 15-12。ch15_03.html
<table>
<tr>
<td>
<div>
<ul>
<li><input name="data1" type="checkbox" checked />First series</li>
<li><input name="data2" type="checkbox" checked />Second series</li>
<li><input name="data3" type="checkbox" checked />Third series</li>
<li><input name="data4" type="checkbox" checked />Fourth series</li>
<li><input type="button" name="checkall" value="Uncheck All"></li>
</ul>
</div>
</td>
</tr>
</table>
与单选按钮一样,您必须添加 jQuery 方法来绑定这些控件发生的事件。首先,定义每个复选框的状态。正常情况下都应该检查。然后,定义五个 jQuery 方法,启用或禁用要表示的系列,然后强制 replot。
从代码中,您必须删除所有处理先前控件的行,并在它们的位置上,编写清单 15-13 中的方法。
清单 15-13。ch15_03.html
$("input[type=checkbox][name=data1]").change(function(){
if(this.checked){
plot1.series[0].data = dataSet.data1;
plot1.replot();
} else {
plot1.series[0].data = [];
plot1.replot();
}
});
$("input[type=checkbox][name=data2]").change(function(){
if(this.checked){
plot1.series[1].data = dataSet.data2;
plot1.replot();
} else {
plot1.series[1].data = [];
plot1.replot();
}
});
$("input[type=checkbox][name=data3]").change(function(){
if(this.checked){
plot1.series[2].data = dataSet.data3;
plot1.replot();
} else {
plot1.series[2].data = [];
plot1.replot();
}
});
$("input[type=checkbox][name=data4]").change(function(){
if(this.checked){
plot1.series[3].data = dataSet.data4;
plot1.replot();
} else {
plot1.series[3].data = [];
plot1.replot();
}
});
$("input[type=button][name=checkall]").click(function(){
if(this.value == "Check All"){
plot1.series[0].data = dataSet.data1;
plot1.series[1].data = dataSet.data2;
plot1.series[2].data = dataSet.data3;
plot1.series[3].data = dataSet.data4;
$("input[type=checkbox][name=data1]").prop("checked", true);
$("input[type=checkbox][name=data2]").prop("checked", true);
$("input[type=checkbox][name=data3]").prop("checked", true);
$("input[type=checkbox][name=data4]").prop("checked", true);
this.value = "Uncheck All";
plot1.replot();
} else {
plot1.series[0].data = [];
plot1.series[1].data = [];
plot1.series[2].data = [];
plot1.series[3].data = [];
$("input[type=checkbox][name=data1]").prop("checked", false);
$("input[type=checkbox][name=data2]").prop("checked", false);
$("input[type=checkbox][name=data3]").prop("checked", false);
$("input[type=checkbox][name=data4]").prop("checked", false);
this.value = "Check All";
plot1.replot();
}
});
如图 15-5 所示,用户现在可以选择他或她想要在图表中显示的系列。
图 15-5。
A custom legend with check boxes and a button
如果您单击标记为“全部取消选中”的按钮,所有复选框都将被取消选中,相应的系列将在绘图中隐藏。随后,该按钮将显示标签“全部选中”当这次点击它时,所有的复选框将被选中,相应的系列将显示在图表中。
最后一个例子中涵盖的特性与 EnhancedLegendRenderer 插件提供的图例非常相似(参见第十章中的“处理图例”一节)。在这种情况下,通过单击与系列相对应的彩色方块,您可以决定是否应该在图表中显示该系列。但是,这里您还添加了只需一次点击就可以选中和取消选中所有系列的可能性,而且这个功能目前还没有在插件中实现(尽管有人正在提议)。这是如何通过使用控件来扩展库提供的功能的另一个小例子。
摘要
在本章中,您已经看到了如何使用各种控件(如单选按钮、滑块和复选框)来增加图表的交互性。随着控件的引入,作为程序员,我们不再是唯一能够直接控制图表属性值的人;通过这样的控制,用户也能够做出适当的选择。
此外,您了解了如何将 jQuery UI 小部件与 jqPlot 库集成,并将这些小部件用作控件。在下一章中,您将通过使用 jQuery UI 小部件作为图表的容器来完成这个集成。这种组合极大地扩展了使用 jqPlot 库开发和表示图表的可能性。
十六、在 jQuery 小部件中嵌入 jqPlot 图表
Abstract
在第二章中,您看到了几个用作容器的 jQuery UI 小部件的例子。在本章中,您将利用这种能力来表示这些容器中的图表。这使您能够利用 jQuery UI 小部件的巨大潜力来进一步改进图表的表示方式。
在第二章中,您看到了几个 jQuery UI 小部件被用作容器的例子。在本章中,您将利用这种能力来表示这些容器中的图表。这使您能够利用 jQuery UI 小部件的巨大潜力来进一步改进图表的表示方式。
结合 jQuery UI 和 jqPlot 库的好处是多方面的:可以在网页中显示更多占用相同空间的图表,同时保持页面的上下文整洁。另一个优点是 jQuery UI 小部件可以调整大小,甚至用户可以调整 jqPlot 图表的大小。
在本章中,您将探索三个简单的案例,在这些案例中,刚才提到的好处将变得显而易见。你在使用 jQuery UI 小部件时也会变得更加自信,甚至比你在第二章中做的还要自信。
选项卡上的 jqPlot 图表
你要用作容器的第一个小部件是选项卡(参见第二章的中的“选项卡”一节)。在选项卡内插入图表允许您在同一页面的有限区域内显示不同的图表。在本例中,您将在三个选项卡中放置三个不同的 jqPlot 图表,分别称为Tab 1、Tab 2和Tab 3。在第一个选项卡中,您将放置一个条形图,在第二个选项卡中,您将放置一个多系列折线图,在最后一个选项卡中,您将放置一个饼图。您不会详细分析这些图表,因为它们与前几章中使用的图表完全相同。每种类型的图表都需要特定的插件,清单 16-1 显示了所需插件的列表。
清单 16-1。ch16_01.html
<!--[if lt IE 9]>
<script src="http://cdn.jsdelivr.net/excanvas/r3/excanvas.js
<![endif]-->
<script src="http://code.jquery.com/jquery-1.9.1.min.js
<script src="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.js
</script>
<link rel="stylesheet" type="text/css"
href="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.css
<script src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.pieRenderer.min.js
</script>
<script type="text/javascript" src=" http://cdn.jsdelivr.net/jqplot/1.0.8/plugins 是
cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.dateAxisRenderer.min.js
<script type="text/javascript" src=" http://cdn.jsdelivr.net/jqplot/1.0.8/plugins 是
cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins
cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisTickRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins
cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.categoryAxisRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins
cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.barRenderer.min.js
此外,您将使用 jQuery 小部件作为容器,这也需要包含一些文件:
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js
Note
对于那些使用本书源代码的工作空间的人来说,可以使用工作空间中已经包含的库。使用以下参考资料:
<script src="../src/js/jquery-1.9.1.js"></script>
<script src="../src/jquery.jqplot.min.js"></script>
<link rel="stylesheet" type="text/css" href="../src/jquery.jqplot.min.css" />
<link rel="stylesheet" href="../src/css/smoothness/jquery-ui-1.10.3.custom.min.css" />
<script src="../src/js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="../src/plugins/jqplot.pieRenderer.min.js"></script>
<script src="../src/plugins/jqplot.dateAxisRenderer.min.js"></script>
<script src="../src/plugins/jqplot.canvasTextRenderer.min.js"></script>
<script src="../src/plugins/jqplot.canvasAxisTickRenderer.min.js"></script>
<script src="../src/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script src="../src/plugins/jqplot.barRenderer.min.js"></script>
随着网页上引入如此多的图形元素,级联样式表(CSS)样式的使用变得越来越重要。您需要定义一些设置来修改选项卡的外观,使它们符合您的需要。添加清单 16-2 中的样式设置。
清单 16-2。ch16_01.html
<style>
.ui-tabs {
width: 690px;
margin: 2em auto;
}
.ui-tabs-nav {
font-size: 12px;
}
.ui-tabs-panel {
font-size: 14px;
}
.jqplot-target {
font-size: 18px;
}
ol.description {
list-style-position: inside;
font-size: 15px;
margin: 1.5em auto;
padding: 0 15px;
width: 600px;
}
</style>
您将使用三种不同的图表,它们已经在前面的章节中使用过(参见第九章的折线图、第十章的条形图和第十一章的饼图)。因此,这一章不包括它们设置的细节。将它们添加到我们的 web 页面,用chart1、chart2和chart3替换通常的目标名称myChart。正如你在清单 16-3 中看到的,在这些图表中,你已经直接在三个jqplot()函数中定义了options对象。它们的返回值存储在三个不同的变量中:plot1、plot2和plot3。这些变量将用于处理 JavaScript 代码中相应的图表。
清单 16-3。ch16_01.html
var bar1 = [['Germany', 12], ['Italy', 8], ['Spain', 6],
['France', 10], ['UK', 7]];
var data1 = [1, 2, 3, 2, 3, 4];
var data2 = [3, 4, 5, 6, 5, 7];
var data3 = [5, 6, 8, 9, 7, 9];
var data4 = [7, 8, 9, 11, 10, 11];
var pie1 = [
['Dairy', 212], ['Meat', 140], ['Grains', 276],
['Fish', 131], ['Vegetables', 510], ['Fruit', 325]
];
var plot1 = $.jqplot ('chart1', [bar1], {
title: 'Foreigner customers',
series:[{renderer:$.jqplot.BarRenderer}],
axesDefaults: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: {
angle: -30,
fontSize: '10pt'
}
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
});
var plot2 = $.jqplot ('chart2', [data1, data2, data3, data4],{});
var plot3 = $.jqplot ('chart3', [pie1], {
seriesDefaults: {
renderer: jQuery.jqplot.PieRenderer,
rendererOptions: {
showDataLabels: true,
dataLabels: 'value',
fill: false,
sliceMargin: 6,
lineWidth: 5
}
}
});
现在是时候在$(document).ready()函数的末尾添加 jQueryUI tabs()函数了,如清单 16-4 所示。
清单 16-4。ch16_01.html
$(document).ready(function(){
...
$("#tabs").tabs();
});
这个调用创建了选项卡容器,因此您需要将选项卡绑定到您的绘图上(见清单 16-5)。
清单 16-5。ch16_01.html
$('#tabs').bind('tabsshow', function(event, ui) {
if (ui.index === 0 && plot1._drawCount === 0) {
plot1.replot();
}
else if (ui.index === 1 && plot2._drawCount === 0) {
plot2.replot();
}
else if (ui.index === 2 && plot3._drawCount === 0) {
plot3.replot();
}
});
选择一个选项卡将重新绘制其中的图表内容。现在,在 web 页面的<body>部分,您需要添加 jQuery UI 库将转换成选项卡的<div>元素。方法是用tabs指定一个<div>元素作为id。在其中,您定义了一个包含三个项目的列表,每个项目代表一个选项卡。在列表之后,您必须定义另外三个tabs的子部分:三个额外的<div>元素,称为tabs-1、tabs-2和tabs-3。你将把这些放到你的图表中:chart1、chart2和chart3(见清单 16-6)。
清单 16-6。ch16_01.html
<div id="tabs">
<ul>
<li><a href="#tabs-1">Tab 1</a></li>
<li><a href="#tabs-2">Tab 2</a></li>
<li><a href="#tabs-3">Tab 3</a></li>
</ul>
<div id="tabs-1">
<p>This is the bar chart</p>
<div id="chart1" style="height:300px; width:650px;"></div>
</div>
<div id="tabs-2">
<p>This is the line chart</p>
<div id="chart2" style="height:300px; width:650px;"></div>
</div>
<div id="tabs-3">
<p>This is the pie chart</p>
<div id="chart3" style="height:300px; width:650px;"></div>
</div>
</div>
图 16-1 显示了最终结果。
图 16-1。
A page with three tabs containing different charts
手风琴上的 jqPlot 图表
另一种常用的 jQuery 容器是 accordion。这一次你将把前三张图表放进手风琴里。web 页面中包含的插件列表与上一个示例中的一样。你需要在 CSS 样式上做一些改变;手风琴有特定的 CSS 类,需要指定它们的属性。它们如清单 16-7 所示。
清单 16-7。ch16_02.html
<style type="text/css">
.ui-accordion {
width: 690px;
margin: 2em auto;
}
.ui-accordion-header {
font-size: 12px;
}
.ui-accordion-content {
font-size: 14px;
}
.jqplot-target {
font-size: 18px;
}
ol.description {
list-style-position: inside;
font-size: 15px;
margin: 1.5em auto;
padding: 0 15px;
width: 600px;
}
.section {
width: 400px;
height: 200px;
margin-top: 20px;
margin-left: 20px;
}
</style>
正如您在前一个示例中所做的那样,您必须创建 jQueryUi 小部件。您可以通过调用accordion()函数来实现:
$("#accordion").accordion();
您还需要将这个 accordion 绑定到您的图表,如清单 16-8 所示。当您选择一个 accordion 选项卡时,该事件确保在其中重新绘制相应的图表,调用replot()函数。
清单 16-8。ch16_02.html
$('#accordion').bind('accordionchange', function(event, ui) {
var index = $(this).find("h3").index ( ui.newHeader[0] );
if (index === 0) {
plot1.replot();
}
else if (index === 1) {
plot2.replot();
}
else if (index === 2) {
plot3.replot();
}
});
如您所见,您定义手风琴的方式与您定义选项卡的方式非常相似。以同样的方式,您现在定义了将被转换成 HTML 代码中的折叠标签的<div>元素(见清单 16-9)。
清单 16-9。ch16_02.html
<div id="accordion" style="margin-top:50px">
<h3><a href="#">Section 1</a></h3>
<div>
<p>This is the bar chart</p>
<div class="section" id="chart1" data-height="200" data-width="400"></div>
</div>
<h3><a href="#">Section 2</a></h3>
<div>
<p>This is the multiseries line chart</p>
<div class="section" id="chart2" data-height="200" data-width="400"></div>
</div>
<h3><a href="#">Section 3</a></h3>
<div>
<p>This is the pie chart</p>
<div class="section" id="chart3" data-height="200" data-width="400"></div> </div>
</div>
在图 16-2 中可以看到,结果与上一个类似,但这次不同的图表是通过垂直滑动 accordion 选项卡来替换的。
图 16-2。
An accordion widget containing three charts
可调整大小和可拖动的图表
您可以在图表中广泛利用的另外两个功能允许用户调整和拖动容器区域。网页中可调整大小的框架允许您任意更改其大小及其包含的对象的大小。这个特性可以与在页面中拖动元素的能力相结合,这将使它们能够相对于原始元素占据不同的位置。
除了赋予页面布局流动性之外,当您希望用户交互地管理页面上不同框架所占据的空间时,该功能有时会很有用(参见图 16-3 )。
图 16-3。
Enclosing the charts in jQueryUI containers enables you to resize and move them around the page
在本节中,您将看到两个示例。在第一个示例中,您将关注应用于折线图的大小调整。您将看到调整包含在容器中的图表的大小是多么容易。在第二个示例中,您将通过添加两个折线图来进一步开发该示例。一旦所有三个图表都启用了 draggable 属性,您将看到如何根据自己的喜好更改它们的位置,甚至交换它们。
可调整大小的折线图
在本例中,您将使用一个简单的折线图。因此,除了 jQuery 容器和基本 jqPlots 库所需的插件之外,您不再需要包含所有的 jqPlot 插件:
<!--[if lt IE 9]>
<script type="text/javascript" src="../src/excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="../src/jquery.min.js"></script>
<script type="text/javascript" src="../src/jquery.jqplot.min.js"></script>
<link rel="stylesheet" type="text/css" href="../src/jquery.jqplot.min.css" />
<link rel="stylesheet" href="../src/css/smoothness/jquery-ui-1.10.3.custom.min.css" />
<script src="../src/js/jquery-ui-1.10.3.custom.min.js"></script>
或者,如果您喜欢使用内容交付网络(CDN)服务:
<!--[if lt IE 9]><script type="text/javascript" src="http://cdn.jsdelivr.net/excanvas/r3/excanvas.js
<script src="http://code.jquery.com/jquery-1.9.1.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.js
<link rel="stylesheet" type="text/css" href="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.css
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js
即使在这里也有必要指定一些 CSS 样式,如清单 16-10 所示。
清单 16-10。ch16_03.html
<style type="text/css">
.chart-container {
border: 1px solid darkblue;
padding: 30px 0px 30px 30px;
width: 900px;
height: 400px;
}
#chart1 {
width: 96%;
height: 96%;
}
</style>
在网页的<body>部分,你现在添加了<div>元素,它将是包含名为chart1的折线图的容器(见清单 16-11)。
清单 16-11。ch16_03.html
<div class="chart-container">
<div id="chart1"></div>
</div>
现在,在将chart-container定义为容器之后,可以用两个 jQuery 方法来处理它——resizable()函数添加了可调整大小的功能,而bind()函数将调整大小的事件绑定到图表的重新绘制上(参见清单 16-12)。
清单 16-12。ch16_03.html
$(document).ready(function(){
var plot1 = $.jqplot ('chart1', [[100, 110, 140, 130, 80, 75, 120, 130, 100]]);
$('div.chart-container').resizable({delay: 20});
$('div.chart-container').bind('resize', function(event, ui) {
plot1.replot();
});
});
结果是一个可调整大小的图表,如图 16-4 所示,在右下角有一个灰色的小三角形。通过点击它,用户可以调整容器的大小,从而调整 jqPlot 图表的大小。
图 16-4。
A resizable line chart
三个可拖动的折线图
从上一个示例开始,您将通过将折线图放在两个独立的容器中来添加两个折线图。这里的目标——除了使所有三个容器都可以调整大小之外——是使容器可以拖动。最终结果是一个包含三个折线图的网页,可以通过拖动它们来改变它们的位置,甚至交换它们的位置。
首先对前面的例子做一些小的补充。在清单 16-13 中,您添加了另外两个容器(chart-container2和chart-container3),里面有新的折线图,分别命名为chart2和chart3。
清单 16-13。ch16_03b.html
<BODY>
<div class="chart-container">
<div id="chart1"></div>
</div>
<div class="chart-container2">
<div id="chart2"></div>
</div>
<div class="chart-container3">
<div id="chart3"></div>
</div>
</BODY>
现在你已经为新的折线图创建了容器,有必要通过三个不同的$.jqplot()函数来定义它们(见清单 16-14)。这三个函数返回的值将被传递给三个变量:plot1、plot2和plot3。这是因为每当容器发生变化时,您需要通过对这三个变量使用replot()函数来重新绘制这三个图表。
清单 16-14。ch16_03b.html
$(document).ready(function(){
var plot1 = $.jqplot ('chart1', [[100, 110, 140, 130, 80, 75, 120, 130, 100]],
{seriesColors: [ "#bb0000" ]});
var plot2 = $.jqplot ('chart2', [[120, 90, 150, 120, 110, 75, 90, 120, 110]],
{seriesColors: [ "#00bb00" ]});
var plot3 = $.jqplot ('chart3', [[ 130, 110, 140, 100, 80, 135, 120, 90, 110]],
{seriesColors: [ "#0000bb" ]});
$('div.chart-container').resizable({delay:20});
...
});
现在,您将为这三个容器激活可拖动特性。做到这一点真的很简单;您需要将该函数添加到应用于每个容器的三个 jQuery 选项中,如清单 16-15 所示。此外,您将为两个新容器添加调整大小功能,其方式与第一个容器相同。
清单 16-15。ch16_03b.html
$(document).ready(function(){
...
var plot3 = $.jqplot ('chart3', [[130, 110, 140, 100, 80, 135, 120, 90, 110]],
{seriesColors: ["#0000bb"]});
$('div.chart-container').draggable({cursor: 'move'});
$('div.chart-container2').draggable({cursor: 'move'});
$('div.chart-container3').draggable({cursor: 'move'});
$('div.chart-container').resizable({delay: 20});
$('div.chart-container').bind('resize', function(event, ui) {
plot1.replot();
});
$('div.chart-container2').resizable({delay: 20});
$('div.chart-container2').bind('resize', function(event, ui) {
plot2.replot();
});
$('div.chart-container3').resizable({delay: 20});
$('div.chart-container3').bind('resize', function(event, ui) {
plot3.replot();
});
});
剩下的就是添加 CSS 样式,从而定义每个容器的初始位置和大小,如清单 16-16 所示。
清单 16-16。ch16_03b.html
<style type="text/css">
.chart-container {
border: 1px solid darkblue;
padding: 30px 0px 30px 30px;
width: 300px;
height: 200px;
position: relative;
float: left;
}
.chart-container2 {
border: 1px solid darkblue;
padding: 30px 0px 30px 30px;
width: 200px;
height: 200px;
position: relative;
float: left;
margin-left: 20px;
}
.chart-container3 {
border: 1px solid darkblue;
padding: 30px 0px 30px 30px;
width: 500px;
height: 200px;
position: relative;
float: left;
margin-left: 20px;
}
#chart1 {
width: 96%;
height: 96%;
}
#chart2 {
width: 96%;
height: 96%;
}
#chart3 {
width: 96%;
height: 96%;
}
</style>
在图 16-5 中,你可以看到页面初始加载时的页面布局。图 16-6 显示了用户改变了第三个图表的位置和大小,使其位于其他两个图表的下方。
图 16-6。
By dragging and resizing the containers, the original layout can be changed
图 16-5。
The web page shows the three line charts enclosed in three different containers
摘要
在本章中,您已经看到了如何利用 jQuery UI 库提供给您的小部件的潜力,这些小部件可以帮助您改进图表的表示方式。您已经看到了如何在容器中包含更多的图表,例如折叠和标签,以便您可以逐个查看它们,即使它们占据相同的区域。您还看到了如何调整这些容器的大小,将这种功能扩展到用 jqPlot 库开发的图表。
到目前为止,你已经加深了你的图表的图形和代表性方面。在下一章,你将学习图表的核心:数据管理。到目前为止,为了使示例更容易理解,页面中定义的数据种类是有限的。实际上,在包含代码管理图表的同一个网页上定义数据是不太可能的。更有可能的是,数据是由外部文件或数据库通过 SQL 查询提供的。