JavaScript高效图形编程(修订版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-09-18 02:53:41

点击下载

作者:[英]拉斐尔·茄科(Raffaele Cecco)

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

JavaScript高效图形编程(修订版)

JavaScript高效图形编程(修订版)试读:

前言

作为资深的视频游戏开发人员,我已经习惯于和高性能的编程语言和硬件打交道,因此刚开始我并没有对JavaScript进行图形编程有太高的期望。不过后来发现,实际上JavaScript是一个优秀和高效的编程语言,而且随着更好的浏览器支持、本身的性能提升,以及新的工具库加入,JavaScript还在不断变好。JavaScript结合了HTML5 Canvas等特性,给Web开发人员提供了真正可以不用Adobe Flash等插件的方案。而WebGL等特性则为使用JavaScript和浏览器进行图形编程描绘了非常美好的未来。

这本书的目标读者需要具备一定的JavaScript知识,并且想要学习真正的Web图形编程,而不仅仅依赖于jQuery这样的库做一些动画特效。本书中涵盖了下面这些内容:● 如何重用和优化代码,包括继承技术和性能优化经验;● 用普通的DOM操作(DHTML)来构建图形化应用;● 使用更高级的画布元素;● 创建视频游戏;● 创建图形和动画所需的数学;● 使用谷歌可视化API和画图工具来呈现你的数据;● 如何有效使用jQuery并开发面向图形的jQuery插件;● 使用jQuery Mobile创建适合移动设备的图形Web应用;● 使用PhoneGap将你的Web应用转换为本地Android应用。

本书将带你了解不同的图形编程技术,你可以进一步探索自己感兴趣的领域。

多做尝试,你会获得很多乐趣!目标读者

打算阅读本书的读者应该对网站和Web应用开发,特别是JavaScript,具有一定知识和使用经验。

为了方便开发和表达,本书的许多示例代码都使用了jQuery。一般来说,本书中用到的所有外部库及其文件都可以从谷歌等可靠的内容分发网络获取。

另外,本书用到了一些基础的数学知识,包括向量和三角函数。本书组织结构

本书节奏较快,读者从第1章中就可以看到第一个图形编程的示例。

剩余章节涉及多个图形相关的技术,这些技术可以给你的Web应用增加视觉冲击力和交互性。

讨论交互式图形的书无法避开视频游戏。本书中将开发一个完整的视频游戏应用,并讨论相关的子图和滚动等技术。

本书每章的内容可以总结如下。

第1章,代码重用和优化

本章讨论JavaScript面向对象编程技术,以及图形应用中涉及的代码优化(包括jQuery优化)。本章甚至将介绍如何使用鲜为人知的JavaScript位操作符进行性能优化。

第2章,DHTML基础

本章展示了如何使用普通的DOM操作(DHTML)创建图形应用。我们将在本章开发一个适用于游戏和其他场景的子图系统,并将其以jQuery插件的形式封装。

第3章,滚动

本章首先讨论了CSS滚动技术,包括视差特效。然后本章将介绍基于JavaScript的滚动技术,以及基于块的视差卷轴特效。我们还将介绍一个强大的地图编辑器,用于创建基于块的地图。

第4章,高级UI

本章覆盖了jQuery UI和Ext JS两个UI库。我们将探讨两个库的不同工作方式和各自适合的应用类型。另外,我们还将构建一个三维旋转木马的示例。

第5章,JavaScript游戏介绍

本章演示了如何用开放Web技术,而不是Flash插件来构建有趣的Web游戏。我们将通过开发一个怀旧的视频游戏来说明我们讨论的技术。

第6章,HTML5画布

本章通过许多示例来深入介绍Canvas元素,包括如何使用Canvas和WebSockets创建一个图形化的聊天应用。其中涉及的画布主题包括:绘制、描边、填充、渐变、递归绘制、位图和动画。

第7章,游戏和模拟中的向量

本章介绍图形应用和游戏中广为使用的二维向量。代码示例包括大炮和火箭的模拟。

第8章,谷歌可视化

本章使用谷歌图表工具来对多种数据进行可视化,从基本的饼图到仪表图。本章不仅介绍了静态的可视化图形,而且覆盖了交互式的可视化图表,以及必要的数据格式化技术。

第9章,使用jQuery Mobile为移动设备开发

本章描述了jQuery Mobile,一个基于jQuery的、面向移动设备的开发框架。jQuery Mobile可以将普通的HTML页面转化为交互式和动画式的手机体验。本章中的主要例子是一个使用jQuery UI、面向移动设备的图形化滑动解谜游戏。

第10章,用PhoneGap创建Android应用

本章介绍如何使用PhoneGap将Web应用转换为手机的本地应用。本章解释了如何安装和配置PhoneGap来创建本地Android应用。在此之后,我们将把第9章的滑动解谜游戏转换为可以部署到移动设备上的本地应用。本书的惯例提示这个图标用来强调一个提示、建议或一般说明。警告这个图标用来说明一个警告或注意事项。

本书中提到一些有用的网站和页面,通常除了页面URL外,还会提供页面名称。

因此你可以选择直接输入URL或者通过搜索引擎搜索页面名称,找到相关页面,

可以在地址比较复杂,或页面地址被改变时使用后者。代码示例的使用

本书包含许多代码片段、示例和一些完整充实的应用。有时手动输入代码很麻烦,因此推荐从本书的代码库中复制代码。本书的许多代码中穿插了普通文本,直接从代码库复制代码可以避免你去拼接不同位置的代码。

在本书的HTML页面示例中,大部分使用HTML5文档类型:

< DOCTYPE html >

为方便起见,示例中的所有CSS样式都被直接嵌入HTML页面。在实际Web应用开发中,还是推荐使用外部文件保存CSS样式。本书的示例代码可以在 http://www.professorcloud.com/supercharged中找到。目标浏览器

本书绝大部分示例代码都可以在较新的浏览器上工作,比如:● Firefox 3.6x+● Safari 4.0x+● Opera 10.x+● Chrome 5.x+● Internet Explorer 8+

有些例子甚至可以在IE6和IE7上工作。

这些例子在Windows XP、Windows Vista和Windows 7上进行了完整测试,在iOS上进行了部分测试。理论上,这些例子也应能在上述浏览器的Linux版本上工作。

画布(Canvas)标签的使用则限于支持画布的浏览器,对IE来说,只有IE9可以(无需额外插件或库)直接支持。

有少量的例子需要特殊的环境,比如手机开发环境(PhoneGap)、服务器语言(PHP)或特殊浏览器。

如果是这种情况,书中会提到相关环境的设置和配置。®Safari在线图书

Safari在线图书是一个按需订阅的数字图书馆。它有不少于7500本技术和创意相关的书籍和视频供你参考和搜索。

通过订阅,你可以在线阅读任何页面或视频,甚至可以从手机或移动设备上在线阅读。

你可以在书籍出版前访问到它们,并给作者发送反馈。其他功能还包括:复制和赋值代码、组织收藏夹、下载和标记章节、做笔记、打印等。

O’Reilly Media已经将本书英文版上传到Safari在线图书服务。在http://my.safaribooksonline.com上免费注册,你就可以访问本书所有章节以及类似主题的书籍。联系方式

如果你想就本书发表评论或有任何疑问,敬请联系出版社:

美国:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

我们还为本书建立了一个网页,其中包含了勘误表、示例和其他额外的信息。你可以通过如下网址访问该网页:

http://www.oreilly.com/catalog/9781449393632

关于本书的技术性问题或建议,请发邮件到:

bookquestions@oreilly.com

欢迎登录我们的网站(http://www.oreilly.com),查看更多我们的书籍、课程、会议和最新动态等信息。

Facebook: http://facebook.com/oreilly

Twitter: http://twitter.com/oreillymedia

YouTube: http://www.youtube.com/oreillymedia致谢

以作者一己之力出版一本书几乎是一件不可能的事情,在此我想特别感谢为本书做出贡献的人们。● 感谢Simon St.Laurent为本书付出的热心、鼓励和帮助。● 感谢所有的评审专家,特别是Shelley Powers为本书提供了大量

的真知灼见。● 感谢我的文字编辑Rachel Monaghan, 以及其他为本书完成提供

帮助的伙伴。● 感谢无私的开发者社区,自由地分享他们的工作和知识,来帮助

推动Web的发展。● 感谢我的妻子Rebecca和女儿Sofa,能够容忍我随时随地带着笔

记本准备写作。第1章代码重用和优化

JavaScript受到了许多不公平的评价。许多人说JavaScript在面向对象编程上存在局限,甚至有人认为JavaScript不能归为面向对象编程(OOP)语言。尽管JavaScript和C++、Java有许多相似之处,但它没有等价Class的声明,也没有显而易见的方式去实现流行的OOP技术,如继承(代码复用)和封装。JavaScript的类型非常松散,也没有编译器,因此在运行出错前只能提供很少的错误或警告。JavaScript是把双刃剑,一方面给了程序员很大的自由,另一方面也给程序员带来一些陷阱。

JavaScript中充满了对传统编程“过失”的忽略,传统的程序员可能对此颇为郁闷。比如,在JavaScript中全局函数和变量是默认行为,而忘记加分号是完全可接受的。对JavaScript的工作方式缺乏了解,往往导致程序员无比郁闷。如果首先了解一些基础事实,将有助于你编写JavaScript应用:● JavaScript不是一个基于类的语言;● 写好代码,并不一定需要基于类的面向对象编程语言。

有些编程人员尝试用JavaScript 写C++风格的代码。尽管在某种程度上可以达到目标,但最终结果往往让人感觉不自然。

没有任何编程语言是完美的,人们有理由争论某个编程语言或OOP本身的优越性是否仅仅是皇帝的新衣。根据我的个人经验,用C++、Java或PHP编写的软件生成的bug和问题,并不比用JavaScript编写的软件生成的少。我认为JavaScript的灵活性和表达力,可以使你更快地进行项目开发。

幸运的是,大部分JavaScript的缺点都不是无药可医。解决之道并不是一味模仿其他语言,而是扬长避短:利用Javascript的灵活性,而小心避开难处理的部分。基于类的其他语言容易引起笨拙的类层次和臃肿的代码,JavaScript则提供了同样有效但更轻量级的继承模式。

JavaScript可以有许多种方法来实现继承。下面的代码使用原型继承来创建一个Pet对象,和一个继承它的Cat对象。JavaScript教程中常常能见到这种“经典”的继承模式。

上述代码可以工作,但不是特别优雅。如果你熟悉其他OOP语言比如C++或Java,new声明是好理解的。但关键字prototype显得很啰嗦,并且没有隐私;注意外部代码将petCat的legs属性改成了一个不合理的值:7。这种继承方法没有提供对外部继承的保护,在涉及多个程序员的复杂项目中这个缺点也许会影响很大。

另一个选项无需使用prototype或new,而是利用JavaScript的“函数继承(functional inheritance)”特性来吸收和增强对象实例(object instances):

这里没有可笑的prototype,而且所有东西都封装得很漂亮。最重要的是:legs变量是私有的。如果尝试从cat外部修改不存在的公共legs属性,仅导致创建一个没有用过的legs属性。真正的legs值安全地保存在pet的getDetails()方法创建的闭包(Closure)内部。闭包在函数执行结束后,保持了函数的局部变量。在这个例子中这个函数指的是pet()。

事实上,用JavaScript实现继承并没有所谓“正确”的方法。但我个人认为函数继承方式非常自然。你和你的应用也许倾向其他方法。通过搜索“JavaScript Inheritance”你可以找到许多在线资源。提示使用原型继承的好处之一是内存效率;不管它被继承多

少次,对象的原型属性和方法只被保存一次。函数继承则相反:每个新的实例都会创建重复的属性和

方法。如果你要创建许多(如上千个)大对象的实例,内存

消耗可能会成为一个问题。不过这个问题很容易解决:可以

将较大的属性或方法保存在一个对象中,并将其作为参数传

给构建函数。这样所有实例就可以共同使用一个对象资源,

而不是创建自己的版本。1.1 快速运行“快节奏的JavaScript图形编程”的概念也许听起来很矛盾(oxymoron)。

老实说,尽管JavaScript和Wed浏览器的组合不太可能创作出最尖端的游戏软件, 但还是有很大空间来创建漂亮、快节奏和图形丰富的应用,包括游戏。可用的工具虽然不是最快的,但却免费、灵活、而且容易上手。

作为一种解释性语言,JavaScript不能像C++等语言那样从编译优化中获益。尽管现代浏览器已经大大提升了JavaScript效率,还是有很多空间来提高JavaScript应用的执行效率。这需要程序员去决定使用什么算法,优化哪段代码,如何以高效的方式操作DOM。目前还没有一个健壮的优化工具可以为你完成这件事。

除非代码实在太烂,否则一般情况下简单的JavaScript应用(如仅处理少量鼠标单击或进行零散AJAX调用)是没必要进行代码优化的。而本书中涉及的应用则需要高效的代码才能保证用户体验——好的动画不应该慢或抖动。

本章剩余部分将不讨论如何提高从服务器加载页面的速度,而是考虑服务器资源加载之后的代码执行。具体来说,它讨论适用于JavaScript图形编程的优化技术。1.2 优化什么,何时优化?

和优化技术同等重要的是:知道什么时候不优化。过早优化会带来晦涩的代码和bug,优化很少执行的代码区域也没有必要。以帕莱托法则(即80-20法则)来看,20%的代码将占用80%的CPU周期。程序员应该集中于优化这20%、10%或5%,而忽略其他部分。这样bug会更少,大部分代码都保持了可读性,也保证了你的头脑清醒。

你可以用Firebug等性能测试工具,来了解哪些函数花费了绝大部分执行时间;然后检查这些函数并决定要优化的代码段。Firebug性能测试器依赖火狐(Firefox)浏览器,有些浏览器有自己的性能测试器。而老版本的浏览器则不一定有类似的工具。

图1-1是Firebug性能测试器的界面。在Console菜单,选择Profile来开始性能测试,然后再选择Profile来停止测试。然后Firebug会显示所有在开始和结束点之间被调用的JavaScript函数分析。所显示的信息如下所示。图1-1 运行中的Firebug性能测试器

Function

被调用的函数名

Percent

在函数中所花费的时间和总时间的比例

Call

函数被调用的次数

Own time

在函数中所花费的时间(不包括对其他函数的调用)

Time

在函数中所花费的时间(包括对其他函数的调用)

Average

Own time的平均值

Min

函数的最快执行时间

Max

函数的最慢执行时间

File

函数所在的JavaScript文件

如果你能自己创建适合所有浏览器的性能测试集,可以提高开发效率,并在没有测试工具的浏览器上使用。它只是将相同的测试页面载入到每一个浏览器,然后阅读测试结果。它也可以用来迅速检查函数内的细微优化。“自定义代码性能测试”一节将讨论如何创建自己的性能测试集。警告类似Firebug的调试器会给时间数值带来不小的误差。

在执行性能测试之前,要确保关闭调试器。“优化”是一个很宽泛的词,程序员可以从不同方面,以不同方式来对一个Web应用进行优化。

算法

应用程序是使用最有效的方法来处理数据的吗?代码优化没法修正一个差劲的算法。实际上,找对算法和DOM操作的高效一样,是保证应用快速运行最重要的因素之一。

有时,如果应用要求不高,一个慢但容易实现的算法就足够了。但如果性能是个问题,你也许需要检查研究一下当前所使用的算法。

本书不会讨论常见的搜索和排序等具体算法,因为读者可以在相关的计算机书籍和网络资源中找到许多关于它们的讨论。即使是游戏中涉及的3D图形学、物理和碰撞检测等这些更专业的问题和算法,也有很多书籍可以参考。

JavaScript

仔细检查调用得非常频繁的代码,在应用的某些关键区域中,对频繁执行部分的一个小小优化都会有不错的收益。

DOM和jQuery

DOM加jQuery是操纵Web页面非常方便的一种方式。但如果你没有注意到一些简单规则的话,也会成为性能重灾区。DOM搜索和操作比较慢,应该尽量避免。1.3 自定义代码性能测试

浏览器并不是运行准确代码性能测试的完美环境。短时间的定时器不够准确、事件的要求、零散的垃圾回收和系统上运行的其他进程都会导致结果偏差。一般可以这样来测试JavaScript代码的性能。

这种方法虽然理论上可行,但由于前面提到的原因,现实中它不能给出准确的结果,尤其是当被测试代码只有几毫秒执行时间的情况下。

更好的方法是让被测试代码循环运行较长的时间(比如1秒),然后用在那段时间内完成的循环次数来评价性能。如果你要计算均值(mean)和中值(median)等统计信息,可以重复测试几次。

为保证测试运行较长时间,使用这个代码:

无论系统性能如何,这些测试都会运行相同的时间。更快的系统会完成更多的循环次数。在实践中采用这种方法能得到较为一致的结果。

你可以运行5次这样的性能测试,每次1秒,循环次数的中值可作为最终的衡量标准。1.4 优化JavaScript

严格来说,任何用于JavaScript的优化也适用于其他语言。到了CPU层,道理都是一样的:尽量少做工作。在JavaScript中,CPU层的工作和程序员距离太远,以至于很难确定到底CPU层进行了哪些工作。使用一些前人证实过可行的方法,一般来说对你的代码是有益处的,尽管只有通过实验测试才能明确证明。1.4.1 查找表

高开销的计算可以预先进行,并将值存在一个查找表(lookup table)中,使用时给出简单的整型下标(index)就可以取出查找表中的值。只要查找表访问的代价比从头计算的代价低,你的应用程序就能因此获得更好的性能。比如,JavaScript的三角函数就可以利用查找表加速。在这节中,将用一个查找表取代Math.Sin()函数,并用它来构建一个图形动画的应用。

Math.sin()函数接受一个参数:角度(以弧度为单位),并返回一个−1~1之间的值。角度参数的有效范围是0~2π(约6.283 18)弧度。这个范围对索引一个查找表没什么帮助,因为只有6个可能的整数。与其这样,不如完全不用弧度,而是让查找表接受0~4 095的整数索引。这个粒度对大多数应用来说足够了,但你可以通过给参数steps设置更大的值来得到更精密的查找表。

fastSin()函数将2π弧度分为参数中定义的步数,并将每一步得到的结果保存在数组中。

图1-2为Math.sin()和查找表的性能测试结果的比较。图1-2 Math.sin()和查找表的性能测试对比。数值越大,性能越好

大多数浏览器上的性能提高大约有20%,而Google Chrome上的提高幅度更大。如果查找表里面的值是由比Math.sin()更复杂的函数计算出来的,查找表方法的性能优势将更明显;因为不论计算值的时间多长,查找表的访问时间保持不变。

下面的应用使用fastSin()查找表来创建一个动画,其显示结果如图1-3所示。图1-3 在一个动画应用中使用的sine查找表

下面的代码调用fastSin()函数创建一个sine的查找表,保存在变量sinTable[]中。

下面的drawGraph()函数通过更新许多1像素宽的div的高度和位置,画出一个正弦波。表1-1列出了相关参数。表1-1 传递给drawGraph()的参数参  数描  述ang正弦波的开始角度freq正弦波的频率,定义了波的“紧密度”height正弦波的幅度,也影响画线的宽度

下面的循环创建480个1像素宽的div元素。这些div被添加到$drawTarget中。

drawGraph()函数通过bars[]数组来引用这些div。

setInterval()函数以连续变化的参数,重复调用drawGraph(),创造出动画效果:1.4.2 位操作、整数和二进制数

在JavaScript中,所有数都以浮点数形式表示。和C++和Java等语言不同,JavaScript语言中无法显示声明int和float类型。这个惊人的遗漏是由于JavaScript早期只是面向Web设计者和业余爱好者的简单语言。虽然JavaScript的单个数值类型帮程序员避免了许多数值类型错误,但毕竟整数更快,CPU更容易处理,在许多情况下是其他语言的首选数值类型。提示ECMAScript规范中定义JavaScript的数值表示为“双精

度64位的IEEE 754格式,即IEEE二进制浮点数算术标准”。

其表示范围很广,大约从大数(±1.797 693 134 862 315 7 308−324

× 10)到小数(±5×10)。不过需要注意的是:浮点

数是有误差的,比如alert(0.1+0.2)会显示0.300 000 000 000

000 04,而不是0.3。

不过,仔细阅读ECMAScript标准会发现JavaScript有几个内部操作可以处理整数:

ToInteger 

转为整数

ToInt32

转为有符号32位整数

ToUint32

转为无符号32位整数

ToUint16

转为无符号16位整数

你不能直接使用这些操作,而是在执行位操作时被自动调用,使得数字被预先转为合适的整型。虽然这些操作看起来和Web编程不相关,但实际上它们可用于优化。警告位操作将数字转为32位整数,数字范围为−2 147 483

648~2 147 483 647。超过这个范围的数字也会被调整到这

个范围。1.二进制数的快速回顾

曾几何时,程序员经常要与二进制数打交道。使用彼时计算机所需的底层编程要求对二进制和十六进制有很好的理解。如今,二进制数很少被用在Web编程,但在硬件驱动和网络等领域仍有一席之地。

每个人都熟悉十进制数系统。在表1-2的第一行,从右到左每列所表示的权重从小到大是10的幂。将第二行的数字和对应的权重乘起来,并将所有乘积相加,就得到了最终数字为:

(3×1 000) + (9×1) = 3 009表1-2 十进制数系统

10 0001 000100101

03009

二进制数系统也是类似的,不同的是每列的权重为2的幂,而不是10的幂。第二行中的数字只能是0或1,也称比特或位(bit)。二进制数简单的开关特性使其非常适合在数字电路中模拟。表1-3显示了十进制数69的二进制表示:(1 × 64) + (1 × 4) + (1 × 1) = 69表1-3 十进制数69的8位二进制数表示

1286432168421

01000101

二进制数如何取反?一般采用一个叫做补码的系统:

1.将二进制数中的每位取反,因此01000101变为10111010。

2.加1,因此10111010变为10111011(−69)。

最左边的比特叫做符号位,0代表正,1代表负。使用同样的步骤,我们可以从−69回到+ 69。2.JavaScript的位操作

JavaScript的位操作在整数的二进制数字(或位)上进行。

位与(x&y):对操作数进行二进制与的操作,如果两个操作数的某一位都为1,将对应的结果位设为1。因此0x0007&0x0003的结果为0x003。此操作可用于检查一个对象是否有一组属性或标记。表1-4显示了一个宠物对象的标记。一个小型、年老、棕色的狗可以用64 + 16 + 8 + 2 = 90来标记。表1-4 一个宠物对象的二进制标记大型小型年轻年老棕色白色狗猫1286432168421

搜索一个有特定标记的宠物,只需要和搜索值进行位与操作。下面的代码搜索大型、年轻和白色的宠物(猫狗都可以):

整型有32位来表示不同的标记,而相比之下其他方法,如分开表示标记或其他类型的条件测试,要慢许多。比如:

&运算符也可达到类似取余运算符(%)的效果,也就是返回除法后的余数。下面的代码将保证变量value总是在0到7之间:

不过这种等价性只有在&后面的值是2的幂−1(1,3,6,15,31,...)时才成立。

位或(x|y):对操作数进行二进制或的操作,如果两个操作数的某一位至少有一个为1,将对应的结果位设为1。因此0x0007|0x0003的结果为0x0007。

位异或(x^y):对操作数进行二进制异或的操作,如果两个操作的某一位只有一个为1,将对应的结果位设为1。因此0x0000^0x0001的结果是0x0001,而0x0001^0x0001的结果是0x0000。这可以用于方便地切换变量:

每次执行toggle^=1;,toggle值将在1和0值之间转换(假设原来的值是1或0)。下面是等价的if-else代码:

或者:

位非(~x):对所有位进行取反。例如11100111将变为00011000。如果操作数是有符号整数(最左位为符号位),则~操作符等于取负减1(前面提过补码中取负对应各位取反加1)。

位左移(x<

测试显示左移位运算和对应的乘法运算符(*)相比没有性能提升。

算术位右移(x>>numBits):对x的二进制向右移numBits位。除了(最左)符号位,所有位向右移,最右位丢失。这相当于有符号整数除法 x/2^numBits。例如:

测试显示右移位运算和对应的除法运算符(/)相比没有性能提升。

下面的代码看起来毫无用处:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载