canvas元素本身很简单,只有两个属性width和height来指定元素在屏幕上的大小。canvas元素里包裹的内容会在浏览器不支持canvas元素时作为备用内容展示。canvas所有的功能都体现在JavaScript对象上。

获取画布上下文

为了在canva元素上绘图,需要获得一个画布的上下文对象,这个对象会开放针对特定图形样式的绘图函数,通过在DOM里代表canvas元素的对象HTMLCanvasElement获得上下文,该对象有一个方法是getContext(context)为画布返回绘图的上下文。

绘制矩形

简单的图形方法:

clearRect(x, y, w, h): 清除指定的矩形,return void

fillRect(x, y, w, h): 绘制实心矩形,return void

strokeRect(x, y, w, h): 绘制空心矩形, return void

(x, y): 是从canvas元素左上角算起的偏移量

w, h: 是指定了待绘制矩形的宽和高

示例代码:

html:

<canvas id="rect-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const RectCanvas = document.getElementById('rect-canvas').getContext('2d')

const offset = 10

const size = 50

const count = 5

for (let i = 0; i < count; i++) {

    RectCanvas.fillRect(i * (offset + size) + offset, offset, size, size)

    RectCanvas.strokeRect(i * (offset + size) + offset, (2 * offset) + size, size, size)

    RectCanvas.clearRect(i * (offset + size) + offset, offset + 5, size, size - 10)

}

效果:

设置画布绘制状态

绘图操作由绘制状态配置。

基本的绘制状态属性:

fillStyle: 获取或设置用于实心图形的样式

lineJoin: 获取或设置线条与图形连接时的样式

lineWidth: 获取或设置线条的宽度

strokeStyle: 获取或设置用于线条的样式

示例代码:

html:

<canvas id="drawing-state-canvas" width="350" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const DrawingStateCanvas = document.getElementById('drawing-state-canvas').getContext('2d')

const offset = 10

const size = 50

const count = 5

const lineTypes = ['round', 'bevel', 'miter']

const fillColors = ['black', 'grey', 'lightgrey', 'red', 'blue']

const strokeColors = ['rgb(0, 0, 0)', 'rgb(100, 100, 100)', 'rgb(200, 200, 200)',

'rgb(255, 0, 0)', 'rgb(0, 0, 255)']

for (let i = 0; i < count; i++) {

    DrawingStateCanvas.lineWidth = i * 2  // 线条宽度

    DrawingStateCanvas.lineJoin = lineTypes[i % 3]  // 线条或图形连接时的样式

    DrawingStateCanvas.fillStyle = fillColors[i]  // 实心图形的样式

    DrawingStateCanvas.strokeStyle = strokeColors[i]  // 线条样式

    DrawingStateCanvas.fillRect(i * (offset + size) + offset, offset, size, size)

    DrawingStateCanvas.strokeRect(i * (offset + size) + offset, (2 * offset) + size, size, size)

}

效果:

使用渐变

除了纯色还可以把填充和笔触样式设置成渐变色,渐变是两种或更多颜色之间的渐进转变。canvas元素支持两类渐变:线性和径向。

渐变方法:

createLinearGradient(x0, y0, x1, y1): 创建线性渐变,return CanvasGradient。(x0, y0):开始坐标,(x1, y1):结束坐标

createRadialGradient(x0, y0, r0, x1, y1, r1): 创建径向渐变,return CanvasGradient。(x0, y0):起点圆的圆心坐标,r0:起点圆的半径,(x1, y1):终点圆的圆心半径,r1:终点圆的半径

CanvasGradient对象方法:

addColorStop(position, color): 给渐变的梯度线添加一种纯色,return void。position:在线段上应用颜色的位置,线段的起点由0表示,终点用1表示;color:线段上应用的颜色。

