html6高级程序设计

  • 时间:
  • 浏览:987
  • 来源:成都艾邦软件开发

内容简介

  本书首先介绍了HTML5 的历史背景、新的语义标签及与以往HTML 版本相比的根本变化同时揭示了HTML5 背后的设计原理。从第2 章起分别围绕构建令人神往的富Web 应用逐一讨论了HTML5 的Canvas、Geolocation 、Communication、WebSocket、Forms、Web Workers、Storage 等API 的使用 辅以直观明了的客户端和服务器端示例代码让开发人员能够迅速理解和掌握新一代Web 标准所涵盖的核心技术。本书最后探索了离线Web 应用并展望了HTML5 未来的发展前景。
  本书面向有一定经验的Web 应用开发人员对HTML5 及未来Web 应用技术发展抱有浓厚兴趣的读者也可以学习参考。

目录

第1章 HTML5概述

第2章 Canvas API

第3章 音频和视频

第4章 Geolocation API

第5章 Communication API

第6章 WebSockets API

第7章 Forms API

第8章 Web Workers API

第9章 Web Storage API

第10章 构建离线Web应用

第11章 HTML5未来展望

译者序

  尽管HTML5尚未正式发布但人们对它的关注却日益升温。各大技术资讯网站充斥着HTML5的新闻似乎不谈HTML5就已经落伍了。如果把这一切当成一种炒作的话那可就大错特错了Google、Opera、Apple、Mozilla等浏览器厂商频繁更新旗下浏览器产品添加对HTML5新特性的支持。连一向“偏执”的微软也积极推出了IE9 beta版开放下载。得益于各家浏览器的实践性反馈HTML5进入了快速良性发展的循环真可谓博观实践经验而约取厚积反馈优化而薄发。
  说起本书不能不提本书的三位作者Peter、Brian和Frank他们都是Web领域从业10年以上的资深技术专家其中Peter还曾经是一名荷兰×××特种部队的战士他们没有照搬HTML5规范流水账式地介绍API而是挑选最实用的HTML5技术结合示例引领读者循序渐进、由浅入深地畅游迷人的HTML5殿堂。
本书由山西移动的李杰猴子、FreeWheel的柳靖松鼠和百度的刘淼小猫协作翻译并由柳靖负责最终统稿、润色及审校。翻译过程亦是学习实践与总结提高的过程我们深感HTML5的博大精深并为作者深厚的功力所折服。
  感谢我们的家人和同伴感谢你们一如既往的支持包容我们在生活中的种种任性。
  感谢人民邮电出版社图灵公司的杨海玲、李松峰、杨爽和毛倩倩老师没有你们的信任与指导我们不可能在这么短的时间内完成本书的翻译。
  感谢中国移动通信集团山西有限公司IT规划建设中心的大力支持。赵文婧、李彬、王雪、王仲妮、高莹、赵华杰、李琦、阎丽娜、杨琳等同学为本书的出版倾注了大量的智慧和汗水。
  感谢FreeWheel北京研发中心为本书的付出一切技术难题在这里都会迎刃而解而良好的技术氛围和宽松的工作环境是译文完稿最可靠的技术保证。
  感谢百度商务搜索测试部你们对新技术的跟踪能力着实让人吃惊。
  由于时间仓促而且译者水平有限译文中难免会有错漏望广大同仁批评指正。
  仅以此译作献给在前端海洋中畅游的广大开发人员

猴子 松鼠 小猫
2010年10月27日于北京
 

第2章  Canvas API

  在本章中我们将探索如何使用HTML5的Canvas API。Canvas API很酷可以通过它来动态生成和展示图形、图表、图像以及动画。本章将使用渲染APIrendering API的基本功能来创建一幅可以放大缩小并自适应浏览器环境的图。还会演示如何基于用户输入来动态创建图像生成热点图。当然我们也会提醒你在使用HTML5 Canvas时需要注意的问题并且分享解决这些问题的方法。
  本章只涉及了最基本的图形知识因此你大可不必担心学不会而跳过本章。来吧让我们一起来感受HTML5中这个强大的特性吧。

2.1 HTML5 Canvas概述

  关于HTML5 Canvas API完全可以写一本书还不会是一本很薄的书。由于只有一章的篇幅所以我们将讨论API中那些我们认为是最常用的功能。
2.1.1 历史
  Canvas的概念最初是由苹果公司提出的用于在Mac OS X WebKit中创建控制板部件dashboard widget。在Canvas出现之前开发人员若要在浏览器中使用绘图API只能使用Adobe的Flash和SVGScalable Vector Graphics可伸缩矢量图形插件或者只有IE才支持的VMLVector Markup Language矢量标记语言以及其他一些稀奇古怪的JavaScript技巧。
  假设我们要在没有canvas元素的条件下绘制一条对角线——听起来似乎很简单但实际上如果没有一套二维绘图API的话这会是一项相当复杂的工作。HTML5 Canvas能够提供这样的功能对浏览器端来说此功能非常有用因此Canvas被纳入了HTML5规范。
  起初苹果公司曾暗示可能会为WHATWGWeb Hypertext Application Technology Working GroupWeb超文本应用技术工作组草案中的Canvas规范申请知识产权这在当时引起了一些Web标准化追随者的关注。不过苹果公司最终还是按照W3C的免版税专利权许可条款公开了其专利。

→SVG和CANVAS对比←

  “Canvas本质上是一个位图画布其上绘制的图形是不可缩放的不能像SVG图像那样可以被放大缩小。此外用Canvas绘制出来的对象不属于页面DOM结构或者任何命名空间——这点被认为是一个缺陷。SVG图像却可以在不同的分辨率下流畅地缩放并且支持点击检测能检测到鼠标点击了图像上的哪个点。
  既然如此为什么WHATWG的HTML5规范不使用SVG呢尽管Canvas有明显的不足但HTML Canvas API有两方面优势可以弥补首先不需要将所绘制图像中的每个图元当做对象存储因此执行性能非常好其次在其他编程语言现有的优秀二维绘图API的基础上实现Canvas API相对来说比较简单。毕竟二鸟在林不如一鸟在手。”
——Peter

2.1.2 canvas是什么
  在网页上使用canvas元素时它会创建一块矩形区域。默认情况下该矩形区域宽为300像素高为150像素但也可以自定义具体的大小或者设置canvas元素的其他特性。代码清单2-1是可放到HTML页面中的最基本的canvas元素。

―代码清单2-1 基本的canvas元素―

canvas/canvas

  在页面中加入了canvas元素后我们便可以通过JavaScript来自由地控制它。可以在其中添加图片、线条以及文字也可以在里面绘图甚至还可以加入高级动画。
  大多数主流操作系统和框架支持的二维绘制操作HTML5 Canvas API都支持。如果你在近年来曾经有过二维图像编程的经验那么会对HTML5 Canvas API感觉非常顺手因为这个API就是参照既有系统设计的。如果没有这方面经验则会发现与这么多年来一直使用的图片加CSS开发Web图形的方式比起来Canvas的渲染系统有多么强大。

  使用canvas编程首先要获取其上下文context。接着在上下文中执行动作最后将这些动作应用到上下文中。可以将canvas的这种编辑方式想象成为数据库事务开发人员先发起一个事务然后执行某些操作最后提交事务。
2.1.3 canvas坐标
  如图2-1所示canvas中的坐标是从左上角开始的x轴沿着水平方向按像素向右延伸y轴沿垂直方向向下延伸。左上角坐标为x0y0的点称作原点。
