书名:Web前端开发精品课——HTML5 Canvas开发详解
ISBN:978-7-115-45020-3
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
• 著 莫振杰
责任编辑 赵 轩
• 人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
• 读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书结合笔者在前后端大量开发工作中的实战经验,系统化知识,浓缩精华,用通俗易懂的语言直击学习者的痛点。学习本书,可以让你掌握所有Canvas API、大部分动画技术以及各种高级开发技巧,真正获得一个稀有技能!
全书共分为两大部分,第一部分是Canvas基础内容,主要介绍Canvas API语法,其中包括图形绘制、线条操作、文本操作、图片操作、变形操作、像素操作等各种基础API语法;第二部分是Canvas进阶内容,主要介绍Canvas动画开发,包括事件操作、物理动画、边界检测、碰撞检测、高级动画等各种稀有技巧。
除了知识的讲解,教程还融入了大量的开发案例,并且更加注重实战编程思维的培养,为学习者提供一个流畅的学习思路。
近几年,Web前端技术发展是非常快的,尤其是HTML5,更是引起了浏览器商以及广大Web开发从业者的广泛关注。HTML5增加了大量的新特性,而Canvas则是其中最吸引人的特性。作为HTML5核心技术之一,Canvas应用非常广泛,可以用于绘制图形、绘制图表、动画开发以及游戏开发等。
当前市面上Canvas方面的书是极其之少的。即使有涉及Canvas的,也都是简单介绍一下API,而对本质的深入、开发技巧以及动画开发等却几乎没有涉及。作为“Web前端开发精品课”系列的第3本,这本书的质量是毋容置疑的。本书覆盖面非常广,以极其清晰的思路、精练幽默的语言、系统化的结构对Canvas大部分知识进行深加工,为读者提供了一个流畅的学习思路,同时也避免了读者走太多的弯路。
(1)含金量高,前端精品内容荟萃,强化基础提升实战技能。
(2)通俗易懂,语言风格轻松幽默,形象生动讲解枯燥知识。
(3)系统学习,掌握前端高级技巧,清晰流畅学习进阶内容。
(4)贴近读者,结合自身学习经历,文字极具温度不失严谨 。 (5)直击痛点,规避开发思维误区,精炼浓缩直指技术本质。
(1)有一定基础的Web前端开发工程师。
(2)大中院校相关专业学生。
感谢我最亲爱的奶奶在我成长过程中给予无微不至的照顾和关爱。感谢我的女友小晔五年来的一路陪伴,并且在我写作这段时间一直理解和支持。
感谢我的挚友陈志东先生,他花费了大量的时间为本书绘制了几乎所有的插图,并且给出了诸多非常棒的建议。
感谢充满创意和活力的五叶草(陈志东、邵婵、程紫梦)的一直陪伴和支持。我的人生因为有你们而更为精彩。
感谢yuki、saber、Chris、winne这几位绿叶学习网的小伙伴对本书稿件细致地审查,指出了不少错漏,使得本书更加完善。
感谢本书责任编辑赵轩老师在这段时间中给予我细心的指导和不懈的支持,有您的帮助本书才得以顺利出版。
由于作者水平有限,书中难免有错漏之处,读者如果遇到问题或有意见和建议,可以到绿叶学习网(www.lvyestudy.com)或者发邮件(lvyestudy@foxmail.com)与我联系。
编者
在HTML5之前,为了达到页面绚丽多彩的效果,我们很多情况下都是借助“图片”来实现。不过使用图片这种方式,都是以“低性能”为代价的。由于图片体积大、下载速度慢等原因,因此为了应对日渐复杂的Web应用开发,W3C在HTML5标准中引入了Canvas这一门技术。
我们都知道,HTML5新增了一个Canvas元素。其实,Canvas又称为“画布”,是HTML5的核心技术之一。我们常说的Canvas技术,指的就是使用Canvas元素结合Javascript来绘制各种图形的技术。
既然Canvas是HTML5核心技术,那它都有哪些厉害之处呢?
Canvas可以用来绘制各种基本图形如矩形、曲线、圆等,也可以绘制各种复杂绚丽的图形,如图1-1所示。
图1-1 Canvas绘制图形(七巧板)
很多公司业务的数据展示都离不开图表,使用Canvas可以用来绘制满足各种需求的图表,如图1-2所示。
图1-2 Canvas绘制图表
使用Canvas,我们也可以制作出各种华丽的动画效果,这也是Canvas为大家带来的一大乐趣,如图1-3所示。
图1-3 Canvas动画效果
游戏开发在HTML5领域具有举足轻重的地位,现在我们也可以使用Canvas来开发各种游戏,如图1-4所示。这几年非常火的游戏如围住神经猫等,就是使用HTML5 Canvas来开发的。
图1-4 Canvas开发游戏
此外,Canvas技术是一门纯JavaScript操作的技术,因此大家需要具备JavaScript入门知识。对于JavaScript的学习,可以关注绿叶学习网(www.lvyestudy.com)中的开源教程。
HTML5有两个主要的2D图形技术:Canvas和SVG。事实上,Canvas和SVG是两门完全不同的技术。两者具有以下区别。
(1)Canvas是使用JavaScript动态生成的,SVG是使用XML静态描述的。
(2)Canvas是基于“位图”的,适用于像素处理和动态渲染,图形放大会影响质量。SVG是基于“矢量”的,不适用于像素处理和静态描述,图形放大不会影响质量。也就是说,使用Canvas绘制出来的是一个“位图”,而使用SVG绘制出来的是一个“矢量图”。如图1-5和图1-6所示。
图1-5 Canvas位图(放大会失真)
图1-6 SVG矢量图(放大不会失真)
(3)每次发生修改,Canvas需要重绘,而SVG不需要重绘。
(4)Canvas与SVG的关系,简单来说,就像“美术与几何”的关系一样。
此外,并非Canvas就比SVG更有前途,也并非SVG就比Canvas更有前途,因为这两个是用于不同场合的。在实际开发中,我们应该根据开发需求去选择。
当然,这里只是简单介绍了一下Canvas与SVG的区别,如果想真正了解,我们还需要深入学习这两门技术。最后给大家一个小小的建议:很多人接触新技术的时候,喜欢在第一遍学习中就把每一个细节都弄清楚,事实上这是效率最低的学习方法。在第一遍学习中,如果有些东西实在没办法理解,那就直接跳过,等到学到后面或者看第二遍的时候,自然而然就懂了。
HTML5 Canvas,简单来说,就是一门使用JavaScript来操作Canvas元素的技术。使用Canvas元素来绘制图形,需要以下三步。
(1)获取canvas对象。
(2)获取上下文环境对象context。
(3)开始绘制图形。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
window.onload = function () {
//1、获取canvas对象
var cnv = document.getElementById("canvas");
//2、获取上下文环境对象context
var cxt = cnv.getContext("2d");
//3、开始绘制图形
cxt.moveTo(50, 100);
cxt.lineTo(150, 50);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图1-7所示。
图1-7 Canvas画直线
在Canvas中,我们首先使用document.getElementById()方法来获取canvas对象(这是一个DOM对象),然后使用canvas对象的getContext("2d")方法获取上下文环境对象context,最后再使用context对象的属性和方法来绘制各种图形。
Canvas是一个行内块元素(即inline-block),我们一般需要指定其三个属性:id、width和height。width和height分别定义Canvas的宽度和高度。默认情况下,Canvas的宽度为300px,高度为150px。
对于Canvas的宽度和高度,有两种方法来定义:①在HTML属性中定义;②在CSS样式中定义。但是在实际开发中,我们一定不要在CSS样式中定义,而是应该在HTML属性中定义。为什么呢?下面先来看一个例子。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<style type="text/css">
canvas
{
width:200px;
height:150px;
}
</style>
<script type="text/javascript">
window.onload = function () {
var cnv = document.getElementById("canvas");
var str = "canvas的宽度为:" + cnv.width + ",高度为:" + cnv.height;
alert(str);
}
</script>
</head>
<body>
<canvas id="canvas" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图1-8所示。
图1-8 Canvas无法获取正确的宽度和高度
从这个例子可以看出:如果在CSS样式中定义,我们使用canvas对象获取的宽度和高度是默认值,而不是实际的宽度和高度。这样就无法获取canvas对象正确的宽度和高度。获取canvas对象实际的宽度和高度是Canvas开发中最常用的操作,因此对于Canvas的宽度和高度我们就一定要在HTML属性中定义,而不是在CSS属性中定义。
在Canvas中,我们可以使用document.getElementById()方法来获取canvas对象。canvas对象常用的属性和方法如下:
表1-1 canvas对象属性
属性 |
说明 |
---|---|
width |
Canvas的宽度 |
height |
Canvas的高度 |
表1-2 canvas对象方法
属性 |
说明 |
---|---|
getContext(“2d”) |
获取Canvas 2D上下文环境对象 |
toDataURL() |
获取canvas对象产生的位图的字符串 |
也就是说,我们可以使用cnv.width和cnv.height分别获取Canvas的宽度和高度,可以使用cnv.getContext("2d")来获取canvas 2D上下文环境对象,也可以使用toDataURL()来获取canvas对象产生的位图的字符串。在这里,cnv是指canvas对象。
对于toDataURL()方法,我们可以暂时不去深入,在后面章节中会详细给大家介绍。这里我们只要认真学习一下getContext("2d")方法就可以了。在Canvas中,我们使用getContext("2d")来获取Canvas 2D上下文环境对象,这个对象又称为context对象。后面章节接触的所有图形的绘制,使用的都是context对象的属性和方法,这一点需要特别清楚。当然现在不理解没关系,学到后面再回过头来看看这段话就懂了。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
window.onload = function () {
var cnv = document.getElementById("canvas");
var str = "Canvas的宽度为:" + cnv.width + ",高度为:" + cnv.height;
alert(str);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="160" style="border:1px dashed gray"></canvas>
</body>
</html>
在浏览器中的预览效果如图1-9所示。
图1-9 Canvas获取正确的宽度和高度
本节要特别注意一点:以后学习的所有图形的绘制,我们使用的都是context对象(上下文环境对象)的属性和方法。
(1)我们可以使用getContext("2d")来实现2D绘图,那是不是意味着可以使用getContext("3d")来实现3D绘图呢?
HTML5 Canvas暂时只提供2D绘图API,3D绘图可以使用HTML5中的WebGL进行开发。不过3D绘图一直以来都是HTML5中的“黑科技”,技术要求高并且难度大。等学完了这本书,有兴趣的小伙伴可以关注一下绿叶学习网的WebGl教程
(2)对于IE浏览器来说,暂时只有IE9以上版本支持HTML5 Canvas,那么如何处理IE7和IE8的兼容性问题呢?
对于IE7和IE8,可以借助explorercanvas这个扩展来解决。该扩展下载地址为:https://github.com/arv/explorercanvas。
我们只需要在页面像引入外部JavaScript文件那样引入excanvas.js就可以了,代码如下:
<!--[if IE]>
<script src="excanvas.js"></script>
<![end if]-->
不过要跟大家说明一下,低版本IE浏览器即使引入了excanvas.js来使用Canvas,在功能上也会有很多限制,例如无法使用fillText()方法等。
(3)对于Canvas的学习,除了这本书,还有什么推荐的吗?
建议大家多看看W3C官方网站中的canvas的开发文档,因为这是最权威的参考资料。W3C官网地址:www.w3.org/TR/2dcontext/。
在Canvas中,基本图形有两种:①直线图形;②曲线图形。Canvas常见的直线图形有三种,分另是直线、矩形、多边形。
这一章我们先来学习Canvas中的直线图形。
在学习Canvas之前,我们先来介绍一下Canvas中的坐标系是如何使用的。了解Canvas使用的坐标系是学习Canvas的最基本的前提。
我们经常见到的坐标系是数学坐标系,而Canvas使用的坐标系是W3C坐标系,这两种坐标系唯一的区别在于y轴正方向的不同。
(1)数学坐标系:y轴正方向向上。
(2)W3C坐标系:y轴正方向向下。
注意:W3C坐标系的y轴正方向是向下的。很多小伙伴学到后面对Canvas一些代码感到很困惑,那是因为他们没有清楚地意识到这一点。
数学坐标系一般用于数学形式上的应用,而在前端开发中几乎所有涉及坐标系的技术使用的都是W3C坐标系,这些技术包括CSS3、Canvas、SVG等。了解这一点,我们以后在学习CSS3或者SVG的时候,很多知识就可以串起来了。数字坐标系和w3c坐标系如图2-1所示。
图2-1 数学坐标系和W3C坐标系
在Canvas中,可以使用moveTo()和lineTo()这两个方法配合使用来画直线。利用这两个方法,我们可以画一条直线,也可以同时画多条直线。
cxt.moveTo(x1, y1);
cxt.lineTo(x2, y2);
cxt.stroke();
cxt表示上下文环境对象context。
(x1,y1)表示直线“起点”的坐标。moveTo的含义是“将画笔移到该点(x1,y1)位置上,然后开始绘图”。
(x2,y2)表示直线“终点”的坐标。lineTo的含义是“将画笔从起点(x1,y1)开始画直线,一直画到终点坐标(x2,y2)”。
对于moveTo()和lineTo()这两个方法,从英文意思角度更容易帮助我们理解和记忆。
cxt.moveTo(x1, y1);
cxt.lineTo(x2, y2);
上面两句代码仅仅是确定直线的“起点坐标”和“终点坐标”这两个状态,但是实际上画笔还没开始“动”。因此我们还需要调用上下文对象的stroke()方法才有效。
使用Canvas画直线,与我们平常用笔在纸张上画直线是一样的道理,都是先确定直线起点(x1,y1)与终点(x2,y2),然后再用笔连线(stroke())。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.moveTo(50, 100);
cxt.lineTo(150, 50);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-2所示。
图2-2 使用Canvas画一条直线
在这个例子中,我们定义了一个获取DOM对象元素的函数$$(id),这样减少了重复代码量,使得思路更加清晰。记住,Canvas中使用的坐标系是“W3C坐标系”。其中这个例子的分析图如图2-3所示。
图2-3 分析图
从上面可以知道,使用moveTo()和lineTo()这两个方法可以画一条直线。其实如果我们想要同时画多条直线,也是使用这两种方法。
cxt.moveTo(x1, y1);
cxt.lineTo(x2, y2);
cxt.lineTo(x3, y3);
……
cxt.stroke();
lineTo()方法是可以重复使用的。第一次使用lineTo()后,画笔将自动移到终点坐标位置,第二次使用lineTo()后,Canvas会以“上一个终点坐标”作为第二次调用的起点坐标,然后再开始画直线,以此类推。下面先来看个例子,这样更容易理解些。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.moveTo(50,50);
cxt.lineTo(100,50);
cxt.moveTo(50,100);
cxt.lineTo(100,100);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-4所示。
图2-4 使用Canvas画两条直线
记住,moveTo的含义是:将画笔移到该点的位置,然后开始绘图。lineTo的含义是:将画笔从起点开始画直线,一直到终点坐标。
如果将cxt.moveTo(50,100);改为cxt.lineTo(50,100);,在浏览器中的预览效果如图2-5所示。大家根据这个例子仔细琢磨一下moveTo()与lineTo()两个方法的区别。
图2-5 cxt.moveTo(50,100);改为cxt.lineTo(50,100);
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.moveTo(50, 100);
cxt.lineTo(150, 50);
cxt.lineTo(150, 100);
cxt.lineTo(50, 100);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-6所示。
图2-6 用直线画一个三角形
这里使用moveTo()与lineTo()方法画了一个三角形。在画三角形之前,我们事先要确定三角形三个顶点的坐标。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.moveTo(50, 100);
cxt.lineTo(50,50);
cxt.lineTo(150, 50);
cxt.lineTo(150, 100);
cxt.lineTo(50, 100);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-7所示。
图2-7 用直线画一个矩形
这里使用moveTo()和lineTo()方法画了一个矩形。在画矩形之前,我们也需要事先确定矩形四个顶点坐标的(这几个坐标值不是随便来的,而是要计算出来的)。
其实在Canvas中,使用moveTo()和lineTo()方法可以画各种多边形如三角形、矩形、多边形等。在实际开发中,对于三角形和多边形,我们都是用moveTo()和lineTo()来实现。但是对于矩形来说,Canvas为我们提供了更为简单的一套方法,在下一节中将给大家详细介绍。
从上一节我们知道,可以将moveTo()和lineTo()配合使用来画一个矩形。但是这种画矩形的方法代码量过多,因此在实际开发中并不推荐使用。
对于绘制矩形,Canvas还为我们提供了独立的方法来实现。在Canvas中,矩形分为两种,即“描边”矩形和“填充”矩形。
在Canvas中,我们可以将strokeStyle属性和strokeRect()方法配合使用来画一个“描边矩形”。
cxt.strokeStyle = 属性值;
cxt.strokeRect(x,y,width,height);
strokeStyle是context对象的一个属性,而strokeRect()是content对象的一个方法。大家要区分好什么叫属性,什么叫方法。
(1)strokeStyle属性
strokeStyle属性取值有三种,即颜色值、渐变色、图案。对于strokeStyle取值为渐变色和图案的情况,我们在后续章节会详细讲解。现在先来看一下strokeStyle取值为颜色值的几种情况:
cxt.strokeStyle = "#FF0000"; //十六进制颜色值
cxt.strokeStyle = "red"; //颜色关键字
cxt.strokeStyle = "rgb(255,0,0)"; //rgb颜色值
cxt.strokeStyle = "rgba(255,0,0,0.8)"; //rgba颜色值
(2)strokeRect()方法
strokeRect()方法用于确定矩形的坐标,其中x和y为矩形最左上角的坐标。注意,凡是对于Canvas中的坐标,大家一定要根据W3C坐标系来理解。此外width表示矩形的宽度,height表示矩形的高度,默认情况下width和height都是以px为单位的。strokeRect()方法分析图如图2-8所示。
图2-8 strokeRect()方法分析图
我们还要特别注意一点,strokeStyle属性必须在strokeRect()方法之前定义,否则strokeStyle属性无效。也就是说,在“画(strokeRect())”之前一定要把应有的参数(如strokeStyle)设置好。Canvas是根据已设置的参数来“画”图形的,其实这跟我们平常画画是一样的道理:在动笔之前首先需要确定将要画什么东西,颜色是什么,然后再用笔画出来。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.strokeStyle = "red";
cxt.strokeRect(50, 50, 80, 80);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-9所示。
图2-9 描边矩形
当将cxt.strokeStyle = "red";和cxt.strokeRect(50, 50, 80, 80);这两句代码位置互换顺序后,strokeStyle属性就不会生效了。大家可以自行在本地编辑器中修改测试一下,看看实际效果。上面例子的分析如图2-10所示。
图2-10 描边矩形分析
在Canvas中,我们可以将fillStyle属性和fillRect()方法配合使用来画一个“填充矩形”。
cxt.fillStyle=属性值;
cxt.fillRect(x, y, width, height);
fillStyle是context对象的一个属性,而fillRect()是context对象的一个方法。
fillStyle属性跟strokeStyle属性一样,取值也有三种,即颜色值、渐变色、图案。
fillRect()方法跟strokeRect()方法一样,用于确定矩形的坐标,其中x和y为矩形最左上角的坐标,width表示矩形的宽度,height表示矩形的高度。
跟描边矩形一样,填充矩形的fillStyle属性也必须在fillRect()方法之前定义,否则fillStyle属性无效。分析如图2-11所示。
图2-11 fillRect()方法分析图
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.fillStyle = "HotPink";
cxt.fillRect(50, 50, 80, 80);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-12所示。
图2-12 填充矩形
当我们将cxt.fillStyle = "HotPink";和cxt.fillRect(50, 50, 80, 80);这两句代码位置互换顺序后,fillStyle属性就不会生效了。大家可以自行在本地编辑器中修改测试一下,看看实际效果。上面例子分析如图2-13所示。
图2-13 填充矩形分析图
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.strokeStyle = "red";
cxt.strokeRect(50, 50, 80, 80);
cxt.fillStyle = "#FFE8E8";
cxt.fillRect(50, 50, 80, 80);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-14所示。
图2-14 同时使用“描边矩形”和“填充矩形”
在这个例子中,我们同时使用了“描边矩形”和“填充矩形”。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.fillStyle = "HotPink";
cxt.fillRect(50, 50, 80, 80);
cxt.fillStyle = "rgba(0,0,255,0.3)";
cxt.fillRect(30, 30, 80, 80);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-15所示。
图2-15 fillStyle取不同的颜色值
这里我们画了两个矩形:第一个矩形使用了十六进制颜色值,第二个矩形使用了RGBA颜色值。
在Canvas,如果想要绘制一个矩形,除了使用strokeRect()和fillRect()这两种方法之外,我们还可以使用rect()方法,如图2-16所示。
图2-16 rect()方法分析图
rect(x,y,width,height);
x和y为矩形最左上角的坐标,width表示矩形的宽度,height表示矩形的高度。
strokeRect()、fillRect()和rect()都可以画矩形。这三种方法参数是相同的,不同在于实现效果方面。其中strokeRect()和fillRect()这两个方法在调用之后,会立即把矩形绘制出来。而rect()方法在调用之后,并不会把矩形绘制出来。只有在使用rect()方法之后再调用stroke()或者fill()方法,才会把矩形绘制出来。
(1)rect()和stroke()
cxt.strokeStyle="red";
cxt.rect(50,50,80,80);
cxt.stroke();
上述代码等价于:
cxt.strokeStyle="red";
cxt.strokeRect(50,50,80,80);
(2)rect()和fill()
cxt.fillStyle="red";
cxt.rect(50,50,80,80);
cxt.fill();
上述代码等价于:
cxt.fillStyle="red";
cxt.fillRect(50,50,80,80);
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
//绘制描边矩形
cxt.strokeStyle = "red";
cxt.rect(50, 50, 80, 80);
cxt.stroke();
//绘制填充矩形
cxt.fillStyle = "#FFE8E8";
cxt.rect(50, 50, 80, 80);
cxt.fill();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-17所示。
图2-17 rect()方法
在Canvas中,我们可以使用clearRect()方法来清空“指定矩形区域”。
cxt.clearRect(x, y, width, height);
x和y分别表示清空矩形区域最左上角的坐标,width表示矩形的宽度,height表示矩形的高度。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id){
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.fillStyle = "HotPink";
cxt.fillRect(50, 50, 80, 80);
cxt.clearRect(60, 60, 50, 50);
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-18所示。
图2-18 clearRect()清空指定区域的矩形
这里使用clearRect()方法来清空指定区域的矩形。这个例子分析如图2-19所示。
图2-19 clearRect()清空指定区域的矩形(分析图)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.fillStyle = "HotPink";
cxt.fillRect(50, 50, 80, 80);
var btn = $$("btn");
btn.onclick = function () {
cxt.clearRect(0, 0, cnv.width, cnv.height);
}
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas><br />
<input id="btn" type="button" value="清空canvas"/>
</body>
</html>
在浏览器中的预览效果如图2-20所示。
图2-20 clearRect()清空整个Canvas
cxt.clearRect(0, 0, cnv.width, cnv.height);用于清空整个Canvas。其中,cnv.width表示获取Canvas的宽度,cnv.height表示获取Canvas的高度。“清空整个Canvas”这个技巧在Canvas动画开发中会经常用到,大家一定要记住。至于怎么用,在接下来的章节里,我们会慢慢接触到。
最后再次强调一下:所有Canvas图形操作的属性和方法都是基于context对象的。
从之前的学习我们知道,可以将moveTo()和lineTo()配合使用来画三角形和矩形。其实在Canvas中,多边形也是使用moveTo()和lineTo()这两个方法画出来的。
如果我们想要在Canvas中画多边形,则需要事先在草稿纸或软件中计算出多边形中各个顶点的坐标,然后再使用moveTo()和lineTo()在Canvas中画出来。
跟矩形不一样,Canvas没有专门用来绘制三角形和多边形的方法。对于三角形以及多边形,我们也是使用moveTo()和lineTo()这两个方法来实现。
对于箭头,我们都是事先确定箭头的7个顶点坐标,然后使用moveTo()和lineTo()来绘制出来的。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.moveTo(40, 60);
cxt.lineTo(100, 60);
cxt.lineTo(100, 30);
cxt.lineTo(150, 75);
cxt.lineTo(100, 120);
cxt.lineTo(100, 90);
cxt.lineTo(40, 90);
cxt.lineTo(40, 60);
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-21所示。
图2-21 Canvas绘制箭头
在绘制之前,首先需要计算出箭头各个顶点的坐标。
正多边形在实际开发中也经常见到,要想绘制正多边形,需首先了解一下最简单的正多边形,即正三角形。正三角形分析图如图2-22所示。
图2-22 正三角形分析图
根据正三角形的特点,可以将其封装一个绘制正多边形的函数:createPolygon()。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
//调用自定义的方法createPolygon()
createPolygon(cxt, 3, 100, 75, 50);
cxt.fillStyle = "HotPink";
cxt.fill();
}
/*
* n:表示n边形
* dx、dy:表示n边形中心坐标
* size:表示n边形的大小
*/
function createPolygon(cxt, n, dx, dy, size) {
cxt.beginPath();
var degree = (2 * Math.PI )/ n;
for (var i = 0; i < n; i++) {
var x = Math.cos(i * degree);
var y = Math.sin(i * degree);
cxt.lineTo(x * size + dx, y * size + dy);
}
cxt.closePath();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-23所示。
图2-23 正三角形
cxt.beginPath();用于开始一条新路径,cxt.closePath();用于关闭路径。对于beginPath()和closePath()这两个方法,我们在“第10章 Canvas路径”中将会详细介绍,这里不需要深入太多。
在这个例子中,我们定义了一个绘制多边形的函数。对于这个函数,可以加入更多的参数如颜色、边框等,然后可以把它封装到我们的私人图形库里面去。
当createPolygon(cxt, 3, 100, 75, 50);改为createPolygon(cxt, 4, 100, 75, 50);时,浏览器中的预览效果如图2-24所示。
图2-24 正四边形(即正方形)
当createPolygon(cxt, 3, 100, 75, 50);改为createPolygon(cxt, 5, 100, 75, 50);时,浏览器中的预览效果如图2-25所示。
图2-25 正五边形
当createPolygon(cxt, 3, 100, 75, 50);改为createPolygon(cxt, 6, 100, 75, 50);时,浏览器中的预览效果如图2-26所示。
图2-26 正六边形
createPolygon()只能绘制“正多边形”,不可以用于绘制“不规则多边形”。对于“不规则多边形”,方法也很简单,我们都是先确定多边形各个定点坐标,然后使用moveTo()和lineTo()慢慢绘制。
同样地,我们也可以先获取各个顶点的坐标,然后使用moveTo()和lineTo()把五角星绘制出来。根据图2-27的分析,我们可以知道∠BOA=36°,∠A0X=18°,∠BOX=54°,然后结合三角函数,就很容易得出五角星各个顶点的坐标。大家自己在草稿中算一下,这里就不详细展开了。分析如图2-27所示。
图2-27 五角星顶点分析
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
cxt.beginPath();
for (var i = 0; i < 5; i++) {
cxt.lineTo(Math.cos((18 + i * 72) * Math.PI / 180) * 50 + 100,
-Math.sin((18 + i * 72) * Math.PI / 180) * 50 + 100);
cxt.lineTo(Math.cos((54 + i * 72) * Math.PI / 180) * 25 + 100,
-Math.sin((54 + i * 72) * Math.PI / 180) * 25 + 100);
}
cxt.closePath();
cxt.stroke();
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-28所示。
图2-28 Canvas绘制五角星
当然,对于本节这些多边形的绘制,我们可以封装成一个个函数,以便实际开发中直接调用。
我们在使用绘图软件或取色软件的过程中,经常会见到各种调色板效果。常见的调色板有两种,即方格调色板和渐变调色板。在这里我们将使用本章所学到的绘图方法来绘制这两种调色板。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
for (var i = 0; i < 6; i++) {
for (var j = 0; j < 6; j++) {
cxt.fillStyle = "rgb(" + Math.floor(255 - 42.5 * i) + "," + Math.floor(255 - 42.5 * j) + ",0)";
cxt.fillRect(j * 25, i * 25, 25, 25);
}
}
}
</script>
</head>
<body>
<canvas id="canvas" width="200" height="200" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-29所示。
图2-29 Canvas绘制方格调色板
对于这种方格色板,实现思路非常简单:我们可以使用两层for循环来绘制方格阵列,每个方格使用不同的颜色。其中变量i和j用来为每一个方格产生唯一的RGB色彩值。我们仅修改其中的红色和绿色的值,而保持蓝色的值不变,就可以产生各种各样的色板。
接下来我们尝试绘制一个更加复杂的调色板:渐变调色板。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta charset="utf-8" />
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
var r = 255, g = 0, b = 0;
for (i = 0; i < 150; i++) {
if (i < 25) {
g += 10;
} else if (i > 25 && i < 50) {
r -= 10;
} else if (i > 50 && i < 75) {
g -= 10;
b += 10;
} else if (i >= 75 && i < 100) {
r += 10;
} else {
b -= 10;
}
cxt.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
cxt.fillRect(3 * i, 0, 3, cnv.height);
}
}
</script>
</head>
<body>
<canvas id="canvas" width="255" height="150" style="border:1px dashed gray;"></canvas>
</body>
</html>
在浏览器中的预览效果如图2-30所示。
图2-30 Canvas绘制渐变调色板
是不是感到很有趣呢?现在我们也可以开发一个属于自己的调色板了。