`

线性渐变

线性渐变指的是沿着一条线设定要用的若干颜色。我们在定义梯度线时要相对于画布进行设置,而不是绘制的图形。

示例代码:

html:

<canvas id="linear-gradient-canvas" width="350" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const linearGradientCanvas = document.getElementById('linear-gradient-canvas').getContext('2d')

const grad = linearGradientCanvas.createLinearGradient(0, 0, 350, 140)  // 相对于画布

grad.addColorStop(0, 'red')

grad.addColorStop(0.5, 'white')

grad.addColorStop(1, 'black')

linearGradientCanvas.fillStyle = grad

linearGradientCanvas.fillRect(0, 0, 350, 140)  // 相对于画布

效果:

径向渐变

用两个圆定义径向渐变,渐变的起点由第一个圆定义,终点则是第二个圆,在两者之间添加颜色点。给渐变添加颜色时,他们会被放置在起点圆边界(改点的值为0.0)和终点圆的边界(改点的值为1.0)之间的一条线上。当你设定的一个圆与另一个不存在包含关系时要小心,各种浏览器对于如何开始渐变存在不一致性,结果也很混乱。

示例代码:

html:

<canvas id="radial-gradient-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const radialGradientCanvas = document.getElementById('radial-gradient-canvas').getContext('2d')

const grad = radialGradientCanvas.createRadialGradient(200, 70, 20, 200, 70, 100)

grad.addColorStop(0, 'red')

grad.addColorStop(0.5, 'white')

grad.addColorStop(1, 'black')

radialGradientCanvas.fillStyle = grad  // fillStyle

radialGradientCanvas.fillRect(0, 0, 250, 140)

radialGradientCanvas.lineWidth = 100

radialGradientCanvas.strokeStyle = grad  // strokeStyle

radialGradientCanvas.strokeRect(301, 0, 150, 140)

效果:

使用图案

除了纯色和渐变之外,还可以创建图案。使用画布上下文对象所定义的createPattern方法。2D绘图上下文定义了三种图案类型支持:图像、视频和画布。

createPattern(patternObj, type): patternObj为图案对象;type为重复样式,repeat为图像被垂直和水平重复;repeat-x为图像被水平重复;repeat-y为图像被垂直重复;no-repeat为图像不应当被重复

示例代码:

html:

<canvas id="pattern-gradient-canvas" width="500" height="200">

  Your browser doesn't support the canvas element.

</canvas>

<img id="pattern-img" src="../assets/logo.png" hidden/>

js:

const patternGradientCanvas = document.getElementById('pattern-gradient-canvas').getContext('2d')

const imageElem = document.getElementById('pattern-img')

const pattern = patternGradientCanvas.createPattern(imageElem, 'repeat')

patternGradientCanvas.fillStyle = pattern  // fillStyle

patternGradientCanvas.fillRect(0, 0, 250, 200)

patternGradientCanvas.lineWidth = 20

patternGradientCanvas.strokeStyle = pattern  // strokeStyle

patternGradientCanvas.strokeRect(270, 30, 200, 100)

效果:

图案复制的是img元素的当前状态,当用JavaScript和DOM修改了img元素的src属性的时候,此图案不会改变。

保存和恢复绘制状态

绘制状态保存时会被存放在一个后进先出的栈中,就是当我们用sava方法最后保存的状态会被restore方法首先进行恢复。画布里面的内容不会被保存或恢复,只有绘制状态的属性值才会。

save(): 保存绘制状态属性的值,并把它们推入状态栈

restore(): 取出状态栈的第一组值,用它们来设置绘制状态

绘制图像

使用drawImage方法在画布上绘制图像,图像来源可以是img,video或其他canvas元素的DOM对象。

使用img

drawImage(source, x0, y0, w0, h0, x1, y1, w1, h1)

source:图像的来源

(x0, y0):在源图像内的偏移量

(w0, h0):源图像所需使用区域的宽度和高度

(x1, y1):指定了所选区域的左上角将要在画布上绘制的坐标

(w1, h1):指定了所选区域将要绘制的宽度和高度

此方法可以有三个、五个或九个参数

示例代码:

html:

<canvas id="draw-image-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

<img id="draw-image-img" src="../assets/logo.png" hidden/>

js:

const DrawImageCanvas = document.getElementById('draw-image-canvas').getContext('2d')

const imageElement = document.getElementById('draw-image-img')

DrawImageCanvas.drawImage(imageElement, 0, 0)

DrawImageCanvas.drawImage(imageElement, 220, 0, 100, 100)

DrawImageCanvas.drawImage(imageElement, 50, 50, 100, 100, 350, 10, 100, 100)

效果:

使用video

可以用video元素作为drawImage方法的图像来源。观看各种HTML5演示时,经常会见到canvas被用来在视频上绘图。

使用画布图像

可以将一张画布的内容作为另一张里drawImage方法的图像来源。

用路径绘图

用路径绘制图形,路径本质上是一组独立的线条(被称为子路径),他们组合到一起构成图形。画布上的每一条子路径都以上一条的终点作为起点。

基本路径方法:

beginPath(): 开始一条新路径,return void

closePath(): 尝试闭合现有路径,方法是绘制一条线,连接最后那条线的终点与起始坐标,return void

fill(): 填充用子路径描述的图形,return void

isPointInPath(x, y): 如果指定的点在当前路径所描述的图形之内则返回true,return Boolean

lineTo(x, y): 绘制一条到指定坐标的子路径,return void

moveTo(x, y): 移动到指定坐标而不绘制子路径,return void

rect(x, y, w, h): 绘制一个矩形,其左上角位于(x, y),宽度是我,高度是h,return void

stroke(): 给子路径描述的图形绘制轮廓线,return void

绘制一条路径的基本顺序:

1. 调用beginPath方法

2. 用moveTo方法移动到起点

3. 用arc和lineTo等方法绘制子路径

4. 调用closePath方法(可选)

5. 调用fill或stoke方法

lineCap: 属性设置线条末端样式,选项:butt(默认),round,square

示例代码:

html:

<canvas id="path-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const PathCanvas = document.getElementById('path-canvas').getContext('2d')

PathCanvas.fillStyle = 'yellow'

PathCanvas.strokeStyle = 'black'

PathCanvas.lineWidth = 8

PathCanvas.lineCap = 'round'  // 线条末端样式

// 用线条绘制路径

PathCanvas.beginPath()

PathCanvas.moveTo(10, 10)

PathCanvas.lineTo(100, 10)

PathCanvas.lineTo(100, 120)

PathCanvas.closePath()

PathCanvas.fill()

PathCanvas.stroke()

// 用线条绘制矩形

PathCanvas.beginPath()

PathCanvas.moveTo(220, 10)

PathCanvas.lineTo(220, 100)

PathCanvas.lineTo(120, 10)

PathCanvas.closePath()

PathCanvas.rect(230, 10, 210, 90)

PathCanvas.rect(250, 100, 240, 30)

PathCanvas.fill()

PathCanvas.stroke()

效果:

绘制圆弧

使用arc和arcTo方法在画布上绘制圆弧。

圆弧方法:

arc(x, y, rad, startAngle, endAngle, direction): 绘制一段圆弧到(x, y),半径为rad,其实角度为startAngle,结束角度为endAngle。direction为可选参数指定圆弧方向是按顺时针(false)还是逆时针(true),return void

arcTo(x1, y1, x2, y2): 绘制一段半径为rad,经过(x1, y1),直到(x2, y2)的圆弧,return void

使用arcTo方法

示例代码:

html:

<canvas id="arcTo-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const ArcToCanvas = document.getElementById('arcTo-canvas').getContext('2d')

const point1 = [100, 10]

const point2 = [200, 10]

const point3 = [200, 110]

ArcToCanvas.fillStyle = 'yellow'

ArcToCanvas.strokeStyle = 'black'

ArcToCanvas.lineWidth = 4

// 画圆弧

ArcToCanvas.beginPath()

ArcToCanvas.moveTo(point1[0], point1[1])

ArcToCanvas.arcTo(point2[0], point2[1], point3[0], point3[1], 100)

ArcToCanvas.stroke()

// 画辅助点

drawPoint(point1[0], point1[1])

drawPoint(point2[0], point2[1])

drawPoint(point3[0], point3[1])

// 画辅助线

ArcToCanvas.beginPath()

ArcToCanvas.moveTo(point1[0], point1[1])

ArcToCanvas.lineTo(point2[0], point2[1])

ArcToCanvas.lineTo(point3[0], point3[1])

ArcToCanvas.stroke()

function drawPoint (x, y) {

ArcToCanvas.lineWidth = 1

ArcToCanvas.strokeStyle = 'red'

ArcToCanvas.strokeRect(x - 2, y - 2, 4, 4)

}

效果:

使用arc方法

示例代码:

html:

<canvas id="arc-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const ArcCanvas = document.getElementById('arc-canvas').getContext('2d')

ArcCanvas.fillStyle = 'yellow'

ArcCanvas.lineWidth = 3

// 画圆弧一

ArcCanvas.beginPath()

ArcCanvas.arc(70, 70, 60, 0, Math.PI * 2, true)

ArcCanvas.stroke()

// 画圆弧二

ArcCanvas.beginPath()

ArcCanvas.arc(200, 70, 60, Math.PI / 3, Math.PI, true)

ArcCanvas.fill()

ArcCanvas.stroke()

// 圆弧三

ArcCanvas.beginPath()

let val = 0

for (let i = 0; i < 4; i++) {

ArcCanvas.arc(350, 70, 60, val, val + Math.PI / 4, false)

val += Math.PI / 2

}

ArcCanvas.closePath()

ArcCanvas.fill()

ArcCanvas.stroke()

效果:

绘制贝塞尔线

canvas支持绘制两种贝塞尔曲线:三次和两次

曲线方法:

bezierCurveTo(cx1, cy1, cx2, cy2, x, y): 绘制一段贝塞尔曲线到点(x, y),控制点为(cx1, cy1)和(cx2, cy2),return void

quadraticCurveTo(cx, cy, x, y): 绘制一段二次贝塞尔曲线到点(x, y),控制点为(cx, cy)

创建剪辑区域

以上说到用stroke和fill方法来绘制或填充一条路径,还一种方法用clip裁剪方法也可以做到。一旦定义一块裁剪区域,就只有区域内的路径才会显示到屏幕上。

clip(): 创建新的裁剪区域,return void

示例代码:

html:

<canvas id="clip-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const ClipCanvas = document.getElementById('clip-canvas').getContext('2d')

// 绘制一个填满画布的矩形

ClipCanvas.fillStyle = 'yellow'

ClipCanvas.beginPath()

ClipCanvas.rect(0, 0, 500, 140)

ClipCanvas.fill()

// 绘制裁剪区域

ClipCanvas.beginPath()

ClipCanvas.rect(100, 20, 300, 100)

ClipCanvas.clip()

// 绘制一个填满画布的矩形

ClipCanvas.fillStyle = 'red'

ClipCanvas.beginPath()

ClipCanvas.rect(0, 0, 500, 140)

ClipCanvas.fill()

效果:

绘制文本

可以在画布上绘制文本,不过对这种功能支持的还很初步。

绘制文本方法:

fillText(text, x, y, width): 在位置(x, y)上绘制并填充指定文本。宽度参数可选,它设置了文本宽度的上限。return void

strokeText(text, x, y, width): 在位置(x, y)上绘制并描边指定的文本,它设置了文本宽度的上限。return void

文本绘制方式的绘制状态属性:

font: 设置绘制文本时使用的字体

textAlign: 设置文本的对齐方式:start,end,right,center

textBaseLine: 设置文本的基线:top,hanging,middle,alphabetic,ideographic,bottom

示例代码:

html:

<canvas id="font-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const FontCanvas = document.getElementById('font-canvas').getContext('2d')

FontCanvas.fillStyle = 'lightgrey'

FontCanvas.strokeStyle = 'black'

FontCanvas.lineWidth = 3

FontCanvas.font = '80px sans-serif'

FontCanvas.fillText('Hello', 20, 100)  // fillText

FontCanvas.strokeText('Hello', 270, 100)  // strokeText

效果:

使用特效和变换

使用阴影

添加阴影的四种绘制状态属性:

shadowBlur: 设置阴影的模糊程度

shadowColor: 设置阴影的颜色

shadowOffsetX: 设置阴影的水平偏移量

shadowOffsetY: 设置阴影的垂直偏移量

使用透明度

使用绘制状态属性globalAlpha设置全局性透明度,属性值可以从0(完全透明)到1(完全不透明,这是默认值)。

使用合成

使用状态属性globalCompositeOpetation来控制图形和文字在画布上绘制的方式。globalCompositeOpetation允许的值自省去网上搜索,在这儿就不一一列举。有些浏览器对globalCompositeOpetation设置的值的解释样式会有些不同,可自行测试。

使用变换

变换的属性:

scale(xScale, yScale): 沿X轴缩放画布xScale倍,沿Y轴缩放yScale倍

rotate(angle): 使画布围绕点(0, 0)顺时针旋转指定的弧度数

translate(x, y): 重映射画布坐标为沿X轴x,沿Y轴y

transform(a, b, c, d, e, f): 合并现有的变换和a-f值所指定的矩阵

setTransform(a, b, c, d, e, f): 用a-f值所指定的矩阵替换现有的变换

测试代码:

html:

<canvas id="effects-canvas" width="500" height="140">

  Your browser doesn't support the canvas element.

</canvas>

js:

const EffectsCanvas = document.getElementById('effects-canvas').getContext('2d')

EffectsCanvas.fillStyle = 'lightgrey'

EffectsCanvas.strokeStyle = 'black'

EffectsCanvas.lineWidth = 3

EffectsCanvas.shadowOffsetX = 5  // 阴影水平偏移量

EffectsCanvas.shadowOffsetY = 5  // 阴影垂直偏移量

EffectsCanvas.shadowBlur = 5  // 阴影模糊程度

EffectsCanvas.shadowColor = 'grey'  // 阴影的颜色

// 设置文字

EffectsCanvas.font = '90px sans-serif'

EffectsCanvas.fillText('Hello', 10, 100)

EffectsCanvas.strokeText('Hello', 10, 100)

// 设置矩形

EffectsCanvas.strokeRect(250, 20, 100, 100)

// 设置圆弧

EffectsCanvas.beginPath()

EffectsCanvas.arc(420, 70, 50, 0, Math.PI, true)

EffectsCanvas.stroke()

EffectsCanvas.beginPath()

EffectsCanvas.arc(420, 80, 40, 0, Math.PI, false)

EffectsCanvas.fill()

EffectsCanvas.globalCompositeOperation = 'destination-out'  // 使用合成

EffectsCanvas.fillStyle = 'red'

EffectsCanvas.globalAlpha = 0.5  // 使用透明度

EffectsCanvas.fillRect(80, 20, 65, 100)

// 使用变换

EffectsCanvas.scale(0.9, 0.9)

EffectsCanvas.translate(50, -103)

EffectsCanvas.rotate(0.3)

EffectsCanvas.globalCompositeOperation = 'source-over'  // 使用合成

EffectsCanvas.fillStyle = 'green'

EffectsCanvas.globalAlpha = 0.5  // 使用透明度

EffectsCanvas.fillRect(300, 10, 160, 120)

效果:

参考资料:《HTML5权威指南》: http://www.ituring.com.cn/boo...


刘春辉同学
48 声望5 粉丝