HTML5 程序设计笔记(二)

时间:2021-02-26 00:20:18

Canvas API

1、HTML5 Canvas 概述
  1.1 历史

    Canvas的概念最初是由苹果公司提出的,用于在Mac OS X WebKit中创建控制板部件(dashboard widget)。在Canvas出现之前,开发人员若要在浏览器中使用绘图API,只能使用Adobe的Flash和SVG插件,或者只有IE才支持的VML,以及其他一些稀奇古怪的javascript技巧。

    SVG和Canvas对比

      "Canvas本质上是一个位图画布,其上绘制的图形是不可缩放的,不能像SVG图像那样可以被放大缩小。此外,用Canvas绘制出来的对象不属于页面DOM结构或者任何命名空间——这点被认为是一个缺陷。SVG图像却可以在不同的分辨率下流畅地缩放,并且支持单击检测(能检测到鼠标单击图像上的哪个点)"。

      既然如此,为什么WHATWG的HTML5规范不使用SVG呢?尽管Canvas有明显的不足,但HTML Canvas API有两个方面优势可以弥补:首先,不需要将所绘制图像中的每个图元当作对象存储,因此执行性能非常好;其次,在其他编程语言现有的优秀二维绘图API的基础上实现Canvas API相对来说比较简单。

  1.2 Canvas 是什么

    在网页上使用canvas元素时,他会创建一块矩形区域。默认情况下该矩形区域宽为300像素,高为150像素,但也可以自定义具体的大小或者设置canvas元素的其他特性。

<canvas></canvas>

    在页面加入了canvas元素后,我们便可以通过javascript来*的控制它。可以在其中添加图片、线条、以及文字,也可以在里面绘图,甚至还可以加入高级动画。

    使用canvas编程,首先要获取其上下文(context)。接着在上下文中执行动作,最后将这些动作应用到上下文中。可以将canvas的这种编辑方式想象成为数据库事务:开发人员先发起一个事务,然后执行某些操作,最后提交事务。

  1.3 canvas坐标

    canvas中的坐标是从左上角开始的,x轴沿着水平方向(按像素)向右延伸,y轴沿着垂直方向向下延伸。左上角的坐标为x=0,y=0的点称作原点。

  1.4 什么情况下不用canvas

    在某些情况下,如果其他元素已经够用了,就不应该再使用canvas元素。例如,用canvas元素在HTML页面中动态绘制所有不同的标题,就不如直接使用标题样式(H1、H2等),他们所实现的效果是一样的。

  1.5 替代内容

    访问页面的时候,如果浏览器不支持canvas元素,或者不支持HTML5 Canvas API中的某些特性,那么开发人员最好提供一份替代代码。例如,开发人员可以通过一张替代图片或者一些说明性的文字告诉访问者,使用最新的浏览器可以获得更佳的浏览效果。   

 <canvas>
Update your browser to enjoy canvas!
</canvas>

     canvas元素的可访问性怎么样?

      “提供替代图像或替代文本引出了可访问性这个话题——很遗憾,这是HTML5 Canvas规范中明显的缺陷。例如,没有一种原生方法能够自动为已插入到canvas中的图片生成用于替换的文字说明。同样,也没有原生方法可以生成替代文字以匹配由Canvas Text API动态生成的文字。”

    Canvas API的未来迭代中,可能会包含与Canvas显示相关的可聚焦的子区域以及他们之间的交互控制。但是,如果你的图像显示需要显著的交互行为,那么可以考虑使用SVG代替Canvas API。SVG也用于绘制,而且他整合了浏览器的DOM。

  1.6 CSS 和canvas

    同大多数HTML元素一样,canvas元素也可以通过应用css的方式来增加边框,设置内边距、外边距等,而且一些css属性还可以被canvas内的元素继承。比如字体样式,在canvas内添加的文字,其样式默认同canvas元素本身是一样的。

    此外,在canvas中为context设置属性同样要遵从css语法。例如,对context应用颜色和字体样式,跟在任何HTML和CSS文档中使用的语法完全一样。

  1.7 浏览器对HTML5 Canvas的支持情况

    随着IE9的到来,所有浏览器厂商现在都提供了对HTML5 Canvas的支持,而且他已被大多数用户所掌握。