2.1.4 什么情况下不用canvas
  尽管canvas元素功能非常强大用处也很多但在某些情况下如果其他元素已经够用了就不应该再使用canvas元素。例如用canvas元素在HTML页面中动态绘制所有不同的标题就不如直接使用标题样式标签H1、H2等它们所实现的效果是一样的。
2.1.5 替代内容
  访问页面的时候如果浏览器不支持canvas元素或者不支持HTML5 Canvas API中的某些特性那么开发人员最好提供一份替代代码2.1.7节中的表2-1详细介绍了浏览器对canvas的支持情况。例如开发人员可以通过一张替代图片或者一些说明性的文字告诉访问者使用最新的浏览器可以获得更佳的浏览效果。代码清单2-2展示了如何在canvas中指定替代文本当浏览器不支持canvas的时候会显示这些替代内容。
代码清单2-2 在canvas元素中使用替代内容

canvas
  Update your browser to enjoy canvas!
/canvas

  除了上面代码中的文本外同样还可以使用图片不论是文本还是图片都会在浏览器不支持canvas元素的情况下显示出来。

→canvas元素的可访问性怎么样←

  “提供替代图像或替代文本引出了可访问性这个话题——很遗憾这是HTML5 Canvas规范中明显的缺陷。例如没有一种原生方法能够自动为已插入到canvas中的图片生成用于替换的文字说明。同样也没有原生方法可以生成替代文字以匹配由Canvas Text API动态生成的文字。在写本书的时候暂时还没有其他方法可以处理canvas中动态生成的内容不过已经有工作组开始着手这方面的设计了。让我们一起期待吧。”
——Peter

2.1.6 CSS和canvas
  同大多数HTML元素一样canvas元素也可以通过应用CSS的方式来增加边框设置内边距、外边距等而且一些CSS属性还可以被canvas内的元素继承。比如字体样式在canvas内添加的文字其样式默认同canvas元素本身是一样的。
  此外在canvas中为context设置属性同样要遵从CSS语法。例如对context应用颜色和字体样式跟在任何HTML和CSS文档中使用的语法完全一样。
2.1.7 浏览器对HTML5 Canvas的支持
  除了Internet Explorer以外其他所有浏览器现在都提供对HTML5 Canvas的支持。不过随后我们会列出一部分还没有被普遍支持的规范Canvas Text API 就是其中之一但是作为一个整体HTML5 Canvas规范已经非常成熟不会有特别大的改动了。从表2-1中可以看到写本书的时候已经有很多浏览器支持HTML5 Canvas了。
表2-1 浏览器对HTML5 Canvas的支持


  浏  览  器支持情况

  Chrome   从1.0版本开始支持

  Firefox   从1.5版本开始支持


  Internet Explorer   不支持

  Opera从9.0版本开始支持

  Safari从1.3版本开始支持

  从上面的表格中可以看出在所有浏览器中只有Internet Explorer不支持HTML5 Canvas。如果需要在Internet Explorer中使用canvas可选择使用名为explorercanvas的开源项目/p/explorercanvas。使用explorercanvas时需要先判断当前浏览器是否是Internet Explorer如果是则在页面中嵌入script标签来加载explorercanvas。写法如下

head
!--[if IE]script srcexcanvas.js/script![endif]--
/head

  开发者迫切希望Canvas可以受到广泛支持因此不断有项目启动来尝试解决老浏览器或者非标准浏览器不支持Canvas的问题。微软已经宣布Internet Explorer 9将支持canvas因此所有主流浏览器都支持canvas已经指日可待了。
  由于各家浏览器对canvas的支持程度有差异所以最好在使用API之前先测试一下HTML5 Canvas是否被支持。2.2.1节会讲解怎样通过代码来检测浏览器支持Canvas的情况。

2.2 使用HTML5 Canvas API

  本节将深入探讨HTML5 Canvas API。为此我们将使用各种HTML5 Canvas API创建一幅类似于LOGO的图像图像是森林场景有树还有适合长跑比赛的美丽跑道。虽然这个示例从平面设计的角度来看毫无竞争力但却可以合理演示HTML5 Canvas的各种功能。
2.2.1 检测浏览器支持情况
  在创建HTML5 canvas元素之前首先要确保浏览器能够支持它。如果不支持你就要为那些古董级浏览器提供一些替代文字。代码清单2-3就是检测浏览器支持情况的一种方法。

―代码清单2-3 检测浏览器支持情况―

try {
  document.createElement(canvas).getContext(2d);
  document.getElementById(support).innerHTML
HTML5 Canvas is supported in your browser.;
} catch (e) {
  document.getElementById(support).innerHTML HTML5 Canvas is not supported 
in your browser.;
}


  上面的代码试图创建一个canvas对象并且获取其上下文。如果发生错误则可以捕获错误进而得知该浏览器不支持canvas。页面中预先放入了ID为support的元素通过以适当的信息更新该元素的内容可以反映出浏览器的支持情况。
  以上示例代码能判断浏览器是否支持canvas元素但不会判断具体支持canvas的哪些特性。写本书的时候示例中使用的API已经很稳定并且各浏览器也都提供了很好的支持所以通常不必担心这个问题。
  此外希望开发人员能够像代码清单2-3一样为canvas元素提供备用显示内容。
2.2.2 在页面中加入canvas
  在HTML页面中插入canvas元素非常直观。代码清单2-4就是一段可以被插入到HTML页面中的canvas代码。

―代码清单2-4 canvas元素―

canvas height200 width200/canvas

  以上代码会在页面上显示出一块200×200像素的“隐藏”区域。假如要为其增加一个边框可以像代码清单2-5中的代码一样用标准CSS边框属性来设置。

―代码清单2-5 带实心边框的canvas元素―

canvas iddiagonal styleborder: 1px solid; width200 height200
/canvas

  注意上面的代码中增加了一个值为“diagonal”的ID特性这么做的意义在于以后的开发过程中可以通过ID来快速找到该canvas元素。对于任何canvas对象来说ID特性都是特别重要的因为对canvas元素的所有操作都是通过脚本代码控制的没有ID的话想要找到要操作的canvas元素会很难。
  代码清单2-5在浏览器中的执行效果如图2-2所示。
 


  看起来好像没什么但是就像那些艺术家说的一张白纸可以画出最新最美的图画。现在就让我们在这张“白纸”上作画吧。前面说过在没有HTML5 Canvas的情况下很难在页面上绘制一条对角线。现在我们来看看有了Canvas以后同样的事情会有多么简单。从代码清单2-6中可以看到基于上面绘制的画布仅仅使用几行代码就可以画出一条对角线。

―代码清单2-6 在canvas中绘制一条对角线―
 
script
function drawDiagonal() {
// 取得canvas元素及其绘图上下文
var canvas document.getElementById(diagonal);
var context canvas.getContext(2d);

//用绝对坐标来创建一条路径
context.beginPath();
context.moveTo(70, 140);
context.lineTo(140, 70);
 
// 将这条线绘制到canvas上
context.stroke();
}

window.addEventListener(load, drawDiagonal, true);
  /script

  仔细看一下上面这段绘制对角线的JavaScript代码。虽然简单它却展示出了使用HTML5 Canvas API的重要流程。
  首先通过引用特定的canvas ID值来获取对canvas对象的访问权。这段代码中ID就是diagonal。接着定义一个context变量调用canvas对象的getContext方法并传入希望使用的canvas类型。代码清单中通过传入“2d”来获取一个二维上下文这也是到目前为止唯一可用的上下文。

