<canvas>标签

<canvas> 是 HTML5 新增的元素,可用于通过使用 JavaScript 中的脚本来绘制图形。使用<canvas>标签时,建议要成对出现,不要使用闭合的形式。

IE9 之前的浏览器不支持 canvas,可以在<canvas>标签中提供替换内容。支持 canvas 的浏览器将会忽略在容器中包含的内容,并正常渲染 canvas。不支持 canvas 的浏览器会显示代替内容。

1
2
3
<canvas id="test" width="300" height="300">
<span>您的浏览器不支持画布元素</span>
</canvas>

canvas 自身属性

<canvas>标签只有两个可选属性:width 和 height。所设置的宽高为画布在对应方向的 CSS 像素个数。当没有设置宽高的时候,会初始化宽度为 300 像素、高度为 150 像素。不支持在 CSS 中设置 canvas 标签的宽高,会产生其他效果。

<canvas>元素有一个叫做 getContext() 的方法,这个方法只有一个参数,上下文的格式。

1
2
3
4
var canvas = document.getElementById('tutorial')
if (canvas.getContext) {
var ctx = canvas.getContext('2d')
}

矩形绘制

canvas 中,矩形是唯一不需要绘制路径的图形。有三种方法绘制矩形:

  1. 绘制一个填充的矩形(填充色默认为黑色):fillRect(x, y, width, height)
  2. 绘制一个矩形的边框(默认边框为:一像素实心黑色):strokeRect(x, y, width, height)
  3. 清除指定矩形区域,让清除部分完全透明:clearRect(x, y, width, height)

x 与 y 指定了画布上所绘制矩形左上角相对于画布左上角的坐标。width 和 height 设置矩形的尺寸。存在边框的话,边框会在 width 和 height 上占据一个边框的宽度,边框宽度在偏移量上下各渲染一半,一旦出现小数边框会向上取整。

需要注意的是,这些方法是作为元素的方法使用的,函数中的数值不加单位。

图形样式

canvas 中有一些设置图形颜色的属性:

  • fillStyle 设置图形的填充颜色,也可以是背景或渐变。
  • strokeStyle 设置图形轮廓的颜色。

默认情况下,线条和填充颜色都是黑色。

lineWidth 用来设置当前绘线的粗细。属性值为正数。描述线段宽度的数字是 0、负数、Infinity 和 NaN 会被忽略。默认值是 1.0。

lineJoin 用来设定线条与线条间接合处的样式(默认是 miter)

  • round:圆角
  • bevel:斜角
  • miter:直角

需要注意的是,canvas 中必须应用图形样式(设置画笔),在进行绘图。

绘制一般路径

路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。

canvas 路径绘制步骤:

  1. 首先,你需要创建路径起始点。
  2. 然后你使用画图命令去画出路径
  3. 之后你把路径封闭。
  4. 一旦路径生成,你就能通过描边或填充路径区域来渲染图形。

相关方法:

  • moveTo(x, y):将笔触移动到指定的坐标 x 以及 y 上,通常用来设置起点。
  • lineTo(x, y):将笔触移动到指定的坐标 x 以及 y 上,绘制一条从当前位置到指定 x 以及 y 位置的直线。
  • stroke():通过线条来绘制图形轮廓。
  • fill():通过填充路径的内容区域生成实心的图形。
  • closePath():通过绘制一条从当前点到开始点的直线来闭合图形。不是必需的。这个方法会之后图重新指向到上下文中。fill()自动调用closePath()
  • beginPath():新建一条路径,图形绘制命令被指向到路径上准备生成路径。路径是由很多子路径构成,这些子路径都是在一个列表中。每次这个方法调用之后,列表清空重置,就可以重新绘制新的图形。

绘制矩形:rect(x, y, width, height)
绘制一个左上角坐标为(x,y),宽高为 width 以及 height 的矩形。当该方法执行的时候,moveTo()方法自动设置坐标参数(0,0)。

lineCap 是 Canvas 2D API 指定如何绘制每一条线段末端的属性。有 3 个可能的值:

  • butt:线段末端以方形结束。
  • round:线段末端以圆形结束。
  • square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域
    默认值是 butt。

save() 可以将当前状态(样式相关和变换相关)放入栈中,保存 canvas 全部状态。保存到栈中的绘制状态有下面部分组成:

  • 当前的变换矩阵。
  • 当前的剪切区域。
  • 当前的虚线列表。
  • 以下属性当前的值:strokeStyle,fillStyle,lineWidth,lineCap,lineJoin…

restore() 将绘图状态栈中顶端的状态弹出到样式容器,将 canvas 恢复到最近的保存状态的方法。如果没有保存状态,此方法不做任何改变。图像的渲染依赖于样式容器。

save()restore()常成对出现,分隔同一画布不同的图形。绘制路径的基本模板如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var canvas = document.querySelector('#test')
if (canvas.getContext) {
var ctx = canvas.getContext('2d')

ctx.save()
//关于样式的设置
//save restore成对出现
ctx.beginPath()
//关于路径
ctx.restore()

ctx.save()
//关于样式的设置
ctx.beginPath()
//关于路径

ctx.fill()
ctx.restore()
}

路径容器、样式容器和样式栈:

  1. 路径容器:
    每次调用路径 api 时,都会往路径容器里做登记;
    调用 beginPath 时,清空整个路径容器。
  2. 样式容器:
    每次调用样式 api 时,都会往样式容器里做登记;
    调用 save 时候,将样式容器里的状态压入样式栈;
    调用 restor 时候,将样式栈的栈顶状态弹出到样式样式容器里,进行覆盖。
  3. 样式栈:
    调用 save 时候,将样式容器里的状态压入样式栈;
    调用 restor 时候,将样式栈的栈顶状态弹出到样式样式容器里,进行覆盖。