2、使用HTML5 Canvas API
  2.1 检测浏览器支持情况

    在创建HTML5 canvas元素之前,首先要确保浏览器能够支持它。如果不支持,就需要为那些古董级浏览器提供一些替代文字。

 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的元素,通过以适当的信息更新该元素的内容,可以反应出浏览器的支持情况。

  2.2 在页面中加入canvas
 <canvas height="200" width="200"></canvas>

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

 <canvas id="diagonal" style="border:1px solid;" width="200" height="200"></canvas>

    注意,上面的代码中增加了一个值为“diagonal”的ID特性,这么做的意义在于以后的开发过程中可以通过ID来快速找到该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>

    首先通过引用特定的canvas ID值来获取对canvas对象的访问权。这段代码中的ID就是diagonal。接着定义一个context变量,调用canvas对象的getContext方法,并传入希望使用的canvas类型。其中,"2d" 为2D、 "webgl"为3D。

    接下来,基于这个上下文执行画线的操作。代码中调用了三个方法——beginPath、moveTo、lineTo,传入了这条线的起点和终点的坐标。

    方法moveTo和lineTo实际上并不画线,而是在结束canvas操作的时候,通过调用context.stroke()方法完成线条的绘制。moveTo(x, y),将上下文移动到坐标指定点;lineTo(x, y),从指定点画线至目标点。

    从上面的代码可以看出,canvas中所有的操作都是通过上下文对象来完成的。只有当对路径应用绘制(stroke)或填充(fill)方法时,结果才会显示出来。否则,只有在显示图像、显示文本或者绘制、填充和清除矩形框的时候,canvas才会马上更新。

  2.3 变换

     也许会认为使用变换增加了不必要的复杂性,但并非如此,其实变换是实现复杂canvas操作的最好方式。了解变换最简单的方法就是把它当成是介于开发人员发出的指令和canvas显示结果质检的修正层(modification layer)。不管在开发中是否使用变换,修正层始终都是存在的。

    修正——在绘制系统中的说法是变换——在应用的时候可以被顺序应用、组合或者随意修改。每个绘制操作的结果显示在canvas上之前都要经过修正层去做修正。虽然增加了额外的复杂性,但却为绘制系统增加了更为强大的功能,可以像目前主流图像编辑工具那样支持实时图像处理,所以API中这部分内容的复杂性是必要的。

    不在代码中调用变换函数并不意味着可以提升canvas的性能。canvas在执行的时候,变换会被呈现引擎隐式调用。

    关于可重用代码有一条重要的建议:一般绘制都应从原点(坐标系中的0,0点)开始,应用变换(缩放、平移、旋转等),然后不断修改代码直至达到希望的效果。

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

    分析上段代码:

      (1)首先,通过ID找到并访问canvas对象。(ID是diagonal)

      (2)接着通过调用canvas对象的getContext函数获取上下文对象。

      (3)接下来,保存尚未修改的context,这样即使进行了绘制和变换操作,也可以恢复到初始状态。如果不保存,那么在进行了平移和缩放等操作以后,其影响会带到后续的操作中,而这不一定是我们所希望的。

      (4)下一步是在context中调用translate函数。通过这个操作,当平移行为发生的时候,我们提供的变换坐标会被加到结果坐标(对角线)上,结果就是将要绘制的对角线移动到了新的位置上。不过,对角线呈现在canvas上是绘制操作结束之后。

      (5)应用平移后,就可以使用普通的绘制操作来画对角线了。代码中调用了三个函数来绘制对角线——beginPaht, moveTo, lineTo。绘制的起点是原点(0, 0),而非坐标点(70, 140)。

      (6)在线条勾画出来之后,可以通过调用context.stroke()函数将其显示在canvas上。

      (7)最后,恢复context至原始状态,这样后续的canvas操作就不会被刚才的平移操作影响了。

  2.4 路径

    HTML5 Canvas API 中的路径代表你希望呈现的任何形状。前面代码中调用beginPath就说明是要开始绘制路径了。路径可以要多复杂有多复杂:多条线、曲线段,甚至是子路径。

    按照惯例,不论开始绘制任何图形,第一个需要调用的就是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重新绘制新路径并完全清除之前的所有路径。

 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();
}

    从上面的代码中可以看到,我们用到的仍然是前面用过的移动和画线命令,只不过调用次数多了一些。这些线条表现树冠的轮廓,最后我们闭合了路径。

 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.5 描边样式
     //加宽线条