提示 规范未来的某个版本中可能会增加对三维上下文的支持。

  接下来基于这个上下文执行画线的操作。在代码清单中调用了三个方法——beginPath、moveTo和lineTo传入了这条线的起点和终点的坐标。
  方法moveTo和lineTo实际上并不画线而是在结束canvas操作的时候通过调用context.stroke()方法完成线条的绘制。图2-3显示了绘制结果。
 

 
  成功了虽然从这条简单的线段怎么也想象不到最新最美的图画不过与以前的拉伸图像、怪异的CSS和DOM对象以及其他怪异的实现形式相比使用基本的HTML技术在任意两点间绘制一条线段已经是非常大的进步了。从现在开始就把那些怪异的做法永远忘掉吧。
  从上面的代码清单中可以看出canvas中所有的操作都是通过上下文对象来完成的。在以后的canvas编程中也一样因为所有涉及视觉输出效果的功能都只能通过上下文对象而不是画布对象来使用。这种设计使canvas拥有了良好的可扩展性基于从其中抽象出的上下文类型canvas将来可以支持多种绘制模型。虽然本章经常提到对canvas采取什么样的操作但读者应该明白我们实际操作的是画布所提供的上下文对象。
  如前面示例演示的那样对上下文的很多操作都不会立即反映到页面上。beginPath、moveTo以及lineTo这些函数都不会直接修改canvas的展示结果。canvas中很多用于设置样式和外观的函数也同样不会直接修改显示结果。只有当对路径应用绘制stroke或填充fill方法时结果才会显示出来。否则只有在显示图像、显示文本或者绘制、填充和清除矩形框的时候canvas才会马上更新。
2.2.3 变换
  现在我们探讨一下在canvas上绘制图像的另一种方式——使用变换transformation。接下来的代码清单显示结果跟上面是一样的只是绘制对角线的代码不一样。这个简单示例可能会让你误认为使用变换增加了不必要的复杂性。事实并非如此其实变换是实现复杂canvas操作的最好方式。在后面的示例中将会看到我们使用了大量的变换而这对熟悉HTML5 Canvas API的复杂功能是至关重要的。
  也许了解变换最简单的方法至少这种方法不涉及大量的数学公式也不需手足并用地去解释就是把它当成是介于开发人员发出的指令和canvas显示结果之间的一个修正层modification layer。不管在开发中是否使用变换修正层始终都是存在的。
  修正——在绘制系统中的说法是变换——在应用的时候可以被顺序应用、组合或者随意修改。每个绘制操作的结果显示在canvas上之前都要经过修正层去做修正。虽然这么做增加了额外的复杂性但却为绘制系统添加了更为强大的功能可以像目前主流图像编辑工具那样支持实时图像处理所以API中这部分内容的复杂性是必要的。
  不在代码中调用变换函数并不意味着可以提升canvas的性能。canvas在执行的时候变换会被呈现引擎隐式调用这与开发人员是否直接调用无关。在接触最基本的绘制操作之前提前了解系统背后的原理至关重要。
  关于可重用代码有一条重要的建议一般绘制都应从原点坐标系中的0,0点开始应用变换缩放、平移、旋转等然后不断修改代码直至达到希望的效果。如图2-4所示。
  代码清单2-7展示了如何使用最简单变换方法——translate函数。
 

 
―代码清单2-7 用变换的方式在canvas上绘制对角线―

script
  function drawDiagonal() {
var canvas document.getElementById(diagonal);
var context canvas.getContext(2d);

// 保存当前绘图状态
context.save();

// 向右下方移动绘图上下文
context.translate(70, 140);

// 以原点为起点绘制与前面相同的线段
context.beginPath();
context.moveTo(0, 0);
context.lineTo(70, -70);
context.stroke();

// 恢复原有的绘图状态
context.restore();
  }

  window.addEventListener(load, drawDiagonal, true);
/script

  我们详细研究一下上面这段通过平移方式绘制对角线的JavaScript代码。
  (1) 首先通过ID找到并访问canvas对象。ID是diagonal。
  (2) 接着通过调用canvas对象的getContext函数获取上下文对象。
  (3) 接下来保存尚未修改的context这样即使进行了绘制和变换操作也可以恢复到初始状态。如果不保存那么在进行了平移和缩放等操作以后其影响会带到后续的操作中而这不一定是我们所希望的。在变换前保存context状态可以方便以后恢复。
  (4) 下一步是在context中调用translate函数。通过这个操作当平移行为发生的时候我们提供的变换坐标会被加到结果坐标对角线上结果就是将要绘制的对角线移动到了新的位置上。不过对角线呈现在canvas上是在绘制操作结束之后。
  (5) 应用平移后就可以使用普通的绘制操作来画对角线了。代码清单中调用了三个函数来绘制对角线——beginPath、moveTo以及lineTo。绘制的起点是原点0,0而非坐标点70,140。
  (6) 在线条勾画出来之后可以通过调用context.stroke()函数将其显示在canvas上。
  (7) 最后恢复context至原始状态这样后续的canvas操作就不会被刚才的平移操作影响了。图2-5显示了用这段代码绘制的对角线。
  虽然新绘制的对角线看起来跟前面的一模一样但这次绘制使用了强大的变换功能。学习完本章接下来的内容就会明白变换的强大之处。
2.2.4 路径
  关于绘制线条我们还能提供很多有创意的方法。不过现在应该进一步学习稍复杂点的图形路径。HTML5 Canvas API中的路径代表你希望呈现的任何形状。本章对角线示例就是一条路径你可能已经注意到了代码中调用beginPath就说明是要开始绘制路径了。实际上路径可以要多复杂有多复杂多条线、曲线段甚至是子路径。如果想在canvas上绘制任意形状那么你需要重点关注路径API。
  按照惯例不论开始绘制何种图形第一个需要调用的就是beginPath。这个简单的函数不带任何参数它用来通知canvas将要开始绘制一个新的图形了。对于canvas来说beginPath函数最大的用处是canvas需要据此来计算图形的内部和外部范围以便完成后续的描边和填充。
  路径会跟踪当前坐标默认值是原点。canvas本身也跟踪当前坐标不过可以通过绘制代码来修改。
  调用了beginPath之后就可以使用context的各种方法来绘制想要的形状了。到目前为止我们已经用到了几个简单的context路径函数。
  moveTo(x, y)不绘制只是将当前位置移动到新的目标坐标(x,y)。
  lineTo(x, y)不仅将当前位置移动到新的目标坐标(x,y)而且在两个坐标之间画一条直线。
  简而言之上面两个函数的区别在于moveTo就像是提起画笔移动到新位置而lineTo告诉canvas用画笔从纸上的旧坐标画条直线到新坐标。不过再次提醒一下不管调用它们哪一个都不会真正画出图形因为我们还没有调用stroke或者fill函数。目前我们只是在定义路径的位置以便后面绘制时使用。
  下一个特殊的路径函数叫做closePath。这个函数的行为同lineTo很像唯一的差别在于closePath会将路径的起始坐标自动作为目标坐标。closePath还会通知canvas当前绘制的图形已经闭合或者形成了完全封闭的区域这对将来的填充和描边都非常有用。
  此时可以在已有的路径中继续创建其他的子路径或者随时调用beginPath重新绘制新路径并完全清除之前的所有路径。
  跟了解所有复杂系统一样最好的方式还是实践。现在我们先不管那些线条的例子使用HTML5 Canvas API开始创建一个新场景——带有长跑跑道的树林。权且把这个图案当成是我们长跑比赛的标志吧。同其他的画图方式一样我们将从基本元素开始。在这幅图中松树的树冠最简单。代码清单2-8演示了如何在canvas上绘制一颗松树的树冠。

