基础内容
<canvas>
标签只有两个属性——width
和height
(可选),默认值(width:300px,height:150px); 它们表示画布的实际宽度和高度,绘制的图形都在这上面。而style中的width和height则是canvas在浏览器中被渲染的宽度和高度。两者比例不一样会出现扭曲。<canvas>
标签的替换内容,不支持<canvas>
的浏览器会忽略容器并在其中渲染后备内容。<canvas id="stockGraph" width="150" height="150"> current stock price: $3.15 +0.15 </canvas> <canvas id="clock" width="150" height="150"> <img src="images/clock.png" width="150" height="150" alt=""/> </canvas>
</canvas>
标签不可省, 否则文档其余部分会被认为是替代内容,将不会显示出来。<canvas>
元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。可以通过getContext()
方法(只有一个参数:上下文的格式)来获得渲染上下文和它的绘画功能。var canvas = document.getElementById('tutorial'); var ctx = canvas.getContext('2d');
- 检测支持性
var canvas = document.getElementById('tutorial'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); // drawing code here } else { // canvas-unsupported code here }
绘制图形
<canvas>
只支持两种形式的图形绘制:矩形和路径(由一系列点连成的线段)
canvas提供了三种方法绘制矩形:
fillRect(x, y, width, height)
绘制一个填充的矩形strokeRect(x, y, width, height)
绘制一个矩形的边框clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明
绘制路径
基本步骤:
- 创建路径起始点
- 使用画图命令去画出路径
- 把路径封闭
- 可通过描边或填充路径区域来渲染图形
所用到的函数:
beginPath()
- 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径
- 本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置,然后我们就可以重新绘制新的图形。
- 注意:当前路径为空,即调用
beginPath()
之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo()
,出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。
closePath()
- 闭合路径之后,图形绘制命令又重新指向到上下文中。
- 该方法不是必须的。
- 调用
fill()
函数时,没有闭合的形状都会自动闭合。调用stroke()
不会自动闭合。
stroke
通过线条来绘制图形轮廓fill()
通过填充路径的内容区域生成实心的图形
代码示例:
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill();
}
}
移动笔触
moveTo(x, y)
将笔触移动到指定的坐标x以及y上
可以使用moveTo()
来绘制一些不连续的路径。
代码示例:
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // 绘制
ctx.moveTo(110, 75);
ctx.arc(75, 75, 35, 0, Math.PI, false); // 口(顺时针)
ctx.moveTo(65, 65);
ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // 左眼
ctx.moveTo(95, 65);
ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // 右眼
ctx.stroke();
绘制线
lineTo(x, y)
绘制一条从当前位置到指定(x, y)位置的直线
绘制圆弧
arc(x, y, radius, startAngle, endAngle, anticlockwise)
- 画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
- 注意:arc()函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式:
弧度=(Math.PI/180)*角度
arcTo(x1, y1, x2, y2, radius)
- 根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点
- x1, y1 第一个控制点的坐标;x2, y2 第二个控制点的坐标, radius圆弧的半径
绘制二次贝塞尔曲线及三次贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
// 二次贝塞尔曲线
ctx.beginPath();
ctx.moveTo(75, 25);
ctx.quadraticCurveTo(25, 25, 25, 62.5);
ctx.quadraticCurveTo(25, 100, 50, 100);
ctx.quadraticCurveTo(50, 120, 30, 125);
ctx.quadraticCurveTo(60, 120, 65, 100);
ctx.quadraticCurveTo(125, 100, 125, 62.5);
ctx.quadraticCurveTo(125, 25, 75, 25);
ctx.stroke();
//三次贝塞尔曲线
ctx.beginPath();
ctx.moveTo(75, 40);
ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
ctx.fill();
绘制矩形
除了直接在画布上绘制矩形的三个额外方法:
fillRect(x, y, width, height)
绘制一个填充的矩形strokeRect(x, y, width, height)
绘制一个矩形的边框clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明
还有rect()
方法,将一个矩形路径增加到当前的路径上
rect(x, y, width, height)
绘制一个左上角坐标为(x,y),宽高为width以及height的矩形。
当该方法执行的时候,moveTo()方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置回默认坐标。
Path2D对象
Path2D()
(实验中的功能,浏览器兼容性迷)
- Path2D() 构造函数返回一个新的 Path2D 对象的实例,可以选择另一条路径作为参数(创建一个拷贝),或者选择 SVG path 数据构成的字符串。
new Path2D(); // 空的Path对象 new Path2D(path); // 克隆Path对象 new Path2D(d); // 从SVG建立Path对象
- Path2D API 添加了 addPath作为将path结合起来的方法。当你想要从几个元素中来创建对象时,这将会很实用。比如:
Path2D.addPath(path [, transform])
添加了一条路径到当前路径(可能添加了一个变换矩阵)
MDN Path2D()
图形上色
默认情况下,为黑色
fillStyle
设置图形的填充颜色strokeStyle
设置图形的轮廓颜色
设置透明度
globalAlpha = transparencyValue
- 这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。
- 该属性在绘制大量拥有相同透明度的图形时候相当高效。
其实可以直接通过rgba()
的形式,设置透明度
设置线的样式
-
lineWidth = value
设置线条宽度 -
lineCap = type
设置线条末端样式:butt
round
square
-
lineJoin = type
设置线条与线条间接合处的样式:round
bevel
miter
(默认)
-
miterLimit = value
限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。 -
getLineDash()
返回一个包含当前虚线样式,长度为非负偶数的数组。 -
setLineDash(segments)
设置当前虚线样式。接受一个数组,来指定线段与间隙的交替 -
lineDashOffset = value
设置虚线样式的起始偏移量。
渐变
createLinearGradient(x1, y1, x2, y2)
(x1, y1) 渐变的起点 (x2, y2) 渐变的终点createRadialGradient(x1, y1, r1, x2, y2, r2)
var lineargradient = ctx.createLinearGradient(0,0,150,150); var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);
可以使用addColorStop
方法给它上色
gradient.addColorStop(position, color)
position 是一个0.0 到1.0之间的数值,表示渐变中颜色所在的相对位置。
图案样式
createPattern(image, type)
image 可以是一个Image对象的引用,或者另一个canvas对象。
type: 必须是下面的字符串值之一: repeat
repeat-x
repeat-y
no-repeat
注意: 用 canvas 对象作为 Image 参数在 Firefox 1.5 (Gecko 1.8) 中是无效的。
var img = new Image();
img.src = 'someimage.png';
var ptrn = ctx.createPattern(img,'repeat');
注意: 与 drawImage 有点不同,你需要确认 image 对象已经装载完毕,否则图案可能效果不对的。
阴影
shadowOffsetX = float
shadowOffsetY = float
用来设定阴影在x和y轴的延伸距离。负值向上向左延伸,正值向下向右延伸。默认为0shadowBlur = float
用于设定阴影的模糊程度,默认0shadowColor = color
设定阴影的颜色效果,默认全透明的黑色
Canvas填充规则
当我们用到 fill
(或者clip
和isPointinPath
)你可以选择一个填充规则,该填充规则根据某处在路径的外面或者里面来决定该处是否被填充,这对于自己与自己路径相交或者路径被嵌套的时候是有用的。
值:
- “nonzero”: non-zero winding rule, 默认值.
- “evenodd”: even-odd winding rule.
绘制文本
fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的strokeText(text, x, y [, maxWidth])
在指定的(x, y) 位置绘制文本边框,绘制的最大宽度是可选的
设置文本样式:
font = value
默认字体10px sans-serif
textAlign = value
文本对齐选项, 可选值包括:start
end
left
right
center
默认值为start
textBaseline = value
基线对齐选项,可选值包括:top
hanging
middle
alphabetic
ideographic
bottom
默认值为alphabetic
direction = value
文本方向 可选值:ltr
rtl
inherit
默认值为:inherit
预测量文本宽度:
measureText()
将返回一个TextMetrics
对象的宽度,所在像素,这些体现文本特性的属性
使用图像
基本步骤:
- 获得图片源(
HTMLImageElement
对象/canvas元素的引用/图片URL) - 使用
drawImage()
函数将图片绘制到画布上
图片源:
HTMLImageElement
:由Image()
函数构造出来的,或者任何的<img>
元素HTMLVideoElement
:<video>
元素作为图片源,可以从当前视频中抓取当前帧作为一个图像HTMLCanvasElement
:<canvas>
元素作为图片源ImageBitmap
:一个高性能的位图,可以低延迟的绘制,它可以从上述的所有源以及其它几种源中生成
这些源统一由CanvasImageSource
类型来引用
MDN 使用图像 Using images
缩放Scaling
drawImage(image, x, y, width, height)
这个方法多了2个参数:width 和 height,这两个参数用来控制 当向canvas画入时应该缩放的大小
切片Slicing
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用。其它8个参数最好是参照右边的图解,前4个是定义图像源的切片位置和大小,后4个则是定义切片的目标显示位置和大小。
过渡缩放图像可能会导致图像模糊或像素化,可以使用绘图环境的imageSmoothingEnabled
属性来控制是否在缩放图像时使用平滑算法。默认值为true,即启用平滑缩放。
变形
变形是一种更强大的方法,可以将原点移动到另一点、对网格进行旋转和缩放。
状态的保存和恢复
save()
保存画布(canvas)的所有状态restore()
save
和restore
方法是用来保存和恢复canvas状态的,都没有参数。
canvas的状态就是当前画面应用的所有样式和变形的一个快照。
你可以调用任意多次save方法,每一次调用restore方法,上一个保存的状态就从栈中弹出,所有设定都恢复。
移动
translate(x, y)
translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量,如右图所示。
旋转
rotate(angle)
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate 方法。
缩放
scale(x, y)
缩放画布的水平和垂直的单位。
变形
transform(a, b, c, d, e, f)
这个方法是将当前的变形矩阵乘上一个基于自身参数的矩阵
如果任意一个参数是Infinity,变形矩阵也必须被标记为无限大,否则会抛出异常
参数如下:
a(m11)
水平方向的缩放b(m12)
竖直方向的倾斜偏移c(m21)
水平方向的倾斜偏移d(m22)
竖直方向的缩放e(dx)
水平方向的移动f(dy)
竖直方向的移动
setTransform(a, b, c, d, e, f)
这个方法会将当前的变形矩阵重置为单位矩阵,然后用相同的参数调用 transform 方法。如果任意一个参数是无限大,那么变形矩阵也必须被标记为无限大,否则会抛出异常。从根本上来说,该方法是取消了当前变形,然后设置为指定的变形,一步完成。
resetTransform()
重置当前变形为单位矩阵,它和调用以下语句是一样的:ctx.setTransform(1, 0, 0, 1, 0, 0);
组合Compositing
globalCompositeOperation = type
这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识12种遮盖方式的字符串。
裁切路径
裁切路径和普通的 canvas 图形差不多,不同的是它的作用是遮罩,用来隐藏不需要的部分。如右图所示。红边五角星就是裁切路径,所有在路径以外的部分都不会在 canvas 上绘制出来。
clip()
将当前正在构建的路径转换为当前的裁剪路径。
动画
动画的基本步骤
- 清空canvas:
clearRect()
- 保存canvas状态: 改变一些会改变canvas状态的设置,又要在每画一帧之时都是原始状态的话,需要保存一下
- 绘制动画图形: 重绘动画帧
- 恢复canvas状态
操控动画
setInterval(function, delay)
设定好间隔时间后,function会定期执行setTimeout(function, delay)
在设定好的时间之后执行函数requestAnimationnFrame(callback)
告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画
注意: 采用 window.requestAnimationFrame()
实现动画效果。这个方法提供了更加平缓并更加有效率的方式来执行动画,当系统准备好了重绘条件的时候,才调用绘制动画帧。一般每秒钟回调函数执行60次,也有可能会被降低。
像素操作
ImageData对象
ImageData
对象中存储着canvas对象真实的像素数据,它包含以下几个只读属性:
width
图片宽度,单位是像素height
图片高度,单位是像素data
Uint8ClampedArray
类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)
包含高度 x 宽度 x 4 bytes数据,索引值从0到(高度 x 宽度 x 4)- 1
创建一个ImageData
对象
-
createImageData()
创建了一个新的具体特定尺寸的ImageData对象。所有像素被预设为透明黑。var myImageData = ctx.createImageData(width, height);
创建一个被anotherImageData对象指定的相同像素的ImageData对象。这个新的对象像素全部被预设为透明黑。这个并非复制了图片数据。
var myImageData = ctx.createImageData(anotherImageData);
得到场景像素数据
getImageData()
方法
var myImageData = ctx.getImageData(left, top, width, height);
注意: 任何在画布以外的元素都会被返回成一个透明黑的ImageData对像。
在场景中写入像素数据
putImageData
: 对场景进行像素数据的写入ctx.putImageData(myImageData, dx, dy);
dx 和 dy 参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标
通过修改像素数据的数值,可以对图形进行灰度处理和反相颜色处理
缩放和反锯齿
imageSmoothingEnabled
反锯齿, 默认是启用的。
保存图片
HTMLCanvasElement
提供一个toDataURL()
方法。 它返回一个包含被类型参数规定的的图像表现格式的数据链接。返回的图片分辨率是96dpi.
canvas.toDataURL('image/png')
默认设定。创建一个PNG图片canvas.toDataURL('image/jpeg', quality)
创建一个JPG图片。你可以有选择地提供从0到1的品质质量,1表示最好品质,0基本不被解析,但有比较小的文件大小。- 你可以将数据链接用于任何
<image>
元素,或者将它放在一个有download属性的超链接里用于保存到本地。 canvas.toBlob(callback, type, encoderOptions)
- 这个创建了一个在画布中的代表图片的Blob对象