context.lineWidth = 4; //平滑路径的接合点
context.lineJoin = 'round'; //将颜色改成棕色
context.strokeStyle = '#663300'; //最后,绘制树冠
context.stroke();

    设置上面这些属性可以改变以后将要绘制的图形外观,这个外观起码可以保持到我们将context恢复到上一个状态。

    首先,我们将线条宽度加粗到4像素。

    其次,我们将lineJoin属性设置为round,这是修改当前形状中线段的连接方式,让拐角变得更圆滑;也可以把lineJoin属性设置成bevel或者miter(相应的context.miterLimit值也需要调整)来变换拐角样式。

    最后,通过strokeStyle属性改变了线条的颜色。

    还有一个没有用到的属性——lineCap,可以把它的值设置为butt、square或者round,以此来指定线条末端的样式。示例中的线是闭合的,没有端点。

  2.6 填充样式

    另一个常用于修改图形的方法是指定如何填充其路径和子路经。

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

    首先,我们将fillStyle属性设置成合适的颜色。然后,只要调用context的fill函数就可以让canvas对当前图形中所有的闭合路径内部的像素点进行填充。

    由于我们是先描边后填充,因此填充会覆盖一部分描边路径。如果希望看到完整的描边路径,可以在绘制路径(调用context.stroke())之前填充(调用context.fill())。

  2.7 填充矩形区域
 //将填充色设置为棕色
context.fillStyle = '#663300'; //填充用作树干的矩形区域
context.fillRect(-5, -50, 10, 50);

    调用fillRect并设置x、y两个位置参数和宽度、高度两个大小参数,随后,Canvas会马上使用当前的样式进行填充。

    与之相关的函数还有strokeRect和clearRect。strokeRect的作用是基于给出的位置和坐标画出矩形的轮廓,clearRect的作用是清除矩形区域内的所有内容并将它回复到初始状态,即透明色。

    canvas动画

      “在HTML5 Canvas API中,canvas的清除矩形功能是创建动画和游戏的核心功能。通过反复绘制和清除canvas片段,就可能实现动画效果,互联网上有许多这样的例子。但是如果希望创建运行起来比较流畅的动画,就需要使用剪裁(clipping)功能了,有可能还需要二次缓存canvas,以便最小化由于频繁的清除动作而导致的画面闪烁。”

  2.8 绘制曲线

    canvas提供了一系列绘制曲线的函数,这里使用最简单的曲线函数——二次曲线。

 //保存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状态,因为我们即将变换坐标系并修改轮廓设置。

    quadraticCurveTo函数绘制曲线的起点是当前坐标,带有两组(x, y)参数。第二组是值曲线的终点,第一组代表控制点(control point)。所谓的控制点位于曲线的旁边(不是曲线之上),其作用相当于对曲线产生一个拉力。通过调整控制点的位置,就可以改变曲线的曲率。

    HTML5 Canvas API的其他曲线功能还涉及bezierCurveTo、atcTo和arc函数。这些函数通过多种控制点(如半径、角度等)让曲线更具有可塑性。

   2.9 在canvas中插入图片

    在canvas中显示图片非常简单。可以通过修正层为图片添加印章、拉伸图片或者修改图片等,并且图片通常会成为canvas上的焦点。

    不过,图片增加了canvas操作的复杂度:必须等到图片完全加载后才能对其进行操作。浏览器通常会在页面脚本执行的同时异步加载图片。如果试图在图片未完全加载之前就将其呈现到canvas上,那么canvas将不会显示任何图片。因此,开发人员要特别注意,在呈现之前,应确保图片已经加载完毕。

    示例中,为保证在呈现之前图片已完全加载,这里提供了回调,即仅当图像加载完成时才执行后续代码。

 //加载图片bark.jpg
