JavaScript 图表入门指南(一)

原文:Beginning JavaScript Charts

协议:CC BY-NC-SA 4.0

一、绘图技术概述

Abstract

当我们需要用图形来表示数据或定性结构,以显示关系,进行比较或突出趋势时,我们会使用图表。图表是由符号组成的图形结构,如折线图中的线条;条形图中的条形;或称切片。图表是有效的工具,可以帮助我们辨别和理解大量数据背后的关系。对于人类来说,阅读图形表示(如图表)比阅读原始数字数据更容易。如今,在各种各样的专业领域以及日常生活的许多其他方面,使用图表已经成为惯例。由于这个原因,根据数据的结构和突出显示的现象,图表有多种形式。例如,如果您将数据分成不同的组,并希望表示每个组相对于总数的百分比,则通常在饼图或条形图中显示这些数据组。相比之下,如果您想要显示一个变量随时间变化的趋势,折线图通常是最佳选择。

当我们需要用图形来表示数据或定性结构,以显示关系,进行比较或突出趋势时,我们会使用图表。图表是由符号组成的图形结构,如折线图中的线条;条形图中的条形;或称切片。图表是有效的工具,可以帮助我们辨别和理解大量数据背后的关系。对于人类来说,阅读图形表示(如图表)比阅读原始数字数据更容易。如今,在各种各样的专业领域以及日常生活的许多其他方面,使用图表已经成为惯例。由于这个原因,根据数据的结构和突出显示的现象,图表有多种形式。例如,如果您将数据分成不同的组,并希望表示每个组相对于总数的百分比,则通常在饼图或条形图中显示这些数据组。相比之下,如果您想要显示一个变量随时间变化的趋势,折线图通常是最佳选择。

在本书中,您将学习如何使用基于 JavaScript 的各种技术来创建、绘制图表,并根据您的需求调整图表。然而,在开始使用 JavaScript 开发图表之前,理解本书章节中涉及的基本概念是很重要的。在这一章中,我将提供这些概念的简要概述。

首先,我将向您展示如何识别构成图表的最常见元素。了解这些元素将会很有帮助,因为您会发现它们以组件、变量和对象的形式存在于专门为实现图表而创建的 JavaScript 库中。

接下来,我将列出最常见的图表类型。您对图表及其功能的了解越多,就越容易为您的数据选择正确的表示方式。如果你要强调你想要表现的关系,做出正确的选择是很重要的,仅仅阅读数据是不够的。只有当你熟悉了最常见的图表类型,你才能选择最适合你的目的的图表。

一旦你熟悉了这些概念,你将需要学习如何通过网络实现它们,以及当前有哪些技术可以帮助你实现这个目标。因此,在这一章的第二部分,我将讨论这些技术方面,逐一介绍本书中提供的例子的开发中所涉及的技术。

最后,鉴于我们所有的工作都将集中在 JavaScript 代码的开发上,我认为对某些类型的数据提供一个简要的描述会有所帮助。那些不熟悉 JavaScript 的人可以从这个关于代码中数据形式的快速参考资料中受益。然而,我强烈建议读者更深入地研究本章中讨论的概念和技术。

图表中的元素

您很快就会看到,图表可以呈现多种形式。在图表中,通过使用特定于图表类型的符号,数据呈现出图形结构;但是,有一些特性是所有图表共有的。

通常,每个图表都有一个标题,显示在顶部,提供数据的简短描述。不太常见的是,副标题或脚注用于提供额外的描述(主要是与数据相关的信息,如参考文献、地点、日期和注释)。

图表通常有轴——两条垂直线,允许用户引用每个数据点 P(x,y)的坐标值(x,y),如图 1-1 所示。水平线通常代表 x 轴,垂直线代表 y 轴。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1。

A two-dimensional chart

每个轴上都定义了一个刻度。尺度可以是数字的,也可以是分类的。每个轴被分成对应于刻度所代表的特定值范围的段。一个线段和下一个线段之间的边界称为记号。每个分笔成交点报告与该轴相关的刻度值。一般来说,称这些为刻度标签。

图 1-2 显示了四个不同比例的轴。轴 a 和 b 有数字刻度,a 是线性刻度,b 是对数刻度。轴 c 和 d 具有分类标度,c 是序数,因此遵循升序,而 d 只是没有任何特定顺序的类别序列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2。

Four axes with different scales

沿着每个轴,最好显示一个标签,简要描述所表示的尺寸;这些被称为轴标签。如果刻度是数字,标签应该在括号中显示测量单位。例如,如果你有一个 x 轴来报告一组数据的时间,你可以把“时间”写成一个轴标签,第二个单位(在这种情况下是秒)用方括号表示为 s )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3。

An axis label

在显示图表的绘图区域中,可以包括线网格以帮助数据的可视化对齐。图 1-4 显示了一个图表网格,x 轴为线性时间刻度,y 轴为对数刻度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4。

A chart with two different scales

您已经看到了数据是如何用符号表示的。但是,文本标签也可以用来突出显示特定的数据点。点标签在图表中的相应点处提供图表中的值,而工具提示是当鼠标经过给定点时动态显示的小框架。这两种标签如图 1-5 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5。

The point label and the tooltip of a data point

数据通常被分组到几个系列中,为了在同一个图表中表示这些数据,它们必须是可区分的。最常见的方法是为每个系列分配不同的颜色。在其他情况下,例如,对于折线图,线条(虚线、点线等)也可用于区分不同的系列。一旦建立了颜色(或笔画)序列,就有必要添加一个表格来演示颜色和组之间的对应关系。该表被称为图例,如图 1-6 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-6。

A legend

虽然讨论这一部分中的概念可能显得琐碎,但是定义我将在整本书中引用的元素的术语是很重要的。它们构成了构建图表的基础。您还将看到专门研究图表表示的 JavaScript 库如何使用这些术语,将它们与编辑和设置组件相关联(参见第八章中的“插入选项”一节)。

最常见的图表

本节包含最常见图表类型的简要概述。这些图表将在本书的后续章节中详细描述。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-10。