绘制曲线

角度与弧度的 js 表达式:radians=(Math.PI/180)*degrees

arc(x, y, radius, startAngle, endAngle, anticlockwise)可以画一个以(x,y)为圆心以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按 anticlockwise 给定方向(默认为顺时针,ture 为逆时针,false 为顺时针)生成。

arcTo(x1, y1, x2, y2, radius)根据给定的控制点和半径画一段圆弧。会从当前位置出发,在(x2 y2)结束。(x1 y1)是控制点,用来控制方向但不一定经过。

quadraticCurveTo(cp1x, cp1y, x, y)绘制二次贝塞尔曲线,cp1x,cp1y 为一个控制点,x,y 为结束点。

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)绘制三次贝塞尔曲线,cp1x,cp1y 为控制点一,cp2x,cp2y 为控制点二,x,y 为结束点。

变换

translate(x, y)用来移动 canvas 的原点到一个不同的位置。x 是左右偏移量,y 是上下偏移量。在 canvas 中 translate 是累加的。

rotate(angle)可以以顺时针偏转一定的角度,以弧度为单位。旋转的中心点始终是 canvas 的原点,如果要改变原点需要用到 translate 方法。在 canvas 中 rotate 是累加的。

scale(x, y)用来缩放图画,x,y 分别是横轴和纵轴的缩放因子,必须是正值。值比 1.0 小表示缩小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。一般用它来增减图形在 canvas 中的像素数目,对形状、位图进行缩小或者放大,图像的像素不发生变化。在 canvas 中 scale 是累加的。

插入图片和图片背景

  1. canvas 操作图片时,必须要等图片加载完才能操作;
  2. drawImage(image, x, y, width, height)
    其中 image 是 image 或者 canvas 对象,x 和 y 是其在目标 canvas 里的起始坐标,width 和 height 用来控制当图片插入时应该缩放的大小。

使用Image类创建图片,在图片加载完成后添加到画布中:

1
2
3
4
5
6
7
8
var img = new Image()
img.src = '1.png'
img.onload = function () {
draw()
}
function draw() {
ctx.drawImage(img, 0, 0, img.width, img.height)
}

图片也可作为背景插入到画布中:

1
2
3
4
5
6
7
8
9
10
11
var img = new Image()
img.src = '1.png'
img.onload = function () {
draw()
}

function draw() {
var pattern = ctx.createPattern(img, 'no-repeat')
ctx.fillStyle = pattern
ctx.fillRect(0, 0, 300, 300)
}

createPattern(image, repetition)
用来设置背景图片,第一个参数 image:图像源。第二个参数 repetition:”repeat”、”repeat-x”、”repeat-y”、”no-repeat”。
一般情况下,将 createPattern 返回的对象作为 fillstyle 的值,并在 fillRect 中设置背景大小。

渐变背景

与 CSS3 的渐变类似,分为线性渐变和径向渐变。

线性渐变使用createLinearGradient(x1, y1, x2, y2),(x1,y1)、(x2,y2)
表示渐变的起点与终点。
gradient.addColorStop(position, color)用来设置渐变的颜色和位置,gradient 是 createLinearGradient 的返回值:

  • position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置;
  • color 参数是一个有效的 CSS 颜色值。
1
2
3
4
5
6
var gradient = ctx.createLinearGradient(0, 0, 200, 200)
gradient.addColorStop(0, 'red')
gradient.addColorStop(0.5, 'yellow')
gradient.addColorStop(1, 'green')
ctx.fillStyle = gradient
ctx.fillRect(0, 0, 300, 300)

与线性渐变类似,径向渐变更换了函数createRadialGradient(x1, y1, r1, x2, y2, r2)。其中前三个参数则定义另一个以(x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。

像素操作

getImageData(sx, sy, sw, sh)获得一个包含画布场景像素数据的 ImageData 对象,它代表了画布区域的对象数据。sx 和 sy 表示将要被提取的图像数据矩形区域的左上角 x 和 y 坐标。sw 和 sh 表示将要被提取的图像数据矩形区域的宽度和高度。

ImageData 对象中存储着 canvas 对象真实的像素数据,它包含以下几个只读属性:

  • width:图片宽度,单位是像素
  • height:图片高度,单位是像素
  • data:Uint8ClampedArray 类型的一维数组,包含着 RGBA 格式的整型数据,范围在 0 至 255 之间。

putImageData(myImageData, dx, dy)方法去对场景进行像素数据的写入。dx 和 dy 参数表示在场景内绘制区域的左上角坐标。

createImageData(width, height)用来创建ImageData 对象。

图片的覆盖合成

全局透明度通过globalAlpha = value设置,影响到 canvas 里所有图形的透明度,值为 0 到 1,默认为 1。

定义下面两个概念:

  • source:新的图像(源);
  • destination:已经绘制过的图形(目标)。

通过globalCompositeOperation设置合成图像的显示,有如下取值:

  • “source-over”(默认值):源在上面,新的图像层级比较高
  • “source-in”:只留下源与目标的重叠部分(源的那一部分)
  • “source-out”:只留下源超过目标的部分
  • “source-atop”:砍掉源溢出的部分
  • “destination-over”:目标在上面,旧的图像层级比较高
  • “destination-in”:只留下源与目标的重叠部分(目标的那一部分)
  • “destination-out”:只留下目标超过源的部分
  • “destination-atop”:砍掉目标溢出的部分

事件

canvas 中有一个事件可以在选到画布中某些位置时触发:isPointInPath(x, y)。这个方法用于判断在当前路径中是否包含检测点,x 和 y 是检测点的 XY 坐标。此方法只作用于最新画出的 canvas 图像,即最后一个 beginPath()后的路径。