var bark = new Image();
bark.src = "bark.jpg"; //图片加载完成后,将其显示在canvas上
bark.onload = function(){
drawTrails();
}

    上面的代码中,我们为bark.jpg图片添加了onload处理函数,以保证仅在图像加载完成时才调用主drawTrails函数。这样做可以保证后续的调用能够把图片正常显示出来。

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

    在drawImage函数中,除了图片本身外,还指定了x、y、width和height参数。这些参数会对贴图进行调整以适应预定的10×50像素树干区域。

   2.10 渐变

    渐变是指在颜色集上使用逐步抽样算法,并将结果应用于描边样式和填充样式中。使用渐变需要三个步骤:

      (1)创建渐变对象;

      (2)为渐变对象设置颜色,指明过渡方式;

      (3)在context上为填充样式或者描边样式设置渐变。

    可以将渐变看作是颜色沿着一条线进行缓慢地变化。

    要设置颜色哪种颜色,在渐变对象上使用addColorStop函数即可。这个函数允许指定两个参数:颜色和偏移量。颜色参数指开发人员希望在偏移位置描边或填充时所使用的颜色。偏移量是一个0.0到1.0之间的数值,代表沿着渐变线渐变的距离有多远。

    除了可以变换成其他颜色外,还可以为颜色设置alpha值(例如透明),并且alpha值也是可以变化的。例如内置alpha组件的CSS rgba函数。

 //创建用作树干纹理的三阶水平渐变
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);

    使用了两个渐变后,最终绘制出来的树干有了平滑的光照效果。

    除了刚才用到的线性渐变以外,HTML5 Canvas API还支持放射性渐变,所谓放射性渐变就是颜色会介于指定圆间的锥形区域平滑变化。

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

    前三个参数代表以(x0, y0)为圆心,r0为半径的圆,后三个参数代表以(x1, y1)为圆心,r1为半径的另一个圆。渐变会在两个圆中间的区域出现。

   2.11 背景图

    这里将调用createPattern函数来替代之前的drawImage函数。

 //加载砾石背景图
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的第二个参数是重复性标记:

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

      repeat-x      横向平铺

      repeat-y      纵向平铺

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

   2.12 缩放canvas对象

      我们计划把示例代码中用于绘制树的操作独立出来,当作一个单独的例程,成为drawTree。

 //创建树对象绘制函数,以便重用
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。

 //在(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两个纬度的值。

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

      “示例中演示了为什么要在原点执行图形的路径的变换操作,执行完后再统一平移。理由就是缩放(scale)和旋转(rotate)等变换操作都是针对原点进行的。

      如果对一个不在原点的图形进行旋转变换,那么rotate变换函数会将图形绕着原点旋转而不是在原地旋转。与之类似,如果进行缩放操作时没有将图形放置到合适的坐标上,那么所有路径坐标都会被同时缩放。取决于缩放比例的大小,新的坐标可能会全部超出canvas范围,进而给开发人员带来困惑,为什么我的缩放操作会把图像删除了?”

   2.13 Canvas变换

    变换操作并不限于缩放和平移,我们可以使用函数context.rotate(angle)来旋转图像,甚至可以直接修改底层变换矩阵以完成一些高级操作,如剪切图像的绘制路径。

 context.save();

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

    下面演示如何对路径坐标进行随意变换,以从根本上改变现有树的路径显示,并最终创建一个阴影效果。

 //创建用于填充树干的三阶水平渐变色
//保存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%的比例将剪裁出的树缩小到了合适的尺寸。

    context.transform(a, b, c, d, e, f);

    a : 水平缩放绘图

    b : 水平倾斜绘图

    c : 垂直倾斜绘图

    d : 垂直缩放绘图

    e : 水平移动绘图

    f : 垂直移动绘图

    注意,剪裁过的“阴影”树会先被显示出来,这样一来,真正的树就会按照Z轴顺序(canvas中对象的重叠顺序)显示在阴影的上面。此外,树影的充分用到了CSS的RGBA特性,通过特性我们将透明度值设为正常情况下的20%。至此,带有半透明效果的树影就做好了。

  2.14 Canvas 文本

    操作canvas文本的方式与操作其他路径对象的方式相同:可以描绘文本轮廓和填充文本内部;同时,所有能够应用与其他图形的变换和样式都能用于文本。

    context对象的文本绘制功能由两个函数组成:

      fillText(text, x, y, maxwidth)

      strokeText(text, x, y, maxwidth)

    两个函数的参数完全相同,必选参数包括文本参数以及用于制定文本位置的坐标参数。maxwidth是个可选参数,用于限制字体大小,它会将文本字体强制收缩到指定尺寸。还有一个measureText函数可供使用,该函数会返回一个度量对象,其中包含了在当前context环境下指定文本的实际显示宽度。

      font    CSS字体字符串    例如:italic Arial, scans-serif

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

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

 //在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();

    我们首先创建了一段使用Impact字体的大字号文本,然后使用已有的树皮图片座位背景进行填充。为了将文本置于canvas的上方并居中,我们定义了最大宽度和center对齐方式。

  2.15 应用阴影

    通过几个全局context属性来控制阴影

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

      shadowOffsetX      像素值            值为正数,向右移动阴影;值为负数,向左移动阴影

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

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

    shadowColor或者其他任意一项属性的值被赋为非默认值,路径、文本和图片上的阴影效果就会被触发。

 //设置文字阴影的颜色为黑色,透明度为20%
context.shadowColor = 'rgba(0, 0, 0, 0.2)'; //将阴影向右移动15px,向上移动10px
context.shadowOffsetX = 15;
context.shadowOffsetY = -10; //轻微模糊阴影
context.shadowBlur = 2;

    如你所见,由CSS生成的阴影只有位置上的变化,而无法与变换生成的阴影(树影)保持同步。为了一致起见,在canvas上绘制阴影时,应该尽量只用一种方法。