目录
一、Canvas简介
二、Canvas基本用法
三、填充和描边
四、绘制矩形
五、绘制路径
5.1、绘制线段
5.2、绘制三角形
5.3、绘制圆弧
5.4、绘制贝塞尔曲线
5.5、线条样式
六、绘制文本
七、绘制图像
八、模式
九、使用图像数据
十、阴影
一、Canvas简介
元素是HTML5新增的,一个可以使用脚本(通常为JavaScript)在其中绘制图像的HTML元素。它可以用来制作照片集或者制作简单的动画,甚至可以进行实时视频处理和渲染。
由几组API构成,除了具备基本绘图能力的2D上下文,还具备一个名为WebGL的3D上下文。
二、Canvas基本用法
使用元素之前,必须先设置其width和height属性,指定可以绘图的区域大小。
出现在开始和结束标签中的内容是后备信息,如果浏览器不支持元素,就会显示这些信息。
要在这块画布上绘图,需要使用getContext()方法传入参数"2d"取得2D上下文对象。
var drawing = document.getElementById("drawing");
//确定浏览器支持
使用2D绘图上下文提供的方法,可以绘制简单的2D图形,比如矩形、弧线和路径。
2D上下文的坐标开始于元素的左上角,原点坐标是(0,0)。
所有坐标值都基于这个原点计算,x值越大表示越靠右,y值越大表示越靠下。
三、填充和描边
2D上下文的两种基本绘图操作是填充和描边。
填充就是用指定的样式(颜色、渐变或图像)填充图形,fillStyle属性设置填充样式。
描边就是只在图形的边缘画线,strokeStyle属性设置描边样式。
这两个属性的值可以是字符串、渐变对象或模式对象,例如:
var drawing = document.getElementById("drawing");
//确定浏览器支持
四、绘制矩形
与绘制矩形有关的方法包括:
- fillRect()
- strokeRect()
- clearRect()
这三个方法都能接收4个参数:矩形的x坐标、矩形的y坐标、矩形的宽度和矩形高度。参数单位都是像素。
示例1:
var drawing = document.getElementById("drawing");
//确定浏览器支持
示例2:
var drawing = document.getElementById("drawing");
//确定浏览器支持
示例3:
var drawing = document.getElementById("drawing");
//确定浏览器支持
五、绘制路径
绘制路径的方法:
- beginPath() —— 表示要开始绘制新路径。
- moveTo(x, y) —— 将绘图游标移动到(x, y),不画线。
- lineTo(x, y) —— 从上一点开始绘制一条直线,到(x, y)为止。
- rect(x, y, width, height) —— 从点(x,y)开始绘制一个矩形,宽度和高度分别由width和height指定。这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的独立的形状。
- arc(x, y, radius, startAngle, endAngle, counterclockwise) —— 以(x,y)为圆心绘制一条弧线,弧线半径为radius,起始和结束角度(用弧度表示)分别为startAngle和endAngle。最后一个参数表示startAngle和endAngle是否按逆时针方向计算,值为true表示按逆时针方向计算。
- quadraticCurveTo(cx, cy, x, y) —— 绘制二次贝塞尔曲线
- bezierCurveTo(c1x, c1y, c2x, c2y, x, y) —— 绘制三次贝塞尔曲线
- closePath() —— 绘制一条连接到路径起点的线条。
- fill() —— 使用fillStyle填充已经完成的路径
- stroke() —— 使用strokeStyle为已经完成的路径描边
5.1、绘制线段
var drawing = document.getElementById("drawing");
//确定浏览器支持
5.2、绘制三角形
绘制三角形边框:
var drawing = document.getElementById("drawing");
//确定浏览器支持
填充三角形:
var drawing = document.getElementById("drawing");
//确定浏览器支持
5.3、绘制圆弧
var drawing = document.getElementById("drawing");
//确定浏览器支持
5.4、绘制贝塞尔曲线
二次贝塞尔曲线:
var drawing = document.getElementById("drawing");
//确定浏览器支持
三次贝塞尔曲线:
var drawing = document.getElementById("drawing");
//确定浏览器支持
5.5、线条样式
lineWidth属性用于设置线宽
var drawing = document.getElementById("drawing");
//确定浏览器支持
lineCap属性用于设置线条末端样式,可以设置为三个值:
- butt —— 线段末端为方形
- round —— 线段末端以圆形结束
- square —— 线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
var drawing = document.getElementById("drawing");
//确定浏览器支持
lineJoin属性用于设置线条与线条间接合处的样式,可以设置为三个值:
- round —— 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。圆角的半径是线段的宽度。
- bevel —— 在相连部分的末端填充一个额外的以三角形为底的区域,每个部分都有各自独立的矩形拐角。
- miter(默认) —— 通过延沈相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
var drawing = document.getElementById("drawing");
//确定浏览器支持
六、透明度
globalAlpha属性用于指定所有绘制的透明度,默认值为0。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
七、变换
7.1、translate()
translate(x, y)用于将坐标原点移动到(x, y),执行这个变换后,坐标(0, 0)会变成之前由(x, y)表示的点。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
7.2、rotate(angle)
rotate(angle)方法能够旋转坐标轴。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
7.3、scale(scaleX, scaleY)
scale(scaleX, scaleY)方法用于缩放图像,在x方向乘以scaleX,在y方向乘以scaleY。
scaleX和scaleY的默认值都是1.0
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
7.4、transform(a, b, c, d, e, f)
直接修改变换矩阵,方式是乘以如下矩阵:
7.5、setTransform(a, b, c, d, e, f)
将变换矩阵重置为默认状态,然后再调用transform()。
八、save()和restore()
调用save()方法,当时所有的设置都会进入一个栈结构,得以妥善保管。
然后可以对上下文进行其他修改,等想要回到之前保存的设置时,可以调用restore()方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。
连续调用save()可以把更多设置保存到栈结构中,之后再连续调用restore()则可以一级一级返回。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
九、绘制文本
绘制文本主要有两个方法:
这两个方法都可以接收4个参数:要绘制的文本字符串、x坐标、y坐标和可选的最大像素宽度。
这两个方法都以下列3个属性为基础:
- font —— 表示文本样式、大小及字体,用CSS中指定字体的格式来指定,例如"10px Arial"
- textAlign —— 表示文本对齐方式。可能的值有"start"、"end"、"left"、"right"和"center"
- textBaseline —— 表示文本的基线,可能的值有"top"、"hanging"、"middle"、"alphabetic"、"ideographic"、"bottom"
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
fillText()和strokeText()方法都可以接收第四个参数,也就是文本的最大像素宽度。提供这个参数后,调用fillText()或strokeText()时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。
十、绘制图像
2D绘图上下文内置了对图像的支持,可以使用drawImage()方法。
drawImage()有9个参数:要素绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度。
①绘制图像简单示例:
var drawing = document.getElementById("drawing");
var img = new Image(); //创建Image对象
img.src = 'https://avatar.csdn.net/6/4/D/1_qq_35732147.jpg?1539065138'; //设置图片源
//确定浏览器支持
使用DOM0级的Image对象可以在客户端预先加载图像,可以像使用元素一样使用Image对象,但无法将其添加到DOM树中。
考虑到图片是从网络加载,所以应该保证图像加载完之后再调用drawImage()方法绘制图像。
②缩放图片简单示例:
var drawing = document.getElementById("drawing");
var img = new Image(); //创建Image对象
img.src = 'https://avatar.csdn.net/6/4/D/1_qq_35732147.jpg?1539065138'; //设置图片源
//确定浏览器支持
③切片
切片示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
十一、模式
模式其实就是重复的图像,可以用来填充或描边图形。
要创建一个新模式,可以调用createPattern()方法并传入两个参数:
- HTML元素
- 表示如何重复图像的字符串,这个参数的值与CSS的background-repeat属性值相同,包括"repeat"、"repeat-x"、"repeat-y"、"no-repeat"
var drawing = document.getElementById("drawing");
//确定浏览器支持
十二、使用图像数据
canvas操作图像数据使用的几个方法:
①getImageData() —— 用于取得画布上指定矩形的像素数据。
具体是这个方法会返回ImageData对象,ImageData对象中包含图像数据。
getImageData()方法接收4个参数:
- 要取得画面区域左上角的x坐标
- 要取得画面区域左上角的y坐标
- 要取得画面区域的像素宽度
- 要取得画面区域的像素高度
例如要取得左上角坐标为(10,5)、大小为50*50像素的区域的图像数据:
var imageData = context.getImageData(10, 5, 50, 50);
返回的对象是ImageData的实例,每个ImageData对象都有三个属性:
- width —— 图像的宽度
- height —— 图像的高度
- data —— 保存图像中每一个像素的数据的数组,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度值。
②putImageData() —— 把图像数据(从指定的ImageData对象)放回画布上。
这个方法接收以下参数:
下面的代码通过getImageData()取得画布上指定矩形的像素数据,然后通过putImageData()将图像数据放回画布:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="green";
ctx.fillRect(10,10,50,50);
var imgData=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData,10,70);
③createImageData() —— 创建新的、空白的ImageData对象
这个方法接收的参数:
以下代码创建100*100像素的ImageData对象,其中每个像素都是红色的,然后把它放到画布上:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var imgData=ctx.createImageData(100,100);
for (var i=0;i
效果:
示例:
创建一个简单的灰阶过滤器:
var drawing = document.getElementById("drawing");
//确定浏览器支持
注意:只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。如果画布”不干净“,那么访问图像数据时会导致JavaScript错误。
十三、阴影
2D上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。
- shadowColor —— 用CSS颜色格式表示的阴影颜色,默认为黑色。
- shadowOffsetX —— 形状或路径x轴方向的阴影偏移量,默认为0。
- shadowOffsetY —— 形状或路径y轴方向的阴影偏移量,默认为0。
- shadowBlur —— 模糊的像素数,默认0,即不模糊。
var drawing = document.getElementById("drawing");
//确定浏览器支持
十四、渐变
渐变由CanvasGradient实例表示,很容易通过2D上下文来创建和修改。
要创建一个新的线性渐变对象,可以调用createLinearGradient()方法。
这个方法接受4个参数:起点的x坐标、起点的y坐标、终点的x坐标、终点的y坐标。
创建了渐变对象后,下一步就是使用addColorStop()方法来指定色标。
这个方法接收两个参数:色标位置和CSS颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
要创建径向渐变(或放射性渐变),可以使用createRadialGradient()方法。
这个方法接收6个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的圆心和半径,后三个参数指定的是终点圆的圆心和半径。
示例:
var drawing = document.getElementById("drawing");
//确定浏览器支持
十五、合成
globalCompositionOperation属性表示后绘制的图形怎样与先绘制的图形结合。
这个属性的值是字符串,可能的值如下:
- source-over(默认值) —— 后绘制的图形位于先绘制的图形上方
- source-in —— 后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明
- source-out —— 后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明
- source-atop —— 后绘制的图形与先绘制的图形重叠部分可见,先绘制图形不受影响
- destination-over —— 后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见
- destination-in —— 后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明
- destination-out —— 后绘制的图形擦除与先绘制的图形重叠的部分
- destination-atop —— 后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明
- lighter —— 后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮
- copy —— 后绘制的图形完全替代与之重叠的先绘制图形
- xor —— 后绘制的图形与先绘制的图形重叠的部分执行“异或”操作
①source-over(默认值)
var drawing = document.getElementById("drawing");
//确定浏览器支持
②source-in
var drawing = document.getElementById("drawing");
//确定浏览器支持
③source-out
var drawing = document.getElementById("drawing");
//确定浏览器支持
④source-atop
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑤destination-over
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑥destination-in
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑦destination-out
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑧destination-atop
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑨lighter
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑩copy
var drawing = document.getElementById("drawing");
//确定浏览器支持
⑾xor
var drawing = document.getElementById("drawing");
//确定浏览器支持
十六、基本动画
16.1、动画的基本步骤
①清空canvas
除非要画的内容会完全充满canvas(例如背景图),否则需要清空所有。
最简单的做法就是用clearRect()方法。
②保存canvas状态
如果要改变一些会改变canvas状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,需要先保存一下。
③绘制动画图形
这一步才是重绘动画帧
④恢复canvas状态
如果已经保存了canvas的状态,可以先恢复它,然后重绘下一帧。
16.2、操纵动画
在canvas上绘制内容是用canvas提供的或者自定义的方法,而通常,我们仅仅在脚本执行结束后才能看见结果,比如说,在for循环里面做完成动画是不太可能的,因为for循环一直高速执行,动画都来不及绘制。
因此,为了实现动画,我们需要一些可以定时执行重绘的方法。
首先,可以用window.setInterval(),window.setTimeout(),和window.requestAnimationFrame()来设定定期执行一个指定函数:
- setInterval(function, delay) —— 当设定好间隔时间后,function会定期执行
- setTimeout(function, delay) —— 在设定好的时间之后执行函数
- requestAnimationFrame(callback) —— 告诉浏览器希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画
如果并不需要与用户互动,可以使用setInterval()方法,它就可以定期执行指定代码。
如果需要做一个游戏,我们可以使用键盘或者鼠标事件配合上setTimeout()方法来实现。
通过设置事件监听,可以捕捉用户的交互,并执行相应的动作。
16.3、太阳系的动画
下面的例子,采用window.requestAnimationFrame()实现动画效果。
这个方法提供了更加平缓并更加有效率的方式来执行动画,当系统准备好了重绘条件的时候,才调用绘制动画帧。
一般每秒钟回调函数执行60次,也有可能会被降低。
一个小型的太阳系模拟动画:
var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
window.requestAnimationFrame(draw);
}
function draw(){
var ctx = document.getElementById("drawing").getContext('2d');
//后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见
ctx.globalCompositeOperation = 'destination-over';
ctx.clearRect(0, 0, 300, 300); //clear canvas
ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)';
ctx.save();
//移动坐标原点
ctx.translate(150, 150);
// Earth
var time = new Date();
ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds() );
ctx.translate(105, 0);
ctx.fillRect(0, -12, 50, 24); //Shadow
ctx.drawImage(earth, -12, -12);
// Moon
ctx.save();
ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds() );
ctx.translate(0, 28.5);
ctx.drawImage(moon, -3.5, -3.5);
ctx.restore();
ctx.restore();
ctx.beginPath();
ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // Earth orbit
ctx.stroke();
ctx.drawImage(sun, 0, 0, 300, 300);
window.requestAnimationFrame(draw);
}
init();