―代码清单2-8 用于绘制树冠轮廓的函数―

function createCanopyPath(context) {
  // 绘制树冠
  context.beginPath();

  context.moveTo(-25, -50);
  context.lineTo(-10, -80);
  context.lineTo(-20, -80);
  context.lineTo(-5, -110);
  context.lineTo(-15, -110);

  // 树的顶点
  context.lineTo(0, -140);

  context.lineTo(15, -110);
  context.lineTo(5, -110);
  context.lineTo(20, -80);
  context.lineTo(10, -80);
  context.lineTo(25, -50);

  // 连接起点闭合路径
  context.closePath();
}

  从上面的代码中可以看到我们用到的仍然是前面用过的移动和画线命令只不过调用次数多了一些。这些线条表现的是树冠的轮廓最后我们闭合了路径。我们为这棵树的底部留出了足够的空间后面几节将在这里的空白处画上树干。代码清单2-9演示如何使用树冠绘制函数将树的简单轮廓呈现到canvas上。

―代码清单2-9 在canvas上画树的函数―

function drawTrails() {
  var canvas document.getElementById(trails);
  var context canvas.getContext(2d);

  context.save();
  context.translate(130, 250);

  // 创建表现树冠的路径
  createCanopyPath(context);

  // 绘制当前路径
  context.stroke();
  context.restore();
}

  这段代码中所有的调用想必大家已经很熟悉了。先获取canvas的上下文对象保存以便后续使用将当前位置变换到新位置画树冠绘制到canvas上最后恢复上下文的初始状态。图2-6展示了我们的绘画技艺一条简单的闭合路径表现了树冠。以后我们会详细扩展这段代码现在算是一个好的开始。
 

 
2.2.5 描边样式
  如果开发人员只能绘制直线而且只能使用黑色HTML5 Canvas API就不会如此强大和流行。下面我们就使用描边样式让树冠看起来更像是树。代码清单2-10展示了一些基本命令其功能是通过修改context的属性让绘制的图形更好看。

―代码清单2-10 使用描边样式―

// 加宽线条
context.lineWidth 4;

// 平滑路径的接合点
context.lineJoin round;

// 将颜色改成棕色
context.strokeStyle #663300;

// 最后绘制树冠
context.stroke();

  设置上面的这些属性可以改变以后将要绘制的图形外观这个外观起码可以保持到我们将context恢复到上一个状态。
  首先我们将线条宽度加粗到4像素。
  接着我们将lineJoin属性设置为round这是修改当前形状中线段的连接方式让拐角变得更圆滑也可以把lineJoin属性设置成bevel或者miter相应的context.miterLimit值也需要调整来变换拐角样式。
  最后通过strokeStyle属性改变了线条的颜色。在这个例子中我们使用了CSS值来设置颜色不过在后面几节中我们将看到strokeStyle的值还可以用于生成特殊效果的图案或者渐变色。
  还有一个没有用到的属性——lineCap可以把它的值设置为butt、square或者round以此来指定线条末端的样式。哦示例中的线是闭合的没有端点。图2-7就是我们加工过的树冠与之前扁平的黑线相比现在是一条更粗、更平滑的棕色线条。
 

 2.2.6 填充样式
  正如你所期望的那样能影响canvas的图形外观的并非只有描边另一个常用于修改图形的方法是指定如何填充其路径和子路径。从代码清单2-11中可以看到用宜人的绿色填充树冠有多么简单。

―代码清单2-11 使用填充样式―

// 将填充色设置为绿色并填充树冠
context.fillStyle #339900;
context.fill();

  首先我们将fillStyle属性设置成合适的颜色。在后面我们将看到还可以使用渐变色或者图案填充。然后只要调用context的fill函数就可以让canvas对当前图形中所有的闭合路径内部的像素点进行填充。结果如图2-8所示。
 

   由于我们是先描边后填充因此填充会覆盖一部分描边路径。我们示例中的路径是4像素宽这个宽度是沿路径线居中对齐的而填充是把路径轮廓内部所有像素全部填充所以会覆盖描边路径的一半。如果希望看到完整的描边路径可以在绘制路径调用context.stroke()之前填充调用context.fill()。
2.2.7 填充矩形区域
  每棵树都有一个强壮的树干。我们在原始图形中为树干预留了足够的空间。从代码清单2-12中可以看到通过fillRect函数可以画出树干。

―代码清单2-12 调用fillRect函数―

// 将填充色设为棕色
context.fillStyle #663300;

// 填充用作树干的矩形区域
context.fillRect(-5, -50, 10, 50);

  在上面的代码中再次将棕色作为填充颜色。不过跟上次不一样的是我们不用lineTo功能显式画树干的边角而是使用fillRect一步到位画出整个树干。调用fillRect并设置x、y两个位置参数和宽度、高度两个大小参数随后Canvas会马上使用当前的样式进行填充。
  虽然示例中没有用到但与之相关的函数还有strokeRect和clearRect。strokeRect的作用是基于给出的位置和坐标画出矩形的轮廓clearRect的作用是清除矩形区域内的所有内容并将它恢复到初始状态即透明色。

→canvas动画←

  “在HTML5 Canvas API中canvas的清除矩形功能是创建动画和游戏的核心功能。通过反复绘制和清除canvas片段就可能实现动画效果互联网上有很多这样的例子。但是如果希望创建运行起来比较流畅的动画就需要使用剪裁clipping 功能了有可能还需要二次缓存canvas以便最小化由于频繁的清除动作而导致的画面闪烁。本书中不会专门讲解动画我们鼓励大家自己探索学习。”——Brain

  图2-9显示的是基于树冠图形添加的、一次填充的树干。
 

 
2.2.8 绘制曲线
  这个世界特别是自然界并不是只有直线和矩形。canvas提供了一系列绘制曲线的函数。我们将用最简单的曲线函数——二次曲线来绘制我们的林荫小路。代码清单2-13演示了如何添加两条二次曲线。

―代码清单2-13 绘制曲线―

// 保存canvas的状态并绘制路径
context.save();

context.translate(-10, 350);
context.beginPath();

// 第一条曲线向右上方弯曲
context.moveTo(0, 0);
context.quadraticCurveTo(170, -50, 260, -190);

// 第二条曲线向右下方弯曲
context.quadraticCurveTo(310, -250, 410,-250);

// 使用棕色的粗线条来绘制路径
context.strokeStyle #663300;
context.lineWidth 20;
context.stroke();