A candlestick chart

  • 蜡烛图:一种专门用于描述价格趋势的图表。每个数据点由四个值组成,通常称为开盘-盘高-盘低-收盘(OHLC)值,并呈现类似烛台的形状(见图 1-10 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-9。

A bubble chart and a radar chart

  • 气泡图:一个二维散点图,其中第三个变量由数据点的大小表示(见图 1-9 )。
  • 雷达图:一种图表,其中一系列数据表示在许多轴上,从图表中心的原点开始呈放射状。这张图表通常呈现蜘蛛网的外观(见图 1-9 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-8。

A line chart and a pie chart

  • 折线图:由线条连接的有序数据点序列。数据点 P(x,y)在图表中报告,代表 x 和 y 两个轴的刻度(见图 1-8 )。
  • 饼图:一个被分成若干段(片)的圆(饼)。每个切片代表一组数据,其大小与百分比值成正比(见图 1-8 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-7。

A histogram and a bar chart

  • 直方图:竖立在 x 轴上的相邻矩形,分成离散的间隔(区间),其面积与该区间的观察频率成比例(见图 1-7 )。
  • 条形图:形状类似于直方图,但本质不同,这是一种矩形条的长度与它们所代表的值成比例的图表。每个条形标识一组数据(见图 1-7 )。

Note

开盘-盘高-盘低-收盘(OHLC)是四个数值,通常用于说明金融工具价格随时间的变化。

如何在 Web 上实现图表

现在,我已经描述了最常见的图表类型和组成它们的元素,下一步是快速浏览一下今天可用的技术,这些技术将允许您实现您的图表。

如今,web 技术处于不断的变化之中:每天都有新的解决方案被提出,解决不久前还被证明非常复杂的问题。这些创新将为您提供实现具有引人注目的图形的高度交互式图表的可能性,所有这些都只需编写几行 JavaScript 代码。整个事情可以快速而容易地完成,因为大部分工作已经由 JavaScript 库为您完成,这些库在图表表示方面非常专业。这些库现在遍布网络。

在本书中,您将使用 jqPlot、Highcharts 和 D3,它们是目前使用最广泛的库,可以为图表实现过程中可能出现的几乎任何问题提供通用解决方案。

但是,在逐一浏览这些库之前(您将在后面的章节中完成),您必须首先调查构成 JavaScript 图表开发基础的所有技术,因为这些技术将伴随您阅读本书的其余部分。

HTML5

最近,有很多关于 HTML5 的讨论,它实际上彻底改变了 web 应用的开发方式。在它出现之前,如果你想引入交互式图形内容,使用 Adobe Flash 等应用几乎是必经之路。但是,使用 Flash 或类似的应用在网上开发图表或其他图形表示有一个明显的限制:依赖于安装在最终用户机器上的插件。此外,智能手机不支持这类应用。由于 HTML5,开发人员现在可以创建高级图形和动画,而不依赖于 Flash。

当你通读这本书时,你会看到 HTML5 是如何导致许多其他技术的诞生的,有些是新的,有些是旧的,但又是更新的,比如 JavaScript。事实上,作为一种语言,JavaScript 正在经历重生,这是由于新库的开发利用了 HTML5 引入的创新。HTML5 有许多新的语法特性,包括

元素和标量矢量图形(SVG)内容的集成。由于这些元素,在不使用 Flash 的情况下,在 Web 上集成多媒体和图形内容将非常容易。

在 Flash 的位置上,您将使用 JavaScript 库,如 jQuery、jqPlot、Highcharts 和 D3。目前,这些是可用于实现任务(如数据的图形可视化)的最广泛和最完整的库。然而,网络技术的世界在不断发展;在互联网上,你总是可以找到新的图书馆,其特征与本书所包含的特征相似。

用 SVG 和画布制作图表

在 HTML5 引入的新技术可以实现的所有可能的图形应用中,我将重点介绍通过图表表示和可视化数据。使用 JavaScript 作为编程语言,我们现在可以利用新浏览器中嵌入的强大渲染引擎。作为这种语言新功能的基础,我将参考 HTML5 canvas 和 SVG。SVG 和 canvas 不是在服务器上绘制静态图像,然后将它们下载到浏览器中,而是允许您开发完全交互式的图表,从而通过内置的动画、过渡和工具提示来丰富您的图形表示。这是因为 SVG 和 canvas 内容是在浏览器中绘制的,所以组成图表的图形元素可以在不刷新页面的情况下进行转换。该功能对于可视化实时数据至关重要,因为实时数据要求图表随着数据的变化而不断更新。以这种方式操作将确保真正的客户端图表。事实上,通过利用这些技术,图表实际上是在客户机上绘制的,只需要从服务器传递数据。这个方面提供了相当多的优点,最重要的是消除了从服务器下载大图形文件的需要。

Canvas vs SVG 的应用

HTML5 canvas 和 SVG 都是允许您在浏览器中创建丰富图形的 web 技术,但它们是根本不同的。贯穿本文,您将主要看到两个 JavaScript 框架:jqPlot 和 D3。基于 jQuery 框架的 jqPlot 利用 HTML5

元素来绘制图表。相比之下,D3 没有利用 canvas 它依赖 SVG 技术进行图形表示。

SVG 是一种基于 XML 的矢量图形格式。SVG 内容可以是静态的、动态的、交互式的或动画的,这使得它非常灵活。您还可以使用层叠样式表(CSS)来设置 SVG 元素的样式,并使用 SVG 文档对象模型(DOM)提供的应用编程接口(API)方法向它们添加动态行为。因此,选择这种格式,您可以获得比简单的矢量图形和动画更多的东西:您可以开发高度交互式的 web 应用,包括脚本、高级动画、事件、过滤器和几乎任何您想象得到的东西。

HTML5 canvas 规范是一个通用的 JavaScript API,允许您编写编程绘制操作。Canvas 本身允许您定义一个 canvas 上下文对象,在 HTML 页面上显示为一个

元素。然后,可以通过网络图形库(WebGL)使用二维或三维绘图环境在内部绘制该元素。我将只讨论第一种选择;jqPlot 使用二维绘图上下文。二维上下文为您提供了一个强大的 API,可以在位图表面(画布)上执行快速绘制操作。与 SVG 不同,形状没有 DOM 节点,只有像素。

与 SVG 相比,canvas 的优点是绘图性能高,图形和图像编辑速度更快。每当需要在像素级别工作时,canvas 是更好的选择。然而,对于 canvas,没有 DOM 节点是一个缺点,尤其是如果您不使用 JavaScript 框架,比如 jqPlot。另一个缺点是文本呈现能力差。

与 canvas 相比,SVG 的优势在于分辨率独立性、对动画的良好支持,以及使用声明性语法来激活元素的能力。不过,最重要的是,使用 JavaScript 中的 SVG DOM API 完全控制每个元素。然而,当复杂性增加时,缓慢的渲染可能是一个问题,但浏览器提供商正在努力使浏览器更快(见表 1-1 和 1-2 )。

表 1-1。

Web Browsers and Engines

| 浏览器 | 目前的 | 发动机 | 开发者 | 许可证 | | --- | --- | --- | --- | --- | | 谷歌 Chrome | Twenty-nine | 眨眼 | 谷歌,Opera,三星,英特尔,其他 | GNU 宽松通用公共许可证(LGPL),Berkeley 软件分发(BSD)风格 | | Mozilla Firefox | Twenty-three | 壁虎 | 网景/Mozilla 基金会 | Mozilla 公共许可证(MPL) | | 微软公司出品的 web 浏览器 | Ten | 三叉戟 | 微软 | 所有人 | | 苹果浏览器 | six | 网络工具包 | 苹果,KDE,诺基亚,黑莓,Palm,其他 | GNU lgpl BSD 样式 |

表 1-2。

Web Technology Support: Comparison of Web Browsers

|   | 浏览器 | | --- | --- | | 技术 | Internet Explorer 10 | 铬 29 | 火狐 23 | 野生动物园 6 | | --- | --- | --- | --- | --- | | SVG(五)。1.1) |   |   |   |   | | 过滤 | 是(从 10 开始) | 是 | 是 | 是(从 6 开始) | | 同步多媒体集成语言(SMIL)动画 | 不 | 是 | 是 | 部分的 | | 字体 | 不 | 是 | 不 | 是 | | 片段标识符 | 是 | 不 | 是 | 不 | | HTML 效果 | 部分的 | 部分的 | 是 | 部分的 | | css 背景 | 是 | 是 | 部分的 | 是 | | 半铸钢ˌ钢性铸铁(Cast Semi-Steel) | 是 | 是 | 是 | 是 | | HTML5 |   |   |   |   | | 帆布 | 是(从 9 点开始) | 是 | 是 | 是 | | 新元素 | 是 | 是 | 是 | 是 | | 视频元素 | 是(从 9 点开始) | 是 | 是 | 是 | | 百度地图 |   |   |   |   | | JavaScript 对象符号(JSON)解析 | 是 | 是 | 是 | 是 | | web GL(web GL) | 不 | 是 | 部分的 | 部分的 |

使用在 HTML 页面结构元素层次上工作的库,我们不能避免谈论 DOM。我会经常提到这个概念,因为它是每个网页的基本结构。万维网联盟(W3C)认为有必要为结构化文档的表示创建一个官方标准,以便为所有编程语言和平台开发指导原则,这是正确的。HTML 文档的树结构,以及 XML 文档的树结构,完全遵循了这个标准开发的指导原则。以下是一个 HTML 文档的示例:

<HTML>

<HEAD>

<TITLE>A title</TITLE>

</HEAD>

<BODY>

Hello

<BR>

</BODY>

</HTML>

该文档的 DOM 树可以表示为如图 1-11 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-11。

An example of tree structure of the DOM

但是,DOM 标准并不局限于开发如何在文档中构造 DOM 的指南;该标准还定义了许多功能,用于处理组成文档的元素。因此,任何与文档相关的操作(创建、插入、删除)都应该遵循 DOM 标准。因此,不管您使用的是哪种编程语言,也不管您使用的是哪种平台,您都会发现这个标准表达了相同的功能。通常,术语 DOM 也适用于 API,它管理网页的所有元素。

所有这些都很重要,因为任何选择阅读这本书的人都对开发不仅使用 DOM,而且也是 DOM 的一部分的图表感兴趣,这些图表的每个方面都可以用 JavaScript 检查和操作。在整本书中,您将学习如何最好地利用 jQuery、jqPlot 和 Highcharts (jQuery 扩展)以及 D3 库。使用这些 JavaScript 库,您可以访问每个图表元素,比如更改对象的颜色和位置。

用 JavaScript 开发

尽管大多数选择阅读本书的人可能已经对 JavaScript 有了很好的了解,但事实上可能并非如此。出于这个原因,我以实用的方式组织了这本书,给出了一步一步的例子,并提供了例子中必须编写的所有代码。因此,这本书为新来者提供了一个学习这门语言的机会,也为那些已经有一段时间没有使用这门语言的人提供了一个刷新记忆的机会。

要开始使用将用于开发图表的 JavaScript 库,有必要准备一个开发环境。的确,要开发 JavaScript 代码,您可以简单地使用文本编辑器,比如 Notepad(或者更好的 Notepad++ ),但是开发人员通常更喜欢使用专门的应用(通常称为集成开发环境(ide ))来开发代码。除了为文本编辑器提供与代码中使用的关键字相对应的不同颜色之外,此类应用还包含一组旨在简化工作的工具。这些应用可以检查代码中是否有任何错误,提供调试工具,使管理文件变得容易,并帮助在服务器上部署,以及许多其他操作。

现在网络上有很多 JavaScript IDEs,但最突出的还是 Aptana Studio(见图 1-12);Eclipse Web Developer,安装了 JavaScript 测试驱动程序(JSTD)插件;和 NetBeans。这些编辑器还允许您开发超文本预处理器(PHP)、CSS 和 HTML(有关如何使用 Aptana Studio IDE 建立工作区以实现本书代码的信息,请参见附录 A,或者直接使用本书附带的源代码;您可以在 Apress 网站[ www.apress.com/9781430262893 ]的源代码/下载区找到代码示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-12。

The Aptana Studio 3 IDE

对于那些不喜欢在计算机上安装太多应用的人,有在线 JavaScript IDEs。这些允许用户在作为 IDE 工作的网页中编辑 JavaScript 代码,并直接从同一个网页中检查结果。不幸的是,许多 ide 都要收费。然而,jsFiddle ( http://jsfiddle.net )是一个不需要付费的在线 IDE,除了编辑之外,它还提供代码共享和添加库的选项,比如 jQuery 和 D3。(参见图 1-13 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-13。

The online IDE jsFiddle

jsFiddle 可以证明非常有用。除了让用户包含许多 JavaScript 库(见图 1-14 )之外,它还提供各自不同的发布版本,从而允许用户实时测试任何不兼容性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-14。

jsFiddle offers a set of the most popular JavaScript libraries

运行和调试 JavaScript

如果我们想在客户机-服务器框架中定义 JavaScript,它是一种完全的客户端编程语言。它不需要编译,除了 HTML 文档之外,部分代码可以在其他语言特有的许多其他类型的文件中找到,例如。JSP 或. PHP。

这些代码片段不受影响地通过应用服务器,从未被处理过。只有浏览器负责运行 JavaScript 代码。因此,JavaScript 代码仅在下载网页时或之后运行,以响应事件。如果 JavaScript 代码相当大或者以后可能有用,可以在. JS 文件中外部定义它;在这里,您可以找到本文中提到的所有 JavaScript 库和框架。然而,不管其形式如何,JavaScript 都是直接从浏览器运行的。

因此,即使您没有使用真正的 IDE 来开发和调试 JavaScript 代码,您也可以简单地将代码插入到一个空的 HTML 文件中,然后直接在浏览器中加载该文件(Chrome、Internet Explorer 和 Firefox 是最常见的)。为了将它与页面上的其他文本区分开来,您必须将代码放在

<script type="text/javascript">

// JavaScript code

</script>

如果 JavaScript 代码驻留在一个外部文件中,那么有必要将它包含在 HTML 页面中,编写

<script type="text/javascript" src="library.js"></script>

因此,只要 JavaScript 的执行不是出于安装某个东西的目的,您就拥有了所需的一切。谁的操作系统上没有 web 浏览器?

JavaScript 中的数据类型

如前所述,本书既不会解释优秀 JavaScript 代码编程的规则和语法,也不会在编程细节上停留太久。然而,我们将要开发的代码是以图表为中心的,或者说是数据的处理以及如何显示它们。让我们从最简单的例子开始。所有数据结构的最小构造块是变量(当它包含单个值时)。在处理数据类型方面,JavaScript 与其他编程语言有很大不同。,当您希望将 JavaScript 存储在变量中时,您不必指定值的类型(int、string、float、boolean 等);你只需要用关键字var来定义它。

在 Java 或 C 中,包含整数值的变量与包含文本的变量的声明不同:

int value = 3;

String text = "This is a string value";

在 JavaScript 中,存储值的类型无关紧要。所有东西都用var声明,所以相同的声明是

var value = 3;

var text = "This is a string value";

因此,在 JavaScript 中,我们可以将变量视为存储任何类型值的容器。

为了简单起见,这里的变量被视为单个值的容器,因此代表了最简单的数据结构。然而,实际上,变量也可能包含更复杂的数据类型:数组和对象。

Note

JavaScript 中变量的使用实际上要复杂一些。你也可以不用关键字var来声明变量。var关键字将在当前范围内声明变量。如果缺少var, JavaScript 将搜索在更高级别的作用域中声明的同名变量。如果 JavaScript 没有找到这个变量,则声明一个新变量;否则,JavaScript 将使用值in the variable found. As a result, an incorrect use of variables can sometimes lead to errors that are difficult to detect.

数组

数组是由逗号分隔并括在方括号[ ]中的一系列值:

var array = [ 1, 6, 3, 8, 2, 4 ];

数组是 JavaScript 中最简单也是最广泛使用的数据结构,所以您应该对它们非常熟悉。通过在括号中指定它的索引(在数组中的位置),可以访问数组中的任何值,紧跟着数组的名称。在 JavaScript 中,索引从 0:

array[3]  //returns 8

数组可以包含任何类型的数据,而不仅仅是整数:

var fruits = [ "banana", "apple", "peach" ];

有许多函数可以帮助我们处理这类对象。由于它的有用性,我将在整本书中频繁使用这个对象,因此快速浏览一下它似乎是合适的。

通过书写可以知道数组中值的数量

fruits.length  //returns 3

或者,如果您知道这些值,您可以使用

fruits.indexOf("apple") //returns 1

此外,有一组函数允许我们在数组中添加和删除项目。push()和 pop()函数添加和移除数组中的最后一个元素,而 shift()和 unshift()函数添加和移除数组中的第一个元素:

fruits.push("strawberry");

// Now the array is [ "banana", "apple", "peach", "strawberry" ];

fruits.pop(); //returns "strawberry"

// Now the array is [ "banana", "apple", "peach"];

fruits.unshift("orange", "pear");

// Now the array is ["orange", "pear", "banana", "apple", "peach"];

fruits.shift();   //returns "orange"

// Now the array is ["pear", "banana", "apple", "peach"];

有时,有必要对数组中的每个值进行循环,以便对其执行某些操作。在其他编程语言中广泛使用的一种方法是使用函数for()。例如,要计算数组中值的总和,您应该编写

var sum = 0;

for (var i = 0; i < array.length; i++) {

sum += array[i];

}

但是,在 JavaScript 中更常见的是使用forEach()函数,其中 d 按照以下顺序一个接一个地假定数组中的值:

var sum = 0;

array.forEach(function(d) {

sum += d;

});

目标

数组对于简单的值列表很有用,但是如果你想要结构化的数据,你需要定义一个对象。对象是一种自定义数据结构,其属性和值由您定义。您可以通过将对象的属性括在两个大括号{ }中来定义对象;每个属性都由一个名称定义,后跟一个冒号(:)和分配的值,每个属性/值对之间用逗号分隔:

var animal = {

species: "lion",

class: "mammalia",

order: "carnivora",

extinct: false,

number: 123456

};

在 JavaScript 代码中,点符号表示每个值,指定属性的名称:

animal.species      //Returns "lion"

现在,您已经了解了对象和数组,您可以看到如何将它们结合起来,以便在 JavaScript 中获得更复杂的数据结构。您可以创建对象的数组或数组的对象,甚至对象的对象。方括号用来表示一个数组,花括号,一个对象。例如,让我们以这种方式定义一个对象数组:

var animals = [

{

species: "lion",

class: "mammalia",

order: "carnivora",

extinct: false,

number: 123456

},

{

species: "gorilla",

class: "mammalia",

order: "primates",

extinct: false,

number: 555234

},

{

species: "octopus",

class: "cephalopoda",

order: "octopoda",

extinct: false,

number: 333421

}

];

要获得这些数据结构的值,您需要将方括号与属性的索引和名称一起使用:

animals[0].extinct  //return false

animals[2].species //return "octopus"

Firebug 和 DevTools

为了进行调试,如果您使用的是 IDE,可以很容易地利用它附带的各种调试工具。但是,如果您无法访问 IDE,您仍然可以利用外部工具。可以把浏览器想象成一个开发环境,在这里调试工具可以通过可从互联网下载的插件来集成。目前互联网上有很多可用的工具,但我想推荐的是 Firebug,这是一款针对那些喜欢使用浏览器 Mozilla Firefox 的 web 开发工具。Firebug 是一个无缝集成到 Firefox 浏览器中的插件,如图 1-15 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-15。

Firebug is an extention of Mozilla Firefox and is fully integrated into the browser

Firebug 将被证明是一个非常有用的工具,尤其是在使用 jQuery 和 D3 库时,这些库要求 DOM 的结构始终处于控制之下。这个工具将允许你直接监控 DOM 的结构。

然而,对于那些更喜欢使用谷歌 Chrome 的人来说,还有已经集成到浏览器中的 DevTools(见图 1-16 )。要访问该工具,只需单击浏览器右上角的按钮。

接下来,选择工具➤开发人员工具,或者只需右键单击任何页面元素,然后在上下文菜单中选择检查元素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-16。

With DevTools it is possible to monitor a lot of information about your web page

有了这两个工具,您不仅可以轻松地检查 DOM 的每个元素——它的属性和值——还可以检查应用于它们的 CSS 样式。您还可以输入对这些值的更改来实时观察效果,而不必每次都修改文件中的代码并保存它。Firebug 和 DevTools 还包括各种工具,用于监控页面的性能,包括渲染和联网。

对于 DevTools,还应该特别注意控制台的使用。通过它,您可以使用诸如console.log()之类的方法来访问诊断信息。此方法经常用于通过控制台显示许多变量的值,将变量的名称作为参数传递,并添加文本作为指示:

var x = 3;

console.log("The value of x is " + x); // The value of x is 3

还可以使用诸如$()profile()的方法输入命令并与文档进行交互。有关这些方法的更多信息,请参见关于控制台 API ( https://developers.google.com/chrome-developer-tools/docs/console-api )和命令行 API ( https://developers.google.com/chrome-developer-tools/docs/commandline-api )的文档。

数据

JSON 是一种将数据组织成 JavaScript 对象的特定语法。这种格式通常用于基于浏览器的代码,尤其是 JavaScript。JSON 代表了组织数据的 XML 的有效替代方案。两者都独立于编程语言,但是 JSON 比 XML 更快,更容易用 JavaScript 解析,XML 是一种全标记语言。而且 jqPlot 和 D3 和 JSON 配合的很好。它的结构完全遵循 JavaScript 中定义的对象和数组的规则:

var company = {

"name": "Elusive Dinamics",

"location": "France",

"sites": 2,

"employees": 234,

"updated": true

};

摘要

这第一章已经向你介绍了许多基本概念,它们将伴随你阅读整本书。首先,您研究了最常见的图表类型以及组成它们的元素。您还快速浏览了在着手开发 Web 图表时需要了解的许多技术方面。最后,您简要探讨了本书中 JavaScript 示例中使用的数据类型。

我提到过你的大部分工作将由专门的 JavaScript 库来完成。在下一章,你将学习 jQuery 库。这个库将为您提供一整套直接作用于 DOM 级别的工具。在本书的后面,你会发现关于这个库的知识是至关重要的:许多图形库(包括 jqPlot 和 Highcharts)都是基于它构建的。

二、jQuery 基础知识

Abstract

在前一章中,您了解了 DOM 树,看到了 HTML 文档是如何由许多可以在初始上下文中创建、修改和删除的元素组成的。这些操作由浏览器通过 JavaScript 命令来执行,如前所述,这些命令可以在页面加载时执行,也可以作为后续事件的结果来执行。为此,开发了一个 JavaScript 库,它以一种简单且成熟的方式管理所有这些操作。这个库就是 jQuery,而且是完全开源的。它由 Jon Resig 于 2006 年创建,并由一个开发团队继续改进。与经典 JavaScript 相比,jQuery 非常有用,而且能够操作 DOM 元素,因此它是目前使用最广泛的 JavaScript 库,是所有 web 开发人员的参考点。

在前一章中,您了解了 DOM 树,看到了 HTML 文档是如何由许多可以在初始上下文中创建、修改和删除的元素组成的。这些操作由浏览器通过 JavaScript 命令来执行,如前所述,这些命令可以在页面加载时执行,也可以作为后续事件的结果来执行。为此,开发了一个 JavaScript 库,它以一种简单且成熟的方式管理所有这些操作。这个库就是 jQuery,而且是完全开源的。它由 Jon Resig 于 2006 年创建,并由一个开发团队继续改进。与经典 JavaScript 相比,jQuery 非常有用,而且能够操作 DOM 元素,因此它是目前使用最广泛的 JavaScript 库,是所有 web 开发人员的参考点。

任何计划在网页中包含 jQuery 库的开发人员都会很快发现伴随这个 UI 库的著名格言:“写得少,做得多。”本着这一口号的精神,jQuery 在 JavaScript 代码开发中引入了三个新概念——在使用 thisUI 库提供的方法时,您需要记住这些概念:

  • 通过级联样式表(CSS)选择器选择要应用 jQuery 方法的 HTML 页面元素(选择)
  • 构建 jQuery 方法链,在同一选择中按顺序应用
  • 使用 jQuery 包装器进行隐式迭代

在本章中,在了解了如何在将要开发的网页中包含 jQuery 库之后,将介绍“选择”的概念。选择是 jQuery 库的基础,理解它们以及如何实现它们非常重要,因为它们将在整本书中讨论。通过一系列小示例并使用链接方法的技术,您将浏览 jQuery 库提供的一系列函数,这些函数允许您操作选择,以便创建、隐藏和更改各种 DOM 元素及其内容。在本章的最后一部分,我将介绍 jQuery 用户界面库(jQuery UI ),并举例说明一些最常见的小部件。您将了解它们的基本功能,并发现如何将它们整合到网页中。

本章的目的是提供一个 jQuery 的快速视图——它的功能和基本概念。对每种方法的详细描述超出了本书的范围。在本文的所有例子中,这些方法将根据上下文来解释。但是,您可能还想参考 jQuery 官方网站上的文档( http://jquery.com/ )。

包括 jQuery 库

现在,有两种方法可以将 jQuery 库包含在您的 web 页面中。

  • 本地方法:在本地下载必要的库,然后添加到网页中。
  • CDN 方法:直接设置链接到提供这些 JavaScript 库的站点。

提供这些库的网站被称为内容交付网络(cdn)。CDN 是一个大型服务器系统,为最终用户提供高可用性和高性能的内容。当用户试图访问文件时,CDN 会选择离用户最近的服务器。最常用的 cdn 之一是谷歌托管图书馆。该服务为 web 应用提供了对许多最流行的开源 JavaScript 库(如 jQuery)的可靠访问。

要从此服务加载库,您需要复制以下 HTML 代码片段,并将其直接粘贴到您的网页中:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js

</script>

另一个可以获得任何版本 jQuery 库的 CDN 站点是 jQuery 本身的官方 CDN 站点: code.jquery.com 。如果您更喜欢使用该网站的 URL,您需要复制并粘贴以下 HTML 片段:

<script src="http://code.jquery.com/jquery-1.9.1.min.js

Note

本章中的所有例子都使用 1.9.1 版的 jQuery 库。

如果选择本地选项,则需要复制并粘贴 jQuery 库的相对路径。该路径会有所不同,具体取决于库在 web 服务器或 PC 上的位置。创建一个适当的本地目录来加载您需要包含的所有库是一个很好的做法。

例如,您可能决定将您的 jQuery 库放在一个src目录中,而将您正在开发的 web 页面放在一个charts目录中,如图 2-1 所示。在这种情况下,您必须使用这个相对路径:

<script src="../src/js/jquery-1.9.1.js"></script>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-1。

An example of how a directory might be organized on a web server Note

有关如何在 web 服务器或 PC 上设置工作区以开发本书中的示例的详细信息,请参见附录 a。您还可以找到关于不同版本的库、如何下载它们以及如何将它们包含在工作区中的信息。

选择

选择是为了以某种方式操作而选择的一组 HTML 元素。实际上,这是 jQuery 背后的主要概念。让我们以清单 2-1 中的简单 HTML 页面为例:

清单 2-1。ch2_01a.html

<HTML>

<HEAD>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js

</HEAD>

<BODY>

<div> This is the first text</div>

<div class="selected"> This is the second text</div>

<div> This is the last text</div>

</BODY>

</HTML>

在此页面中,有三个元素包含三种不同的文本。列表中的第二个元素已经用类名‘selected’标记。要选择所有三个元素,您可以使用选择器‘div’,它可以在页面上的所有元素中识别它们。

接下来,编写jQuery()函数,将选择器作为参数传递。这样,您就已经选择了三个元素及其内容。要获取文本,您可以使用函数text(),将它链接到jQuery()函数调用,并在该部分的末尾添加这一行,如清单 2-2 所示。

清单 2-2。ch2_01a.html

<script>

var text = jQuery('div').text();

console.log(text);

</script>

这三个元素中包含的所有文本都被赋给了变量 text。要查看其内容(在调试中非常有用),可以使用函数console.log(),然后在 Google Chrome 上,直接右键点击页面选择 Inspect element(见图 2-2 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-2。

变量 text 包含三个< div >元素中的文本

根据您选择的频率,您也可以用$()调用这个函数,如清单 2-3 所示。我们将在本书提供的例子中使用这个选项。

清单 2-3。ch2_01b.html

<script>

var text = $('div').text();

console.log(text);

</script>

相反,如果你只想选择三个元素中的一个,你可以通过给每个元素分配一个类名来区分它们,然后将选择器应用于所选元素的名称,而不是标签元素(清单 2-4)。

清单 2-4。ch2_01c.html

<script>

var text = $('.selected').text();

console.log(text);

</script>

在这种情况下,变量 text 只包含第二个元素的文本,如图 2-3 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-3。

Google Chrome 浏览器中 Inspect 元素显示的文本变量的内容

一旦您理解了如何进行选择,您将会发现如何通过改变其内容或属性来操作任何元素。您甚至可以添加其他元素或从页面中删除一个元素。在这方面,由于 jQuery 提供了大量的方法,它为我们提供了必要的工具。

链接方法

jQuery 被设计成允许 jQuery 方法被链接。一旦选择了一个元素或一组元素,下一步就是对它应用一系列方法。这个序列可以用链接来写。

使用前面的例子(见清单 2-1),假设您想用另一个短语替换第二个元素中的文本,并隐藏另外两个元素,使它们不再出现在网页中。为此,您将把“这是第二个文本”替换为一个新行,“这是一个新文本”,同时隐藏其他文本。图 2-4 显示了应用任何更改之前出现的内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-4。

不使用 jQuery 方法链的网页显示的文本

现在,您应用以下方法链:

$('div').hide().filter('.selected').text('This is a new text').show();

这三个元素都包含在选择中,然后被隐藏。在您选择的选项中,只有类名为’selected’的元素及其内容会被替换为新文本。只有最后这些元素必须显示。因此,在这个命令链的末尾,结果将是外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

包装套件

当涉及到 jQuery 时,我们处理包装器集。在前面的例子中,有三个元素。您通常会选择包含几个元素的选项,但您永远不需要指定编程循环。这里,当您应用hide()方法来隐藏所有三个元素时,您没有使用forwhile构造(即$(‘div’).each(function() {})。因此,包装集可以被定义为一组可以进行任何操作的元素(选择),就像它是单个项目一样。

jQuery 和 DOM

jQuery 是一个主要在文档对象模型(DOM)上工作的库,并且总是引用它的所有特性。与 DOM 一样,jQuery 将每个 web 页面视为一个树形结构,其中每个标签(也称为元素)都是一个节点。这个树的根是文档,文档是包含 DOM 所有其他元素的元素。jQuery 提供了一组简化这种对象操作的方法,允许您为页面添加动态性。

ready()方法

如果您想编写一个操纵 DOM 元素的 JavaScript 代码,那么在对 DOM 进行操作之前,需要加载 DOM。但是,您需要在浏览器完全加载所有资产之前进行操作。为此,jQuery 为您提供了ready()方法。这是一个自定义事件处理程序,绑定到文档对象的 DOM。ready()方法只有一个参数:一个包含代码的函数,这个函数应该在 DOM 加载之后、用户可以在浏览器中看到所有资源之前执行。

$(document).ready( function() {

// we write the JavaScript code here.

});

用选择遍历 DOM

您已经看到了如何选择一组 DOM 元素,使用特定的 CSS 选择器作为标识它们的参数传递。然而,jQuery 的潜力并不止于此;从 DOM 中的选择位置开始,可以遍历 DOM 以获得一组新的要操作的选择元素。jQuery 为我们提供了一组应用于选择的方法。

让我们以清单 2-5 中的简单 HTML 代码为例:

清单 2-5。ch2_03a.html

<HTML>

<HEAD>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js

</HEAD>

<BODY>

<div class="fruits">

<div>Apple</div>

<div>Orange</div>

<div>Banana</div>

<div>Strawberry</div>

</div>

</BODY>

</HTML>

该页面将显示四种水果的列表。正如您已经看到的,如果您使用‘div’作为选择器进行选择,您将得到五个元素的序列:

<div class="fruits">

<div>Apple</div>

<div>Orange</div>

<div>Banana</div>

<div>Strawberry</div>

</div>

<div>Apple</div>

<div>Orange</div>

<div>Banana</div>

<div>Strawberry</div>

你需要特别注意第一个要素。您将在选择中找到其他四种水果,尽管它们将在连续的元素中重复出现。这是因为选择器‘div’选择每个元素及其内容,而不管其中的元素是否会被依次选择。当你想对这种类型的选择进行进一步的操作时,考虑到这一点是很重要的。

现在,如果您编写清单 2-6 中的代码片段,您会在一个警告对话框中得到文本,如图 2-5 所示。,您可以看到最后一行中的文本包括所有水果。

清单 2-6。ch2_03a.html

<script>

var text = $('div').text();

alert(text);

</script>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-5。

The alert dialog box shows the text contained within the elements of the selection

但是,通常您需要直接访问选择的特定值。例如,要直接访问当前选择的第二个元素,您可以编写

var text = $('div:eq(1)').text();

您已经将函数eq()用于您希望选择的元素的索引。现在,你只有这个文本:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同样,如果你想选择序列的第三个元素,你可以直接写

var text = $('div:eq(2)').text();

或者,如果您愿意,您可以进行遍历,使用next()方法将选择从一个元素移动到下一个元素:

var text = $('div:eq(1)').next().text();

然后,您会收到以下警告消息:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,让我们看一个例子,演示选择和 DOM 结构之间的区别。这有时会造成混乱。你必须记住,eq()方法产生了一种部分选择;next()prev()parent()children()nextAll()prevAll()将选择移动到 DOM 上。

事实上,如果你写了这个链

var text = $('div:eq(1)').prev().text();

您不会得到任何东西,因为由‘div:eq(1)’选择的元素是列表中的第一个(但在选择中是第二个)。因此,如果您试图将选择移动到 DOM 中的前一个元素,您将什么也得不到。如果您想将选择转移到名为‘fruits’的父元素,您需要使用parent()方法:

var text = $('div:eq(1)').parent().text();

现在,您获得了父元素,它与选择的第一个元素相同。图 2-6 给出了结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-6。

The alert dialog box shows the four fruits within the first element

你写了命令吗

var text = $('div:eq(0)').text();

你会得到同样的结果。

创建和插入新元素

到目前为止,您已经看到,通过在函数jQuery()或其别名$()中传递一个参数,您获得了在 DOM 中具有该标签或相同类名的所有项目的选择。现在,假设您将一个不在 HTML 页面中的标签作为参数传递。在这里,您刚刚创建了一个要添加到 DOM 的新项目。此外,该元素实际上是一个选择,因此可能会受到任何类型的操作,即使它尚未实际添加到网页中。通过在方法链的末尾添加一些特定的 jQuery 方法,您将决定在哪里插入新创建的元素。

例如,如前面的示例所示,通过编写代码片段

$('<div>Lemon</div>').appendTo('div:eq(2)');

您在水果列表中创建了一个新元素。然后,将它追加到选择的第三个元素(列表的第二个元素)之后。图 2-7 显示了应用更改后网页中的列表是如何显示的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-7。

The list can be increased dynamically, adding new elements

有许多方法可以指定在何处以及如何插入刚刚创建的元素:prepend()after()before()append()appendTo()prependTo()insertAfter()insertBefore()wrap()wrapAll()wrapInner()等等。

关于这些函数使用的更多细节,建议读者参考 jQuery 官方网站上的文档( http://jquery.com/ )。

移除、隐藏和替换元素

另一组非常有用的 jQuery 方法包括那些允许我们从页面(从 DOM)中消除静态元素或者至少隐藏它们的方法。有时,这些方法甚至可以用于用一个元素替换另一个元素。

要从列表中删除“橙色”水果,只需简单地写下

$('div:eq(2)').remove(); 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你想隐藏它,你写

$('div:eq(2)').hide();

...

$('div:eq(2)').show();

然而,在这种情况下,在代码的后面,可能会再次显示“Orange”。

如果使用remove()(见清单 2-7),对应于选择器‘div:eq(2)’的元素会改变,并且不可能恢复被移除的元素。

清单 2-7。ch2_04c.html

$('div:eq(2)').remove();

var text = $('div:eq(2)').text();

alert(text); //returns 'Banana'

最后,如果您想用“菠萝”替换“橘子”,您可以使用replaceWith()方法,如下所示:

$('div:eq(2)').replaceWith('<div>Pineapple<div>');

现在,你有了一个新的水果列表,如图 2-8 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-8。

The list can be dynamically reduced by removing some of its elements

jquery ui:widget

除了 jQuery 库,还有另一个库可以帮助您将 web 页面与交互式图形对象集成在一起:jQuery UI。这个库提供了一整套工具,比如小部件、主题、效果和交互,这些工具丰富了 web 页面,将它们变成了高度交互的 web 应用。就我们的目的而言,小部件是我们特别感兴趣的。这些小图形应用可以证明是一个有价值的工具,当添加到您的网页,使您的图表更具互动性。小部件促进了网页下程序的交互,通常是真正的迷你应用。最简单的形式是,小部件以表格、手风琴、组合框甚至按钮的形式出现。

与 jQuery 库一样,如果想要集成插件,您需要在 web 页面中包含插件文件。您还必须包含表示主题的 CSS 文件。这可以通过谷歌托管图书馆服务来实现:

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js

</script>

<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js

</script>

您也可以从 CDN jQuery 官方网站下载:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css

<script src="http://code.jquery.com/jquery-1.9.1.min.js

<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js

如果您喜欢在本地下载这些库,或者使用本书附带的源代码中的工作区(参见附录 A),您可以参考下面的库:

<link rel="stylesheet" href="../src/css/smoothness/jquery-ui-1.10.3.custom.min.css" />

<script src="../src/js/jquery-1.9.1.js"></script>

<script src="../src/js/jquery-ui-1.10.3.custom.min.js"></script>

Note

本书中使用的 jQuery UI 小部件的主题是平滑度。可用主题的列表非常庞大,涵盖了许多颜色和形状的组合。这份库存丰富的清单可以在 ThemeRoller ( http://jqueryui.com/themeroller )上查到。ThemeRoller 是 jQuery 官方网站上的一个页面,允许您预览小部件,然后从可用的小部件中下载您喜欢的主题。

在访问 jQuery UI 的官方网站( http://jqueryui.com/ )时,您会注意到这个库提供了大量的小部件。这里,我将只讨论最常见的例子,尤其是那些最有可能集成到包含图表的页面中的例子。

正如您将在本书中看到的,其中一些小部件将被用作容器,利用它们的特定功能,如调整大小和封装,包括:

  • 手风琴
  • 制表符

其他小部件将用于取代 HTML 提供的简单控件,因为前者更高级,功能更丰富,包括:

  • 小跟班
  • 组合框
  • 菜单
  • 滑块

还有一些小部件也将执行指示器的功能。通过这些,您将看到如何集成一个特定的小部件类:

  • 进度条

手风琴

accordion 小部件是一组可折叠的面板,使网页能够在紧凑的空间中显示大量信息。每个面板可以包含一个主题区域,或者,正如您将在后面的章节中看到的,包含不同类型的图表。通过单击每个面板的选项卡来显示内容,允许用户从一个面板移动到另一个面板,而无需更改页面。手风琴的面板根据用户的选择扩展和收缩,使得在任何给定时间只有一个面板显示其内容。

为了在页面中获得一个折叠式小部件,您需要编写的 HTML 结构由一个包含所有面板的外部标签组成。每个面板依次由放置在两个

标签和一对标签之间的标题指定,内容在标签之间。清单 2-8 展示了一个简单的有四个面板的手风琴。

清单 2-8。ch2_05.html

<div id="accordion">

<h3>First header</h3>

<div>First content panel</div>

<h3>Second header</h3>

<div>Second content panel</div>

<h3>Third header</h3>

<div>Third content panel</div>

<h3>Fourth header</h3>

<div>Fourth content panel</div>

</div>

在 JavaScript 代码中,您需要添加清单 2-9 中的代码片段,以便获得一个 accordion 小部件。

清单 2-9。ch2_05.html

$(function() {

$( "#accordion" ).accordion();

});

图 2-9 展示了我们的手风琴。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-9。

An accordion consists of collapsible panels suitable for containing information in a limited amount of space

但是,这还不够。如果能控制手风琴的风格就更好了。这可以通过添加清单 2-10 中给出的代码来实现。

清单 2-10。ch2_05.html

<style type="text/css">

.ui-accordion {

width: 690px;

margin: 2em auto;

}

.ui-accordion-header {

font-size: 15px;

font-weight: bold;

}

.ui-accordion-content {

font-size: 12px;

}

</style>

结果如图 2-10 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-10。

By modifying the CSS style properties, you can change the accordion’s appearance as you like

标签

在功能上与手风琴非常相似的小部件是带有选项卡的面板。这里,每个面板都是唯一的,但是在顶部有几个选项卡,由不同的标题标识。尽管如此,这个小部件提供了在有限的空间内显示大量信息的可能性,用户可以选择一次只查看一个选项卡的内容。更重要的是面板垂直膨胀的损失。

为了在 web 页面中获得一个选项卡小部件,您需要编写的 HTML 结构比前一个稍微复杂一些。标题在一个无序列表

  • An anchor tag

清单 2-11。ch2_06.html

<div id="tabs">

<ul>

<li><a href="#tabs-1">First header</a></li>

<li><a href="#tabs-2">Second header</a></li>

<li><a href="#tabs-3">Third header</a></li>

<li><a href="#tabs-4">Fourth header</a></li>

</ul>

<div id="tabs-1">

<p>First tab panel</p>

</div>

<div id="tabs-2">

<p>Second tab panel</p>

</div>

<div id="tabs-3">

<p>Third tab panel</p>

</div>

<div id="tabs-4">

<p>Fourth tab panel</p>

</div>

</div>

在 JavaScript 代码中,您需要指定选项卡小部件,如清单 2-12 所示。

清单 2-12。ch2_06.html

$(function() {

$( "#tabs" ).tabs();

});

CSS 样式类也必须被定义,如清单 2-13 所示。

清单 2-13。ch2_06.html

<style type="text/css">

.ui-tabs {

width: 690px;

margin: 2em auto;

}

.ui-tabs-header {

font-size: 15px;

font-weight: bold;

}

.ui-tabs-panel {

font-size: 12px;

}

</style>

当程序完成时,您将得到如图 2-11 所示的小部件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-11。

The tab widget consists of multiple panels that occupy the same area

纽扣

在所有可用的小部件中,按钮仍然是最常用的。以前,在网页中插入按钮有两种方法。第一种是经典方法,带有标签<input type="button"/>。一种更现代的方法是标签。但是,多亏了 jQuery,还有另一种我们还没有考虑到的按钮。我们可以创建一个锚标签

清单 2-14。ch2_07.html

<button>A button element</button>

<input type="submit" value="A submit button" />

<a href="#">An anchor</a>

在没有进一步说明或 JavaScript 代码的情况下,当您加载页面时,您会看到如图 2-12 所示的按钮。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-12。

The web page shows three types of buttons: a simple button element, a submit button, and an anchor button

要使用 JavaScript 函数引用它们,请编写清单 2-15 中提供的代码片段。

清单 2-15。ch2_07.html

$(function() {

$( "input[type=submit], a, button" )

.button()

.click(function( event ) {

event.preventDefault();

});

});

这样,你将得到一组更美观的按钮,如图 2-13 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-13。

The three types of buttons are now represented by the jQuery UI button widgets

你可以通过添加图标来丰富你的按钮。jQuery UI 提供了大量的图标,但是您也可以使用更大的个人图标。清单 2-16 显示了如何将这四个按钮写入你的网页:

清单 2-16。ch2_08.html

<button>Button with icon only</button>

<button>Button with custom icon on the left</button>

<button>Button with two icons</button>

<button>Button with two icons and no text</button>

您添加了四个按钮来突出显示四种可能的情况:只有一个图标的按钮;左侧带有文本和图标的按钮;每边都有文本和图标的按钮;以及一个有两个图标但没有文本的按钮(见图 2-14 )。查看 HTML 代码,您可以看到实际上所有四个按钮内部都有文本,但是可以禁用此功能以获得没有文本的按钮。清单 2-17 展示了不同按钮的图标分配,图标名称被分配给primarysecondary(可选)属性。此外,通过将text属性设置为‘false’,可以获得一个没有文本的按钮。

清单 2-17。ch2_08.html

$(function() {

$( "button:first" ).button({

icons: {

primary: "ui-icon-locked"

},

text: false

}).next().button({

icons: {

primary: "ui-icon-italy"

}

}).next().button({

icons: {

primary: "ui-icon-gear",

secondary: "ui-icon-triangle-1-s"

}

}).next().button({

icons: {

primary: "ui-icon-gear",

secondary: "ui-icon-triangle-1-s"

},

text: false

});

});

要插入定制图标,你需要使用函数url(),将它们的地址定义为一个 CSS 文件,如清单 2-18 所示。

清单 2-18。ch2_08.html

<style>

.ui-button .ui-icon-italy {

background-image: url("icon/exit24x24.png");

width: 24px;

height: 24px;

}

</style>

图 2-14 显示了您刚刚创建的一组按钮。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-14。

Each button can be easily enriched with icons

组合框

组合框是网页和许多应用中另一个广泛使用的控件。组合框是一个可编辑的下拉菜单,用户可以从中选择一个条目。要在你的页面中插入一个组合框,你需要定义一个特定的元素结构,如清单 2-19 所示。

清单 2-19。ch2_09.html

<div class="ui-widget">

<label>Select your destination:</label>

<select id="combobox">

<option value="">Select one...</option>

<option value="Amsterdam">Amsterdam</option>

<option value="London">London</option>

<option value="Rome">Rome</option>

</select>

</div>

接下来,您需要使用 JavaScript 代码引用这个结构,首先用$()选择元素,然后将该结构激活为一个 jQuery 组合框小部件:

$(function() {

$( "#combobox" ).combobox();

});

让我们添加一些 CSS 样式:

<style>

.ui-widget {

font-size: 18px;

}

</style>

图 2-15 展示了组合框小部件,它代表了一系列事件捕获功能的起点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-15。

A combo box is a drop-down menu allowing the user to make a choise among various options

菜单

刚刚考虑了组合框,你不能忽视在你的主页上包含一个交互式菜单的可能性。使用这样的菜单,用户可以进行一系列选择,例如选择如何表示图表的选项。

在 HTML 中,无序列表被定义为

  • . If you want to add a submenu as a menu item, you only need to insert an embedded unordered list.

清单 2-20。ch2_10.html

<ul id="menu">

<li class="ui-state-disabled"><a href="#">Advanced</a></li>

<li><a href="#">Filter</a></li>

<li>

<a href="#">Zoom</a>

<ul>

<li><a href="#">10%</a></li>

<li><a href="#">25%</a></li>

<li><a href="#">50%</a></li>

<li><a href="#">100%</a></li>

</ul>

</li>

</ul>

与前面的小部件一样,您必须通过添加以下函数来激活菜单:

$(function() {

$( "#menu" ).menu();

});

您还需要包括 CSS 样式设置:

<style>

.ui-menu {

width: 150px;

}

</style>

现在,你在页面上有了一个菜单,如图 2-16 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-16。

A drop-down menu lets you categorize different options

滑块

当你开始开发各种类型的图表时,你会发现每次都要设置几个参数。用户可以通过滑块实时修改这些参数。这些滑块使用户能够在一定范围内更改参数。

与许多其他小部件一样,首先添加元素来表示 web 页面中的滑块。

<div id="slider"></div>

然后,像往常一样,用 JavaScript 函数激活小部件,在。例如,要指定滑块手柄的默认位置,可以将value属性设置为 0 到 100 之间的百分比值。类似地,可以通过将字符串‘horizontal’‘vertical’分配给orientation属性来设置方向。对于range属性,您可以指示滑块覆盖的范围(滑块轨迹的阴影区域)是从’min’值还是从’max’值开始(参见图 2-19 )。因此,如果您将范围属性设置为’]',范围将从最小值扩展到滑块句柄。animation属性是另一个需要考虑的设置。slider 小部件内置了动画:当用户点击滑块轨迹时,手柄从当前位置移动到被点击的点;这可以慢慢来,也可以很快来。您可以通过将animation属性设置为“fast或“slow’. The attributes ‘true’来选择手柄移动的速度,并且‘false’指示动画是启用还是禁用(参见清单 2-21)。

清单 2-21。ch2_12.html

$(function() {

$( "#slider" ).slider({

value: 60,

orientation: 'horizontal',

range: 'min',

animate: 'slow'

});

});

一旦你定义了滑块的基本属性,你必须决定它的大小(和句柄的大小)并添加 CSS 样式设置。当您定义滑块的长度和宽度时,您需要考虑您选择的方向,相应地设置heightwidth属性。在这种情况下,我们希望水平表示一个滑块;因此,width属性将远远大于height属性(见清单 2-22)。

清单 2-22。ch2_12.html

<style>

.ui-slider {

width: 400px;

height: 10px;

}

.ui-slider .ui-slider-handle {

width: 12px;

height: 20px;

}

</style>

如果在浏览器中加载网页,可以看到滑块(见图 2-17 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-17。

A slider is a widget that allows you to select a numeric value in a range

有时,您将需要使用多个滑块;你需要水平地组织它们(你可以找到类似的结构,例如,在立体声的均衡器中)。当指定几个滑块时,没有必要定义多个元素:只需要一个元素,用"eq"作为它的id来标记它。然后,在这个元素中,将每个滑块定义为包含其默认值的一对滑块(即各自的句柄出现在滑块轨道上的位置),如清单 2-23 所示。

清单 2-23。ch2_13.html

<div id="eq">

<span>88</span>

<span>77</span>

<span>55</span>

<span>33</span>

<span>40</span>

<span>45</span>

<span>70</span>

</div>

现在,您必须实现一个 JavaScript 函数,这次稍微复杂一些。首先,使用$("#eq > span")选择器,对七个元素进行选择。然后,使用parseInt()函数,将所有成对包含的值分配给相应的value属性,以便句柄位于图 2-18 所示的位置(参见清单 2-24)。

清单 2-24。ch2_13.html

$(function() {

$( '#eq > span' ).each(function() {

// read initial values from markup and remove that

var value = parseInt( $( this ).text(), 10 );

$( this ).empty().slider({

value: value,

range: 'min',

animate: 'slow',

orientation: 'vertical'

});

});

});

即使对于这种类似均衡器的结构,也有必要添加一些 CSS 样式设置,比如不同滑块之间的边距(见清单 2-25)。

清单 2-25。ch2_13.html

<style>

#eq span {

height:180px;

float:left;

margin:15px;

width:10px;

}

</style>

最终,你会得到如图 2-18 所示的条形。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-18。

The sliders can also be grouped in series to achieve more complex controls (e.g., an equalizer)

进度条

当您开发复杂的操作时,系统可能需要很长时间来完成其任务。当用户处于等待状态时,为了防止系统看起来被锁定,通常用进度条来表示进程完成的百分比。定义进度条非常简单:

<div id="progressbar"></div>

您还必须用 JavaScript 编写相应的函数来激活进度条,如清单 2-26 所示。

清单 2-26。ch2_11a.html

$(function() {

$( "#progressbar" ).progressbar({

value: 37

});

});

接下来,添加 CSS 样式设置,如清单 2-27 所示。

清单 2-27。ch2_11a.html

<style>

.ui-progressbar {

height: 20px;

width: 600px;

}

</style>

但是,你得到的并不是你想要的结果;你得到一个静态进度条,固定在 37%的标记处(见图 2-19 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-19。

With a progress bar, you can display the status of a process

为了获得一个全功能的进度条,您需要用一个直接连接到流程底层迭代的计数器值来设置它的属性value。此外,如果想增加进度条的动态效果,可以使用动画图形交换格式(GIF)图像作为背景。清单 2-28 显示了进度条中 CSS 样式属性的添加。

清单 2-28。ch2_11b.html

<style>

.ui-progressbar {

height: 20px;

width: 600px;

}

.ui-progressbar .ui-progressbar-value {

background-image: url(img/pbar-ani.gif);

}

</style>

图 2-20 中的 GIF 图像给人一种更好的操作进度感。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-20。

A progress bar with an animated GIF gives a highly dynamic appearance to the web page Note

从网站 ajaxload ( www.ajaxload.info )可以轻松安全地获得适合任何种类进度条的动画 gif。只需选择你想使用的进度条类型,然后选择前景和背景颜色,网站就会自动生成动画 GIF 的预览。如果你喜欢这张图片,你可以继续下载。

否则,您可以使用本书附带的代码中的动画 GIF ( pbar-ani.gif),在 charts/images 目录中(您可以在 Apress 网站[ www.apress.com/9781430262893 ]的源代码/下载区找到代码示例)。

关于 jQuery 库的总结性思考

现在,您可能想知道为什么我们从一个库(jQuery)开始,这个库显然与图表的开发或一般的数据可视化没有任何关系。您已经看到 jQuery UI 库为我们提供了图形元素,但是它的用途与您想象中的图表相去甚远。

实际上,我们必须从这里开始。您已经决定使用 JavaScript 语言,目的是在 web 页面中实现图形元素(只不过是 DOM 元素)。所有这些的核心是通过这个库引入的概念。选择、方法链、结构、使用 CSS 样式的实践——这些是 web 编程的基础,更是图表开发的基础。还有什么比使用 jQuery 库更好的方法来获得这些基础知识呢?

随着本书的深入,您会发现您操作的大多数 JavaScript 库(jqPlot、Highcharts 等等)都必须包含 jQuery 库。即使是不使用 jQuery 的 D3 库,其结构也能够管理选择、方法链和结构——也就是说,这些概念现在形成了 JavaScript 开发的基础。

这就是为什么了解 jQuery 很重要。

摘要

在开始直接用 JavaScript 开发图表之前,有必要介绍一些基本工具,它们构成了开发这类代码的基础。在第二章中,我们向您介绍了 jQuery 和 jQuery UI 库。使用 jQuery,您学习了如何通过选择和方法链动态操作 DOM 元素。通过 jQuery UI,您发现了如何用交互式图形元素来丰富页面:jQuery UI 小部件。

在下一章,你将开始运用你目前所学的一切来实现你的图表。您将从处理传入数据开始,这将通过解析一个 HTML 表来完成。

三、简单的 HTML 表格

Abstract

HTML 页面中最简单也是最广泛使用的数据显示形式之一是 HTML 表格。正因为它的广泛用途,表格是 HTML 中最早开发的元素之一。

HTML 页面中最简单也是最广泛使用的数据显示形式之一是 HTML 表格。正因为它的广泛用途,表格是 HTML 中最早开发的元素之一。

在这一章中,你将看到一个表格是如何构造的,以及实现它的 HTML 标签。正确使用这些标记可以区分一个可读的表和一个不可理解的表,后者不允许您理解潜在的关系。

然后,您将构建一个包含数据的表,您将在这里和接下来的章节中使用这些数据。这个例子的目的是理解一个表的本质以及数据在表中是如何组织的。这是构建最适合特定数据结构的图表类型的关键一步。

负责数据可视化的图表完全用 JavaScript 实现。因为您需要在图表中表示的数据包含在 HTML 表中,所以在本章的第二部分,您将看到如何用 JavaScript 语言实现一系列解析器。使用 jQuery 库,您会发现实现读取 HTML 表中特定数据的解析器是多么容易。这些以数组形式收集的数据很容易从 JavaScript 语言中获得,也很容易操作。

为您的数据创建表

表格只是一个嵌套标签的结构,以<table>标签为根。构建这种结构的过程并不困难,但需要一些深谋远虑。首先,你需要在一张纸上画出桌子的草图,或者至少,对于那些更熟悉桌子的人来说,在心里画出。这有助于确定表格中应包含的列数、行数和标题数。在标签对<table></table>中,根据需要插入与<tr></tr>对一样多的行。每个<tr>标记在表中创建一行。然后,您必须定义单元格。通常,顶行包含标题,因此您必须指定它们。您使用<th></th>对来指示应该被视为标题的文本。为了指定普通单元格,您使用了一对标签<td></td>。您必须小心保持行内单元格的数量一致。

还有其他一些标签可以实现丰富表格结构的功能。<caption>标签通常紧接在开始的<table>标签之后,呈现时,<caption>标签中的内容显示在表格上方的中间。标签<thead><tfoot><tbody>极大地改善了表格结构,并为级联样式表(CSS)和 JavaScript 提供了额外的挂钩。

这是用 HTML 构建表格结构的基本过程。现在,为了更好地理解,您将创建一个带有简单示例的表。

你的例子的目标

不幸儿童共和国统计局最近公布了关于太空中丢失的气球数量的结果。您希望将这个值放在一个 HTML 表中。

通过这个简单的例子,您将熟悉 HTML 表中的数据结构,学习如何应用 jQuery 选择来提取其中包含的数据。

此外,您将发现 CSS 样式在表格图形方面所起的作用。通过改变颜色和文本样式,您可以创建各种各样的图形主题。您还将看到如何通过使用渐变来调整背景颜色,以便为表格中的单元格提供三维外观。

清单 3-1 提供了一组数据,包括几个国家在六个月内每月丢失的气球数量。

清单 3-1。ch3_01.html

<HTML>

<HEAD>

<TITLE>MyChart</TITLE>

</HEAD>

<BODY>

<table class="myTable">

<caption>Balloons Lost in Space</caption>

<thead>

<tr>

<td></td>

<th>May 2013</th>

<th>Jun 2013</th>

<th>Jul 2013</th>

<th>Aug 2013</th>

<th>Sep 2013</th>

<th>Oct 2013</th>

</tr>

</thead>

<tbody>

<tr>

<th>USA</th>

<td>12</td>

<td>40</td>

<td>75</td>

<td>23</td>

<td>42</td>

<td>80</td>

</tr>

<tr>

<th>Canada</th>

<td>3</td>

<td>22</td>

<td>40</td>

<td>27</td>

<td>35</td>

<td>21</td>

</tr>

<tr>

<th>Australia</th>

<td>60</td>

<td>80</td>

<td>16</td>

<td>28</td>

<td>33</td>

<td>26</td>

</tr>

<tr>

<th>Brazil</th>

<td>46</td>

<td>7</td>

<td>14</td>

<td>26</td>

<td>36</td>

<td>24</td>

</tr>

</tbody>

<tfoot>

<tr>

<td colspan="7">Data from Statistical Office of the Republic of Unhappy Children</td>

</tr>

</tfoot>

</table>

</BODY>

</HTML>

这个简单的 HTML 代码给出了如图 3-1 所示的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1。

A raw HTML table without any CSS style

如你所见,这张桌子完全没有任何图形。它以表格结构中的一系列字符串的形式出现,但仅此而已。这是 CSS 样式发挥作用的时刻。

将 CSS 应用到您的表格

CSS 丰富了表格的图形模式,使其更具可读性,同时也更具吸引力。HTML 页面的每个元素都可以引用 CSS 样式类,并且可以通过设置这些类的属性来调整其图形特性。通过这种方式,您可以根据自己的喜好使用 CSS 来设计表格的样式。可以为 HTML 页面的任何元素设置多个样式属性。这要归功于 CSS3。

Note

这本书没有详细讨论 CSS 样式,也没有列出它们所有的可能性。这是一个庞大的主题,对我们来说,深入讨论可能会产生误导。然而,本书中的具体案例列出了所有需要设置的属性,从而让您更加熟悉 CSS 的广阔世界。

类及其属性的定义以这种方式写在对<style></style>中:

element.class {

attribute: value;

}

或者,如果您愿意,可以将这些定义编写在一个 CSS 文件中,然后包含在一个或多个网页中。因此,您可以为您的表定义以下 CSS 样式类,在 web 页面的<head>部分编写代码行,如清单 3-2 所示。

清单 3-2。ch3_02a.html

<style type="text/css">

table.myTable caption {

font-size: 14px;

padding-bottom: 5px;

font-weight: bold;

}

table.myTable {

font-family: verdana, arial, sans-serif;

font-size:11px;

color:#333333;

border-width: 1px;

border-color: #666666;

border-collapse: collapse;

}

table.myTable th {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background-color: #bbd0da;

}

table.myTable td {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background-color: #dedede;

}

</style>

现在,如果您再次加载网页,您可以看到表格的新布局,如图 3-2 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-2。

An HTML table in which you applied some CSS styles

查看表格,您可以看到数据现在更容易阅读,外观也更美观。上面的图示只是无数可能组合中的一种。可以设置的属性如此之多,以至于表的形式几乎没有限制。您还可以集成图像和背景,以进一步增强图形功能。

为您的表格添加颜色渐变

现在,您将继续优化您的表的外观。你已经取得了显著的进步,但你还可以更进一步。

正如您所看到的,表格中单元格的背景颜色是统一的,但是您可以创建颜色渐变,为 CSS 属性分配特定的值。因为这可能有些困难,网页终极 CSS 渐变生成器( http://www.colorzilla.com/gradient-editor )可以作为一个有用的工具,通过允许您选择颜色和它们将采取的方向,帮助您以图形方式生成渐变(见图 3-3 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-3。

Ultimate CSS Gradient Generator allows you to generate CSS gradients very easily

从最终的 CSS 渐变网页中,让我们选择两个我们喜欢的预设,为灰色单元格选择预设的灰色 3D #4,为标题单元格选择蓝色管道#2。接下来,复制 CSS 属性并粘贴到你的网页中,如清单 3-3 所示。

清单 3-3。ch3_02b.html

table.myTable th {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background: rgb(225,255,255); /* Old browsers */

background: -moz-linear-gradient(top, rgba(225,255,255,1) 0%,

rgba(225,255,255,1) 7%,

rgba(225,255,255,1) 12%,

rgba(253,255,255,1) 12%,

rgba(230,248,253,1) 30%,

rgba(200,238,251,1) 54%,

rgba(190,228,248,1) 75%,

rgba(177,216,245,1) 100%); /* FF3.6+ */

background: -webkit-gradient(

linear, left top, left bottom,

color-stop(0%,rgba(225,255,255,1)),

color-stop(7%,rgba(225,255,255,1)),

color-stop(12%,rgba(225,255,255,1)),

color-stop(12%,rgba(253,255,255,1)),

color-stop(30%,rgba(230,248,253,1)),

color-stop(54%,rgba(200,238,251,1)),

color-stop(75%,rgba(190,228,248,1)),

color-stop(100%,rgba(177,216,245,1))); /* Chrome,Safari4+ */

background: -webkit-linear-gradient(

top,

rgba(225,255,255,1) 0%,

rgba(225,255,255,1) 7%,

rgba(225,255,255,1) 12%,

rgba(253,255,255,1) 12%,

rgba(230,248,253,1) 30%,

rgba(200,238,251,1) 54%,

rgba(190,228,248,1) 75%,

rgba(177,216,245,1) 100%); /* Chrome10+,Safari5.1+ */

background: -o-linear-gradient(

top,

rgba(225,255,255,1) 0%,

rgba(225,255,255,1) 7%,

rgba(225,255,255,1) 12%,

rgba(253,255,255,1) 12%,

rgba(230,248,253,1) 30%,

rgba(200,238,251,1) 54%,

rgba(190,228,248,1) 75%,

rgba(177,216,245,1) 100%); /* Opera 11.10+ */

background: -ms-linear-gradient(

top,

rgba(225,255,255,1) 0%,

rgba(225,255,255,1) 7%,

rgba(225,255,255,1) 12%,

rgba(253,255,255,1) 12%,

rgba(230,248,253,1) 30%,

rgba(200,238,251,1) 54%,

rgba(190,228,248,1) 75%,

rgba(177,216,245,1) 100%); /* IE10+ */

background: linear-gradient(

to bottom,

rgba(225,255,255,1) 0%,

rgba(225,255,255,1) 7%,

rgba(225,255,255,1) 12%,

rgba(253,255,255,1) 12%,

rgba(230,248,253,1) 30%,

rgba(200,238,251,1) 54%,

rgba(190,228,248,1) 75%,

rgba(177,216,245,1) 100%); /* W3C */

filter: progid:DXImageTransform.Microsoft.gradient(

startColorstr='#e1ffff', endColorstr='#b1d8f5',GradientType=0 ); /* IE6-9 */}

table.myTable td {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background: rgb(242,245,246); /* Old browsers */

background: -moz-linear-gradient(

top,

rgba(242,245,246,1) 0%,

rgba(227,234,237,1) 37%,

rgba(200,215,220,1) 100%); /* FF3.6+ */

background: -webkit-gradient(

linear, left top, left bottom,

color-stop(0%,rgba(242,245,246,1)),

color-stop(37%,rgba(227,234,237,1)),

color-stop(100%,rgba(200,215,220,1))); /* Chrome,Safari4+ */

background: -webkit-linear-gradient(

top,

rgba(242,245,246,1) 0%,

rgba(227,234,237,1) 37%,

rgba(200,215,220,1) 100%); /* Chrome10+,Safari5.1+ */

background: -o-linear-gradient(

top, rgba(242,245,246,1) 0%,

rgba(227,234,237,1) 37%,

rgba(200,215,220,1) 100%); /* Opera 11.10+ */

background: -ms-linear-gradient(

top,

rgba(242,245,246,1) 0%,

rgba(227,234,237,1) 37%,

rgba(200,215,220,1) 100%); /* IE10+ */

background: linear-gradient(

to bottom,

rgba(242,245,246,1) 0%,

rgba(227,234,237,1) 37%,

rgba(200,215,220,1) 100%); /* W3C */

filter: progid:DXImageTransform.Microsoft.gradient(

startColorstr='#f2f5f6', endColorstr='#c8d7dc',GradientType=0 ); /* IE6-9 */

您会立即注意到添加的代码相当广泛。关于属性背景上渐变的应用,每个浏览器都有不同的规范。因为网站的用户可以从任何类型的浏览器请求您的页面,所以您必须考虑到所有的可能性。

在图 3-4 中,您可以看到如何将渐变应用于不同的单元格,从而使表格呈现三维外观。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-4。

The CSS background attribute can be set with gradients to give the table a better appearance

使用文件向表格添加颜色渐变

颜色渐变是您可以为表格选择的另一种样式属性。以下示例使用背景图像,使表格的单元格具有颜色渐变。为了实现这一点,您必须包含两个.jpg文件,其中您绘制了两种颜色等级:蓝色用于标题单元格,灰色用于具有常规值的单元格,如清单 3-4 所示。

清单 3-4。ch3_02c.html

table.myTable th {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background:#b5cfd2 url('img/cell-blue.jpg');

}

table.myTable td {

border-width: 1px;

padding: 8px;

border-style: solid;

border-color: #666666;

background:#dcddc0 url('img/cell-grey.jpg');

}

Note

用来给表格的单个单元格着色的两个.jpg背景文件可以在本书附带的代码中找到,在 Apress 网站的源代码/下载区( www.apress.com )。

图 3-5 说明了同一个 HTML 表格,但是这一次,使用两幅图像作为背景,褪色的颜色模拟阴影,使表格具有三维外观。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-5。

The same HTML table, but with another CSS style

您已经看到了如何构建 HTML 表格以及如何为其分配 CSS 样式。现在,让我们看看 JavaScript 将在整本书中扮演的角色:数据分析和图表显示。在这种情况下,输入数据以表格的形式表示,但也可以是从数据库中获得的数据或从文件中读取的数据。

解析表数据

前一章描述了 jQuery 库的基础知识。借助本库提供的函数,在本章和后面的章节中,您将开发不同种类的图表,在表格中显示数据。但是,您应该将 JavaScript 代码放在哪里呢?在<script></script>标记对中,您将添加$(document)。ready()函数,在其中编写 JavaScript 代码,以便在窗口加载之前添加所有事件或您想要包含的任何内容。一旦浏览器注册了文档对象模型(DOM ),您在括号中写的所有内容都会被执行。这使您可以在页面打开之前隐藏或显示页面的元素。

导入 jQuery 库

要使用 jQuery 函数,您必须导入 jQuery 库。没有必要从 jQuery 网站下载并保存到您的服务器上;网页可以从分发站点直接访问库。清单 3-5 代表了您将要编写的 JavaScript 代码的起点。

清单 3-5。ch3_03a.html

<script src="http://code.jquery.com/jquery-1.9.1.min.js

<script>

$(document).ready(function(){

//add your code here

});

</script>

Note

如果您使用的是该书附带的源代码,请将对 jQuery 库的引用替换为

<script type="text/javascript" src=".. /src/jquery.min.js"></script>

一旦准备工作完成,您就可以立即开始编写代码了。首先,您将创建一个名为tableData的 JavaScript 对象来保存所有信息:

<script>

$(document).ready(function(){

var tableData = {};

});

该变量将用作从表中解析的数据的容器。使用括号是为了将它视为一个对象。通过声明tableData.myNewProperty并将该属性设置为您选择的任何值,您可以向该对象添加任何属性。同样,您可以将表格元素存储在另一个变量中:

$(document).ready(function(){

var tableData = {};

var table = $('table');

});

使用这个语句,您可以指向包含在<table></table>标记对中的所有元素。只用几个字,你就做出了选择。

标签

您在tableData对象中创建的第一个属性是xLabels。它将包含 x 轴上标签的值。这些标签对应于表格标题的单元格内容。标签按照收集数据的顺序读取,即从左到右。您可以在<th>标签中找到这些值(参见图 3-6 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-6。

Parsing the headings with the 'thead th' as selector

在清单 3-6 中,xLabels被定义为一个数组,通过使用each()方法,每个<th>元素都被遍历,并将其内容推入这个数组。仔细看看这个表,可以看到<th>元素嵌套在<thead>标签中。因此,正确的选择需要您用'thead th'指定层级。

清单 3-6。ch3_03b.html

$(document).ready(function(){

var tableData = {};

var table = $('table')

tableData.xLabels = [];

table.find('thead th').each(function(){

tableData.xLabels.push( $(this).html() );

});

});

只是为了调试,为了查看这些数组的内容,您可以使用控制台(参见第一章的中的“Firebug 和 DevTools”一节),调用log()函数来显示作为参数传递的变量的内容:

console.log(tableData.xLabels);

这样你就定义了一个新的数组xLabels,包含了如图 3-7 所示的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-7。

The content of the xLabels array, displayed in Firebug

提取标签

现在你需要从表格中提取标签,引用一系列数据,如图 3-8 所示。在您的表格中,您可以用左侧显示的国家名称来识别这些标签。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-8。

Parsing the names of countries with 'tbody th' as selector

为了捕获标签,您认为它们被分组为<tbody>组中的<th>元素。与xLabels一样,您定义了一个新的属性tableData : legend(见清单 3-7)。之所以指定这个名称,是因为在任何类型的图表中,系列的标识符通常在图例中报告。因此,您编写了一个与前一个类似的代码,这次使用选择'tbody th'

清单 3-7。ch3_03c.html

$(document).ready(function(){

...

table.find('thead th').each(function(){

tableData.xLabels.push( $(this).html() );

});

tableData.legend = [];

table.find('tbody th').each(function(){

tableData.legend.push( $(this).html() );

});

});

使用 Firebug 上的控制台,可以看到legend数组的内容,如图 3-9 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-9。

The content of the legend array, displayed in Firebug

通过分析表中列出的点,你可以很容易地区分什么会在 x 轴上,什么会在 y 轴上。您收集了几个系列(国家)在不同时间(月)的数据。很容易看出,时间将在 x 轴上表示,用xLabels填充其刻度;您为每个分笔成交点分配一个月。此外,整个系列的值必须分布在 y 轴上。您事先不知道 y 轴上刻度的数值,也不知道需要多少个刻度,但是您需要计算它们。首先,在这些情况下,通常的做法是找出数据中的最高值和最低值。您可以用'tbody td'选择器选择所有数据,如清单 3-8 所示。

清单 3-8。ch3_03d.html

$(document).ready(function(){

...

table.find('tbody th').each(function(){

tableData.legend.push( $(this).html() );

});

var tmp = [];

table.find('tbody td').each(function(){

var thisVal = parseFloat( $(this).text() );

tmp.push(thisVal);

});

if(Math.min.apply(null, tmp) > 0)

tableData.minVal = 0;

else

tableData.minVal = Math.min.apply(null, tmp);

tableData.maxVal = Math.max.apply(null, tmp);

});

您希望 y 轴上的最小值等于 0,并且仅当表中有负值时才采用更低的值。这种情况下只有正数,所以minVal是 0,maxVal是 80。

然后,使用这两个值来计算 y 标签上的刻度。基于这些值,您应该在 0 到 80 的范围内延伸 y 轴。其实最好是把最大值延长,不要让你的数据的最大值点碰到图表顶部。您可以将最大值乘以一个系数(例如,10%)。让我们修正清单 3-8 的最后一行,引入系数,如清单 3-9 所示。

您将从Math.max.apply()函数返回的最大值乘以因子 1.1,从而将该值增加 10%(max+0.1*max= 1.1*max)。

清单 3-9。ch3_03e.html

if(Math.min.apply(null, tmp) > 0)

tableData.minVal = 0;

else

tableData.minVal = Math.min.apply(null, tmp);

tableData.maxVal = 1.1 * Math.max.apply(null, tmp);

关于刻度的数量和它们的内容,清单 3-10 定义了一个yLabels数组作为tableData的属性。要量化 y 轴上的刻度数,使其代表最佳折衷,您必须首先确定一个刻度与下一个刻度之间的合适距离(以像素为单位)。将 y 轴的范围除以一个数字,该数字表示刻度之间的像素距离。你可能认为 30 像素的距离就足够了。结果不是整数,需要上舍入。

清单 3-10。ch3_03f.html

$(document).ready(function(){

...

tableData.maxVal = 1.1 * Math.max.apply(null, tmp);

tableData.yLabels = [];

var yDeltaPixels = 30;

var h = 360;

var w = 460;

var nTicks = Math.round(h / yDeltaPixels);

var yRange = tableData.maxVal - tableData.minVal;

var yDelta = Math.ceil(yRange / nTicks);

var yVal = tableData.minVal;

while( yVal < (tableData.maxVal - yDelta)){

tableData.yLabels.push(yVal);

yVal += yDelta;

}

tableData.yLabels.push(yVal);

tableData.yLabels.push(tableData.maxVal);

});

如果您研究yLabels数组的内容,您会发现 y 的 12 个值对应于 12 个刻度,如图 3-10 所示。这些标签将显示在每个刻度旁边。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-10。

The content of the yLabels array, displayed in Firebug

yLabels数组中的值取决于许多因素,例如,您想要表示 y 轴的维度(这里,您选择了 360 个像素),每个刻度间隔 30 个像素:这里您得到的是 12 个刻度。另外,如果您想知道 y 的多少个单位对应于一个刻度和下一个刻度之间的距离,您可以计算yDelta(向上取整),在本例中是 8。事实上,yLabels的值都是 8 的倍数。

数据组

您需要创建的下一个属性是dataGroups,一个包含所有值的两级数组,按系列分组。每个数列是一个数值数组,dataGroups是一个数列数组。要对不同系列的数据进行分组,可以使用<tr>标签。事实上,表中的每一行都是一个序列,您可以获取其中的所有值,因为它们是由单元格标记<td>分隔的。结合标题中报告的时间方向,从左至右读取数据(见图 3-11 )来获取数值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-11。

Parsing of groups of data for multiseries

接下来,使用'tbody tr'作为选择器,遍历表中的行(见清单 3-11);对于该迭代的每一步,您都必须对每个单元格进行循环,以便获得值。

清单 3-11。ch3_03g.html

$(document).ready(function(){

...

tableData.yLabels.push(tableData.maxVal);

tableData.dataGroups = [];

table.find('tbody tr').each(function(i){

tableData.dataGroups[i] = [];

$(this).find('td').each(function(){

var tdVal = parseFloat( $(this).text() );

tableData.dataGroups[i].push( tdVal );

});

});

});

最后可以看到dataGroups数组中包含的四个数组(每个系列一个),如图 3-12 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-12。

The content of the dataGroups array, displayed in Firebug

如果您想要访问特定系列中包含的值,您可以按如下方式操作:

console.log(tableData.dataGroups[0]);

console.log(tableData.dataGroups[1]);

...

准备实现图形

现在,您已经提取了表中的所有数据并将它们放在单独的数组中,您已经准备好开始实现图形并将这些数据转换成图形元素。

这将是接下来三章的主题,在这三章中,您将看到这些数据首先以折线图(第四章)表示,然后以条形图(第五章)表示,最后以饼图(第六章)表示。

摘要

本章的目的是介绍当你有一个数据结构要操作时,你必须遵循的方法。通过本章,您开始了解如何基于 jQuery 库提供的工具开发自己的库。

您从创建 HTML 表开始,这是最原始的数据表示形式。尽管它很简单,但是如果设置不好,这个表可能会有问题。选择表格形式的数据表示作为试验场,开始研究 jQuery 如何选择页面上的特定 HTML 元素,更具体地说,是组成 HTML 表格的标记。在此基础上,您构建了一组解析器来从复杂的结构中提取数据(在本例中是一个 HTML 表,但是正如您将看到的,也可以从其他类型的结构中提取数据)。这些数据因此被分成不同的组,以一种更容易操作的格式。

在下一章中,您将开始使用画布提供的第一批图形元素,同时继续使用 jQuery 库。作为第一步,您将学习如何使用通过本章开发的解析器获得的数据来开发折线图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值