// 恢复之前的canvas状态
context.restore();

  跟以前一样第一步要做的事情是保存当前canvas的context状态因为我们即将变换坐标系并修改轮廓设置。要画林荫小路首先要把坐标恢复到修正层的原点向右上角画一条曲线。
  从图2-10中可以看到quadraticCurveTo函数绘制曲线的起点是当前坐标带有两组x,y参数。第二组是指曲线的终点。第一组代表控制点control point。所谓的控制点位于曲线的旁边不是曲线之上其作用相当于对曲线产生一个拉力。通过调整控制点的位置就可以改变曲线的曲率。在右上方再画一条一样的曲线以形成一条路。然后像之前描边树冠一样把这条路绘制到canvas上只是线条更粗了。
  HTML5 Canvas API的其他曲线功能还涉及bezierCurveTo、arcTo和arc函数。这些函数通过多种控制点如半径、角度等让曲线更具可塑性。图2-11显示了绘制在canvas上的两条曲线看起来就像是穿过树林的小路一样。
 

 2.2.9 在canvas中插入图片
  在canvas中显示图片非常简单。可以通过修正层为图片添加印章、拉伸图片或者修改图片等并且图片通常会成为canvas上的焦点。用HTML5 Canvas API内置的几个简单命令可以轻松地为canvas添加图片内容。
  不过图片增加了canvas操作的复杂度必须等到图片完全加载后才能对其进行操作。浏览器通常会在页面脚本执行的同时异步加载图片。如果试图在图片未完全加载之前就将其呈现到canvas上那么canvas将不会显示任何图片。因此开发人员要特别注意在呈现之前应确保图片已经加载完毕。
  我们的示例将加载一张树皮纹理的图片作为树干以供canvas使用。为保证在呈现之前图片已完全加载我们提供了回调即仅当图像加载完成时才执行后续代码如代码清单2-14所示。

―代码清单2-14 加载图像―

// 加载图片bark.jpg
var bark new Image();
bark.src bark.jpg;

// 图片加载完成后将其显示在canvas上
bark.onload function () {
  drawTrails();
}
  从上面的代码中可以看到我们为bark.jpg图片添加了onload处理函数以保证仅在图像加载完成时才调用主drawTrails函数。这样做可以保证后续的调用能够把图片正常显示出来如代码清单2-15所示。

―代码清单2-15 在canvas上显示图像―

// 用背景图案填充作为树干的矩形
context.drawImage(bark, -5, -50, 10, 50);

  在这段代码里我们用纹理贴图替换了之前调用fillRect函数的填充来作为新的树干。尽管替换的动作很小但canvas上显示出来的树干更有质感。注意在drawImage函数中除了图片本身外还指定了x、y、width和height参数。这些参数会对贴图进行调整以适应预定的10×50像素树干区域。我们还可以把原图的尺寸传进来以便在裁切区域内对图片进行更多控制。

 
  在图2-12中可以看到同之前用矩形填充的方式相比树干的变化不大。
2.2.10 渐变
  对树干还是不满意其实我也是。我们使用另一种可以让树干变得稍微好看点的绘制方法渐变。渐变是指在颜色集上使用逐步抽样算法并将结果应用于描边样式和填充样式中。使用渐变需要三个步骤
  (1) 创建渐变对象
  (2) 为渐变对象设置颜色指明过渡方式
  (3) 在context上为填充样式或者描边样式设置渐变。
  可以将渐变看做是颜色沿着一条线进行缓慢地变化。例如如果为渐变对象提供了A、B两个点不论是绘制还是填充只要从A移动到B都会带来颜色的变化。
  要设置显示哪种颜色在渐变对象上使用addColorStop函数即可。这个函数允许指定两个参数颜色和偏移量。颜色参数是指开发人员希望在偏移位置描边或填充时所使用的颜色。偏移量是一个0.0到1.0之间的数值代表沿着渐变线渐变的距离有多远。
  假如要建立一个从点(0,0)到点(0,100)的渐变并指定在0.0偏移位置使用白色在1.0偏移位置使用黑色。当使用绘制或者填充的动作从(0,0)画到(0,100)后就可以看到颜色从白色起始位置渐渐转变成了黑色终止位置。
  除了可以变换成其他颜色外还可以为颜色设置alpha值例如透明并且alpha值也是可以变化的。为了达到这样的效果需要使用颜色值的另一种表示方法例如内置alpha组件的CSS rgba函数。
  下面我们通过示例来详细了解如何使用两个渐变来填充相应的函数为fillRect矩形区域并形成最终的树干见代码清单2-16。

―代码清单2-16 使用渐变―

// 创建用作树干纹理的三阶水平渐变
var trunkGradient context.createLinearGradient(-5, -50, 5, -50);

// 树干的左侧边缘是一般程度的棕色
trunkGradient.addColorStop(0, #663300);

// 树干中间偏左的位置颜色要淡一些
trunkGradient.addColorStop(0.4, #996600);

// 树干右侧边缘的颜色要深一些
trunkGradient.addColorStop(1, #552200);

// 使用渐变色填充树干
context.fillStyle trunkGradient;
context.fillRect(-5, -50, 10, 50);

// 接下来创建垂直渐变以用作树冠在树干上投影
var canopyShadow context.createLinearGradient(0, -50, 0, 0);

// 投影渐变的起点是透明度设为50%的黑色
canopyShadow.addColorStop(0, rgba(0, 0, 0, 0.5));

// 方向垂直向下渐变色在很短的距离内迅速渐变至完全透明这段长度之外的树干上没有投影
canopyShadow.addColorStop(0.2, rgba(0, 0, 0, 0.0));

// 在树干上填充投影渐变
context.fillStyle canopyShadow;
context.fillRect(-5, -50, 10, 50);

  如图2-13所示使用了两个渐变后最终绘制出来的树干有了平滑的光照效果。现在树干看起来更平滑同时树干上也有了轻微的阴影效果。我们把这幅图保存起来吧。
 

 
  除了我们刚才用到的线性渐变以外HTML5 Canvas API还支持放射性渐变所谓放射性渐变就是颜色会介于两个指定圆间的锥形区域平滑变化。放射性渐变和线性渐变使用的颜色终止点是一样的不过参数如代码清单2-17所示。

―代码清单2-17 使用放射性渐变的示例―

createRadialGradient(x0, y0, r0, x1, y1, r1)

  代码中前三个参数代表以(x0,y0)为圆心r0为半径的圆后三个参数代表以(x1,y1)为圆心r1为半径的另一个圆。渐变会在两个圆中间的区域出现。
2.2.11 背景图
  直接绘制图像有很多用处但在某些情况下像CSS那样使用图片作为背景也非常有用。我们已经了解了如何使用加粗的颜色描边和填充。在描边和填充的时候HTML5 Canvas API还支持图片平铺。
  现在我们把林荫小路变得崎岖一点。这次不再对曲线跑道进行描边而是使用背景图片填充的方法。为了达到预想的效果我们将已经作废的树干图片我们已经有了“渐变”树干替换成砾石图片。我们将调用createPattern函数来替代之前的drawImage函数如代码清单2-18所示。

―代码清单2-18 使用背景图片―

// 加载砾石背景图
var gravel new Image();
gravel.src gravel.jpg;
gravel.onload function () {
drawTrails();
}

// 用背景图替代棕色粗线条
context.strokeStyle context.createPattern(gravel, repeat);
context.lineWidth 20;
context.stroke();

  从上面的代码中可以看到绘制的时候还是使用stroke()函数只不过这次我们先设置了context上的strokeStyle属性把调用context.createPattern的返回值赋给该属性。再次强调一下图片必须提前加载完毕以便canvas执行后续操作。context.createPattern的第二个参数是重复性标记可以在表2-2中选择合适的值。
表2-2 重复性参数

平铺方式 意  义

repeat默认值图片会在两个方向平铺

repeat-x横向平铺

repeat-y纵向平铺

no-repeat图片只显示一次不平铺

 
  图2-14显示了应用背景图片方式画出的小路。
 

2.2.12 缩放canvas对象
  树林里怎么可能只有一棵树呢现在我们来解决这个问题。为简单起见我们计划把示例代码中用于绘制树的操作独立出来当做一个单独的例程称为drawTree见代码清单2-19。

―代码清单2-19 绘制树对象的函数―

// 创建树对象绘制函数以便重用
function drawTree(context) {
  var trunkGradient context.createLinearGradient(-5, -50, 5, -50);
  trunkGradient.addColorStop(0, #663300);
  trunkGradient.addColorStop(0.4, #996600);
  trunkGradient.addColorStop(1, #552200);
  context.fillStyle trunkGradient;
  context.fillRect(-5, -50, 10, 50);

  var canopyShadow context.createLinearGradient(0, -50, 0, 0);
  canopyShadow.addColorStop(0, rgba(0, 0, 0, 0.5));
  canopyShadow.addColorStop(0.2, rgba(0, 0, 0, 0.0));
  context.fillStyle canopyShadow;
  context.fillRect(-5, -50, 10, 50);

  createCanopyPath(context);
  context.lineWidth 4;
  context.lineJoin round;
  context.strokeStyle #663300;
  context.stroke();

  context.fillStyle #339900;
  context.fill();
}

  可以看到drawTree函数包括了之前绘制树冠、树干和树干渐变的所有代码。为了在新的位置画出大一点的树我们将使用另一种变换方式——缩放函数context.scale如代码清单2-20所示。

―代码清单2-20 绘制树对象―

// 在(130,250)的位置绘制第一棵树
context.save();
context.translate(130, 250);
drawTree(context);
context.restore();

// 在(260,500)的位置绘制第二棵树
context.save();
context.translate(260, 500);

// 将第二棵树的宽高分别放大至原来的2倍
context.scale(2, 2);
drawTree(context);
context.restore();

  scale函数带有两个参数来分别代表在x、y两个维度的值。每个参数在canvas显示图像的时候向其传递在本方向轴上图像要放大或者缩小的量。如果x值为2就代表所绘制图像中全部元素都会变成两倍宽如果y值为0.5绘制出来的图像全部元素都会变成之前的一半高。使用这些函数就可以很方便的在canvas上创建出新的树如图2-15所示。
 

→始终在原点执行图形和路径的变换操作←

  “示例中演示了为什么要在原点执行图形和路径的变换操作执行完后再统一平移。理由就是缩放scale和旋转rotate等变换操作都是针对原点进行的。
  如果对一个不在原点的图形进行旋转变换那么rotate变换函数会将图形绕着原点旋转而不是在原地旋转。与之类似如果进行缩放操作时没有将图形放置到合适的坐标上那么所有路径坐标都会被同时缩放。取决于缩放比例的大小新的坐标可能会全部超出canvas范围进而给开发人员带来困惑为什么我的缩放操作会把图像删了”
——Brian

2.2.13 Canvas变换
  变换操作并不限于缩放和平移我们可以使用函数context.rotate(angle)来旋转图像甚至可以直接修改底层变换矩阵以完成一些高级操作如剪裁图像的绘制路径。如果想旋转图像只需执行代码清单2-21所示的一系列操作即可。

―代码清单2-21 旋转图像―

context.save();

// 旋转角度参数以弧度为单位
context.rotate(1.57);
context.drawImage(myImage, 0, 0, 100, 100);

context.restore();

  在代码清单2-22中我们将演示如何对路径坐标进行随意变换以从根本上改变现有树的路径显示并最终创建一个阴影效果。

―代码清单2-22 一种变换的使用方法―

// 创建用于填充树干的三阶水平渐变色
// 保存canvas的当前状态
context.save();

// X值随着Y值的增加而增加借助拉伸变换可以创建一棵用作阴影的倾斜的树
context.transform(1, 0, -0.5, 1, 0, 0);

// 在Y轴方向将阴影的高度压缩为原来的60%
context.scale(1, 0.6);

// 使用透明度为20%的黑色填充树干
context.fillStyle rgba(0, 0, 0, 0.2);
context.fillRect(-5, -50, 10, 50);

// 使用已有的阴影效果重新绘制树
createCanopyPath(context);
context.fill();

// 恢复之前的canvas状态
context.restore();

  你可以像上面那样直接修改context变换矩阵前提是要熟悉二维绘图系统中的矩阵变换。分析这种变换背后的数学含义可以看出我们通过调整与Y轴值相对应的参数改变了X轴的值这样做目的是为了拉伸出一棵灰色的树做阴影。接下来我们按照60%的比例将剪裁出的树缩小到了合适的尺寸。
  注意剪裁过的“阴影”树会先被显示出来这样一来真正的树就会按照Z轴顺序canvas中对象的重叠顺序显示在阴影的上面。此外树影的填充用到了CSS的RGBA特性通过特性我们将透明度值设为正常情况下的20%。至此带有半透明效果的树影就做好了。将其应用于已经缩放过的树上效果如图2-16所示。
2.2.14 Canvas文本
  在作品即将完成之际我们要在图像的上部添加一个别致的标题以此来向大家演示HTML5 Canvas API强大的文本功能。需要特别注意的是操作canvas文本的方式与操作其他路径对象的方式相同可以描绘文本轮廓和填充文本内部同时所有能够应用于其他图形的变换和样式都能用于文本。
  context对象的文本绘制功能由两个函数组成
  fillText(text,x, y,maxwidth)
  strokeText(text,x,y,maxwidth)
  两个函数的参数完全相同必选参数包括文本参数以及用于指定文本位置的坐标参数。maxwidth是可选参数用于限制字体大小它会将文本字体强制收缩到指定尺寸。此外还有一个measureText函数可供使用该函数会返回一个度量对象其中包含了在当前context环境下指定文本的实际显示宽度。
  为了保证文本在各浏览器下都能正常显示Canvas API为context提供了类似于CSS的属性以此来保证实际显示效果的高度可配置。如表2-3。

表2-3 文本呈现相关的context属性

属  性 值备  注

font CSS字体字符串例如italic Arialscan-serif

textAlign start、end、left、right、center默认是start

textBaseline top、hanging、middle、alphabetic、ideographic、bottom 默认是alphabetic

  对上面这些context属性赋值能够改变context而访问context属性可以查询到其当前值。在代码清单2-23中我们首先创建了一段使用Impact字体的大字号文本然后使用已有的树皮图片作为背景进行填充。为了将文本置于canvas的上方并居中我们定义了最大宽度和center居中对齐方式。

―代码清单2-23 使用canvas文本―

// 在canvas上绘制标题文本
context.save();

// 字号为60px字体为impact
context.font 60px impact;

// 将文本填充为棕色
context.fillStyle #996600;
// 将文本设为居中对齐
context.textAlign center;

// 在canvas顶部中央的位置以大字体的形式显示文本
context.fillText(Happy Trails!, 200, 60, 400);
context.restore();

  结果如图2-17所示林间小路的美景马上就增添了几分欢快的味道。

2.2.15 应用阴影
  最后我们将使用内置的Canvas Shadow API为文本添加模糊阴影效果。虽然我们能够通过HTML5 Canvas API将阴影效果应用于之前执行的任何操作中但与很多图形效果的应用类似阴影效果的使用也要把握好“度”。
  可以通过几种全局context属性来控制阴影见表2-4。

表2-4 阴影属性

属  性  值备  注

shadowColor 任何CSS中的颜色值可以使用透明度alpha

ShadowOffsetX 像素值值为正数向右移动阴影值为负数向左移动阴影

shadowOffsetY 像素值值为正数向下移动阴影值为负数向上移动阴影

shadowBlur高斯模糊值值越大阴影边缘越模糊

  shadowColor或者其他任意一项属性的值被赋为非默认值时路径、文本和图片上的阴影效果就会被触发。代码清单2-24显示了如何为文本添加阴影效果。

―代码清单2-24 应用阴影效果―

// 设置文字阴影的颜色为黑色透明度为20%
context.shadowColor rgba(0, 0, 0, 0.2);

// 将阴影向右移动15px向上移动10px
context.shadowOffsetX 15;
context.shadowOffsetY -10;

// 轻微模糊阴影
context.shadowBlur 2;

  执行上述代码后canvas渲染器会自动应用阴影效果直到恢复canvas状态或者重置阴影属性。添加阴影后的效果如图2-18所示。
 

 
  如你所见由CSS生成的阴影只有位置上的变化而无法与变换生成的阴影树影保持同步。为了一致起见在canvas上绘制阴影时应该尽量只用一种方法。
2.2.16 像素数据
  Canvas API最有用的特性之一是允许开发人员直接访问canvas底层像素数据。这种数据访问是双向的一方面可以以数值数组形式获取像素数据另一方面可以修改数组的值以将其应用于canvas。实际上放弃本章之前讨论的渲染调用也可以通过直接调用像素数据的相关方法来控制canvas。这要归功于context API内置的三个函数。
  第一个是context.getImageData(sx, sy, sw, sh)。这个函数返回当前canvas状态并以数值数组的方式显示。具体来说返回的对象包括三个属性。
  width每行有多少个像素。
  height每列有多少个像素。
  data一维数组存有从canvas获取的每个像素的RGBA值。该数组为每个像素保存了四个值——红、绿、蓝和alpha透明度。每个值都在0到255之间。因此canvas上的每个像素在这个数组中就变成了四个整数值。数组的填充顺序是从左到右从上到下也就是先第一行再第二行依此类推如图2-19所示。
 

 
  getImageData函数有四个参数该函数只返回这四个参数所限定的区域内的数据。只有被x、y、width和height四个参数框定的矩形区域内的canvas上的像素才会被取到因此要想获取所有像素数据就需要这样传入参数getImageData(0, 0, canvas.width, canvas.height)。
  因为每个像素由四个图像数据表示所以要计算指定的像素点对应的值是什么就有点头疼。不要紧下面有公式。
  在给定了width和height的canvas上在坐标(x ,y)上的像素的构成如下。
  红色部分((width * y) x) * 4
  绿色部分((width * y) x) * 4 1
  蓝色部分((width * y) x) * 4 2
  透明度部分((width * y) x) * 4 3
  一旦可以通过像素数据的方式访问对象就可以通过数学方式轻松修改数组中的像素值因为这些值都是从0到255的简单数字。修改了任何像素的红、绿、蓝和alpha值之后可以通过第二个函数来更新canvas上的显示那就是context.putImageData(p_w_picpathdata, dx, dy)。
  putImageData允许开发人员传入一组图像数据其格式与最初从canvas上获取来的是一样的。这个函数使用起来非常方便因为可以直接用从canvas上获取数据加以修改然后返回。一旦这个函数被调用所有新传入的图像数据值就会立即在canvas上更新显示出来。dx和dy参数可以用来指定偏移量如果使用则该函数就会跳到指定的canvas位置去更新显示传进来的像素数据。
  最后如果想预先生成一组空的canvas数据则可调用context.createImageData(sw, sh)这个函数可以创建一组图像数据并绑定在canvas对象上。这组数据可以像先前那样处理只是在获取canves数据时这组图像数据不一定会反映canvas的当前状态。
2.2.17 Canvas的安全机制
  上面讨论了直接操纵像素数据的方法在这里有必要重点提醒一下大多数开发者都会合法使用像素数据操作。尽管如此还是会有人出于某些邪恶的目的利用这种从canvas直接获取并且修改数据的能力。出于这个原因origin-clean canvas的概念应运而生换句话说如果canvas中的图片并非来自包含它的页面所在的域页面中的脚本将不能取得其中的数据。
  如图2-20所示如果来自的页面包含canvas元素那么页面中的代码完全有可能在canvas里面呈现来自的图片。毕竟在任何Web页面中显示其他远程网站的图片都是完全可接受的。
 
  然而在没有Canvas API以前无法使用编程的方式获取下载图片的像素信息。来自其他网站的私有图片可以显示在本地但无法被读取或者复制。如果允许脚本读取本地之外的图像数据那么整个网络中的用户照片以及其他敏感的在线图片文档将被“无限制地共享”。
  为了避免如此在getImageData函数被调用的时候如果canvas中的图像来自其他域就会抛出安全异常。这样的话只要不获取显示着其他域中图片的canvas的数据那么就可以随意呈现这些远程图片。在开发的过程中要注意这个限制条件使用安全的渲染方式。

2.3 使用HTML5 Canvas创建应用

  使用Canvas API可以创建许多种应用图形、图表、图片编辑等然而最奇妙的一个应用是修改或者覆盖已有内容。最流行的覆盖图被称为热点图。虽然热点图听起来是度量温度的意思不过这里的热度可以用于任何可测量的活动。地图上活跃程度高的部分使用暖色标记例如红色、×××或白色活跃程度低的部分不显示颜色变化或者显示浅浅的黑色或灰色。
  举个例子热点图可以用在城市地图上来标记交通路况或者在世界地图上显示风暴的活动情况。在HTML5中这些应用都非常容易实现只需要将canvas叠放在地图上显示即可。实际上就是用canvas覆盖地图然后再基于相应的活动数据绘制出不同的热度级别。
  现在我们使用已经学过的Canvas API知识来绘制一个简单的热点图。这个示例中热度数据不是来源于外部而是来源于我们的鼠标在地图上的移动情况。鼠标移动到某个区域会使这个区域的“热度”增加。将鼠标放在特定区域不动会让该区域“温度”迅速增长至极限。为了示范我们将在一个“难以名状”的地图上进行热点图的覆盖演示见图2-21。
 

   上面看到的是热点图应用的最终效果下面我们深入分析实现代码。和往常一样你可以在线查看或下载示例的源代码。
  这份源码中我们从HTML元素开始分析。为了演示效果这个HTML中只包含了标题Heatmap、画布和按钮Reset用来复位热点图。canvas上显示的背景图片文件是mapbg.jpg通过代码清单2-25中的CSS代码应用到canvas中。

―代码清单2-25 热点图的canvas元素―

style typetext/css
  #heatmap {
background-p_w_picpath: url(mapbg.jpg);
  }
/style

h2Heatmap /h2
canvas idheatmap classclear styleborder: 1px solid ; height300?
 width300 /canvas
button idresetButtonReset/button

  我们还声明了一些变量然后对其进行了初始化以备后用。

var points {};
var SCALE 3;
var x -1;
var y -1;

  接下来为了支持全局绘制操作我们将为canvas设置一个高透明值并且设置为混合模式让新的绘制操作点亮底层的像素而不是替换它们。
  然后如代码清单2-26所示我们会设置addToPoint函数在鼠标移动的时候或者每隔1/10 s的时间调用它以改变显示效果。

―代码清单2-26 loadDemo函数―

function loadDemo() {
  document.getElementById(resetButton).onclick reset;

  canvas document.getElementById(heatmap);
  context canvas.getContext(2d);
  context.globalAlpha 0.2;
  context.globalCompositeOperation lighter

function sample() {
  if (x ! -1) {
addToPoint(x,y)
  }
  setTimeout(sample, 100);
}

canvas. function(e) {
  x e.clientX - e.target.offsetLeft;
  y e.clientY - e.target.offsetTop;
  addToPoint(x,y);
}

  sample();
}

  使用canvas的clearRect函数就可以让用户在点击Reset按钮的时候将整个canvas区域清空并重置回原始状态见代码清单2-27。

―代码清单2-27 reset函数―

function reset() {
  points {};
  context.clearRect(0,0,300,300);
  x -1;
  y -1;
}
  接下来我们建立一张颜色查找表以便在canvas上执行绘制操作的时候使用。代码清单2-28中列出了颜色亮度由低到高的范围不同的颜色值会被用来代表各种不同的热度。intensity的值越大返回的颜色越亮。

―代码清单2-28 getColor函数―

function getColor(intensity) {
  var colors [#072933, #2E4045, #8C593B, #B2814E, #FAC268, #FAD237];
  return colors[Math.floor(intensity/2)];
}

  不管什么时候只要鼠标移过或者悬停在canvas的某个区域就会有一个点被绘制出来。鼠标在特定区域中停留的时间越长这个点就越大同时越亮。像代码清单2-29中所示使用context.arc函数根据特定的半径值绘制圆通过传到getColor函数中的半径值来判断半径越大画出的圆越亮、颜色越热。

―代码清单2-29 drawPoint函数―

function drawPoint(x, y, radius) {
  context.fillStyle getColor(radius);
  radius Math.sqrt(radius)*6;

  context.beginPath();
  context.arc(x, y, radius, 0, Math.PI*2, true);

  context.closePath();
  context.fill();
}

  在addToPoint函数中每次鼠标移动或者悬停的时候都会调用这个函数canvas特定点上的热度值会升高并保存下来。代码清单2-30中显示了最高的热度值是10。给定像素点的当前热度值一旦被检测到那么相应的像素以及相关的热度、半径值就会被传递到drawPoint函数中。

―代码清单2-30 addToPoint函数―

function addToPoint(x, y) {
  x Math.floor(x/SCALE);
  y Math.floor(y/SCALE);

  if (!points[[x,y]]) {
points[[x,y]] 1;
  } else if (points[[x,y]]10) {
return
  } else {
points[,y]];
  }
  drawPoint(x*SCALE,y*SCALE, points[[x,y]]);
}

  最后还注册了一个loadDemo函数用来在窗口加载完毕的时候调用。

window.addEventListener(load, loadDemo, true);

  总而言之这些100行左右的代码可以向大家证明使用HTML5 Canvas API在短短的时间内不用任何插件或者外部技术就可以实现非常高级的功能。另外我们身边的各种数据源又是无穷无尽的既然将它们可视化如此简单方便那我们还等什么呢进阶功能之全页玻璃窗
  在前面的示例中我们看到了如何把canvas应用于图片上。其实我们还可以把canvas应用于整个浏览器窗口或者其中的一部分之上——种技术通常被称作“玻璃窗”glass pane。在Web页面中放置玻璃窗后我们可以做很多之前意想不到的事情。
  例如可以编写函数来获取页面中所有DOM元素的绝对位置然后创建循序渐进的帮助功能从而引导Web应用的用户一步一步地教他们学会操作。
  另外可以借助canvas玻璃窗并利用鼠标事件让用户在Web页面上绘制反馈。不过使用此功能时请记住以下三点。
  需要将canvas的CSS属性position设置为absolute并且指定canvas的位置、宽度和高度。如果没有明确的宽度和高度值那么canvas将保持默认尺寸——0像素。
  别忘了将canvas的CSS属性z-index的值设置得大一些使其能够盖在所有显示内容的上面。如果canvas被其他内容覆盖在最下面就毫无用武之地了。
  设置canvas玻璃窗会阻塞后续的事件访问因此需要提醒开发人员不需要时要记得“关窗”。
2.4 小结
  到目前为止我们看到了HTML5 Canvas API提供的强大功能利用它可以直接修改Web应用的外观而不必再像以前那样借助于各种第三方技术。HTML5 Canvas API还可以通过自由组合图像、渐变和复杂路径等方式来创建你能想到的几乎所有效果。需要注意的是绘制工作通常应以原点为起点在展现图像之前要先完成加载而在使用外部来源的图片时则要留心。如果能学会驾驭canvas那么你就能在网页上创建出前所未见的应用。
 

458069

1.微信公众号拼图制作怎么完成微信公众号九宫格拼图技巧

在日常生活中常会把同样的东西归纳在一起在微信公众号推送中也常会将多张图片进行拼接形成一张长图这样在浏览时可以直接下滑浏览不用频繁地向后翻页。还有的做成微信公众号九宫格拼图这样阅读者在观看时一…

2.微信公众号拼图工具有哪些值得推荐的微信公众号拼图软件

一篇好的微信公众号推文不仅要有风格干练、描述清晰的文字内容还需要搭配简洁直观的图片这样才能给阅读者舒适的阅读感受。 当遇到图片较多的时候便需要进行图片拼接也就是拼图。很多公众号运营…

3.朋友圈九宫图图片大小规格 微信朋友圈的九宫格拼图尺寸

不知道从什么时候开始很多小伙伴在朋友圈发文皆配有九宫格也许是为了对称也许是为了浪漫也许是为了与众不同。当然也有一部分小伙伴对于自己的每一条朋友圈皆十分严谨即使是朋友圈九宫格图片尺寸也会多多注…

4.微信公众号文章图片怎么拼图微信公众号图片拼图模板分享

很多人都有这样的经历出门游玩拍了很多好看的照片但是上传到手机上后在屏幕上显示不全会有省略号的提示。在微信公众号上亦是这样的当图片内容过多会给阅读者造成繁杂的阅读感受很容易失去耐心和兴趣这…

5.怎么用ps抠图然后拼到另一幅图ps抠图拼图教程

前天《复仇者联盟4》在中国全球首映了! 美国都比中国晚上映三天!! 国内的漫威迷早都热血沸腾各影院的零点首映电影票虽然一路高涨但仍然抵挡不住大家的热情甚至有美国的小伙伴飞到北京看首映再飞回美国…

6.怎么制作长图在线制作超长图片

有时候一张普通大小的图片并不能放下所有我们想要展示的内容这该怎么办呢有的人会通过拼图来解决将含有内容的图片全部连在一起这确实也能达成目的但在视觉效果上并不美观。最佳的方式是进行超长图片制作…

7.ps如何抠图没有毛边ps抠图去毛边的方法

如今抠图拼图合成图已经成为图像处理中最普遍的一些操作方法。特别是抠图不仅操作多工具也很多其实PS抠图方法就包括像魔术棒抠图、蒙版抠图、通道抠图、色彩范围等等每一种都有自己的操作方法和特色优点…

8.ps抠图后怎么移动到另一个图层ps抠图移动的技巧

大家在日常的工作、学习中经常会进行一些需要进行海报制作、logo设计、拼图裁剪等图像处理的情况PS的普及率也因此越来越高。但是真正会用ps的小伙伴却寥寥无几因为ps在很多人眼中都是设计师的专属工…

9.哪款软件可以人像抠图可以把人像抠图的软件

现在很有小伙伴在拍完照都会后期加工处理不管是抠图、拼图、打马赛克还是加贴纸都是为了让自己的照片看起来不一样。而抠图相比其他操作来说比较困难但是也是非常常用的对于很多人来说也是一件非常头疼的事情…

10.微信发朋友圈3张图片排版技巧

有时候发朋友圈亦是令人苦恼的比如你明明只有三张图片却想要排版清晰明确、与众不同那直接上传于朋友圈自然不在你的考虑范围之内了。究竟…