初识canvas
什么是canvas
<canvas>是一个可以使用javascript来绘制2D图形的HTML元素。<canvas>标签只有两个属性width和height,用来设置画布的宽度和高度。下面代码构建了一个300*300的画布。
<canvas id="canvas" width="300" height="300"></canvas>
渲染上下文
canvas初始是空白的。要绘制图形,需要获取canvas元素的渲染上下文。
下面代码,通过getElementById获取canvas的DOM对象,然后通过canvas对象的getContext()方法获取渲染上下文。此时就可以通过context绘制图形了。
const canvas = document.getElementById("canvas")
const context = canvas.getContext("2d")
一个简单的例子
绘制图形的步骤
- 创建一个canvas元素
- 获取canvas元素的渲染上下文
- 绘制图形
一个简单的例子,绘制三角形。
绘制图形
canvas坐标空间
canvas坐标空间起点为左上角(坐标原点(0,0)),Y轴坐标是向下的。
绘制矩形
canvas支持两种形式的图形绘制:矩形和路径。其他所有的图形都通过一条或者多条路径组合而成。
canvas提供了三种方法绘制矩形:
context.fillRect(x, y, width, height)绘制一个填充矩形context.strokeRect(x, y, width, height)绘制一个矩形边框context.clearRect(x, y, widht, height)清除指定矩形 上面提供的方法,x和y指定了在canvas画布上所绘制的矩形的左上角的坐标。width和height表示矩形的宽高。
绘制路径
通过路径绘制图形,需要用到的函数:
beiginPath():表示开启新的路径。closePath():关闭路径,作用是连接起点和终点,主要用于实现封闭图形。stroke(): 通过线条来绘制图形轮廓。fill(): 通过填充路径的内容区域生成实心的图形。moveTo(): 将笔触移动到指定的坐标(x,y) 上,通常会使用moveTo()函数设置起点。
直线 lineTo()
绘制直线,需要用到的方法lineTo(x, y)。x,y代表坐标系中直线结束的点。开始点是之前绘制路径的结束点,也可通过moveTo(x,y)设置开始点。
圆弧 arc()
arc(x, y, radius, startAngle, endAngle, anticlockwise):画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针)来生成。
arcTo(cx, cy, x2, y2, radius):arcTo方法是利用开始点/控制点/结束点/所形成的夹角,绘制一段与夹角两边相切并且半径为radius的圆弧。(cx,cy)表示控制点,(x2,y2)表示结束点坐标,radius表示圆弧半径。
arc()函数中表示角度的单位是弧度,弧度=(Math.PI/180)*角度。
贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y):绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y):绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
给图形设置样式
颜色
给图形设置颜色,使用fillStyle和strokeStyle属性。
- fillStyle = color 设置图形的填充颜色。
- strokeStyle = color 设置图形的轮廓颜色。
颜色值可以是如下格式:
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
渐变样式
我们可以用线性或者径向的渐变来填充或描边,我们可以创建一个渐变对象,然后赋给图形的fillStyle和strokeStyle属性。
createLinearGradient(x1, y1, x2, y2)创建线性渐变对象。createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。createRadialGradient(x1, y1, r1, x2, y2, r2)创建镜像渐变对象。createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。gradient.addColorStop(position, color)创建好渐变对象之后,我们就可以用addColorStop方法给它上色了。addColorStop 方法接受 2 个参数,position参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。
图案样式
图案的应用跟渐变很类似的,创建出一个 pattern 之后,赋给 fillStyle 或 strokeStyle 属性即可。
createPattern(image, type)该方法接受两个参数。Image 可以是一个 Image 对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat。
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
const image = new Image()
image.src= "//iconfont.alicdn.com/p/illus/preview_image/m5Ae1H3sEQPu/55288624-8d1a-452f-a0fa-83cfca6430aa.png"
image.onload = function(){
const parttern = context.createPattern(image, 'no-repeat')
context.fillStyle = parttern;
context.arc(200, 200, 200, 0, 360*Math.PI/180)
context.fill()
}
</script>
</body>
线条样式
lineWidth=value设置线条宽度lineCap = value设置线条末端样式,value取值为butt,round,square。lineJoin = type设置线条与线条间结合处的样式,value取值:round,bevel,miter。默认值是miter。miterLimit = value设置线条交接处的最大长度setLineDash(arr)设置虚线样式lineDashOffset = value设置虚线的起始偏移
阴影样式
shadowOffsetX = float设定阴影在 X 轴的延伸距离, 正值表示向右,负值表示向左。shadowOffsetY = float设定阴影在 Y 轴的延伸距离,正值表示向下,负值表示向上。shadowBlur = float设定阴影模糊程度shadowColor = color设定阴影颜色
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
context.shadowOffsetX = 10
context.shadowOffsetY = 10
context.shadowBlur = 5
context.shadowColor = 'red';
context.arc(50, 50, 50, 0, 360*Math.PI/180)
context.stroke()
</script>
</body>
绘制文本
canvas提供了两种方法来渲染文本:
- fillText(text, x, y)在指定的 (x,y) 位置填充指定的文本
- strokeText(text, x, y)在指定的 (x,y) 位置绘制文本边框 设置文本样式:
- font = value 和css font属性语法相同 font="10px serif"
- textAlign = value 文本对齐选项,包括start end left right center
- textBaseline = value 基线对齐选项。 top, middle, bottom
- direction = value 文本方向。可能的值包括:ltr, rtl, inherit
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
context.font = "30px serif";
context.fillStyle = "red"
context.fillText('I LOVE YOU', 10, 50)
context.strokeStyle = "blue"
context.strokeText('I LOVE YOU', 10, 50)
</script>
</body>
图像操作
canvas 具备图像操作能力。可以用于动态的图像合成或者作为图形的背景。
获取图像源
要将图像绘制到canvas,需要获取图像。以下几种方式都可以用到canvas中。
- 由
Image()函数构造出来的,或者任何的<img>元素 - 用一个 HTML 的
<video>元素作为你的图片源,可以从视频中抓取当前帧作为一个图像 - 可以使用另一个
<canvas>元素作为图片源。
绘制图像
drawImage(image, dx, dy):其中image是image或者canvas对象,dx和dy是其在目标canvas里的起始坐标。drawImage(image, dx, dy, dwidth, dheight)这个方法多了 2 个参数:dwidth和dheight,这两个参数用来控制 当向 canvas 画入时应该缩放的大小drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)前 4 个是定义图像源的切片位置和大小,后 4 个则是定义切片的目标显示位置和大小
像素操作
-
canvas提供了
getImageData方法和putImageData方法配合使用,先用getImageData方法获取ImageData对象,然后利用一定的算法进行像素操作,最后使用putImageData方法输出像素数据。 -
ImageData对象中存储着 canvas 对象真实的像素数据。它包含3个属性:width图片宽度 height图片高度 data是一个一维数组。包含着RGBA格式的整数数据,数组取值如
[r1,g1,b1,a1,r2,g2,b2,a2,...],数组中每四个数存储着一个像素的RGBA颜色值。 -
翻转效果:颜色反转是值图片颜色颠倒的效果,实现算法是:将红、绿、蓝3个通道像素取各自的相反值。
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('canvas')
const cxt = canvas.getContext("2d")
const image = new Image()
image.src = "./1.png"
image.onload = () => {
cxt.drawImage(image, 10, 10)
var imageData = cxt.getImageData(10,10,120,120)
for(let i=0; i<imageData.data.length; i=i+4){
imageData.data[i+0] = 255 - imageData.data[i+0];
imageData.data[i+1] = 255 - imageData.data[i+1];
imageData.data[i+2] = 255 - imageData.data[i+2];
}
cxt.putImageData(imageData, 140, 10)
}
</script>
</body>
- 黑白效果:也叫灰度图,将彩色图片转换成黑白图片,实现算法是,取红绿蓝3个通道的平均值,然后将三个通道全部保存为这个平均值。
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('canvas')
const cxt = canvas.getContext("2d")
const image = new Image()
image.src = "./1.png"
image.onload = () => {
cxt.drawImage(image, 10, 10)
var imageData = cxt.getImageData(10,10,120,120)
console.log(imageData)
console.log(imageData.data)
for(let i=0; i<imageData.data.length; i=i+4){
let avg = (imageData.data[i+0] + imageData.data[i+1] + imageData.data[i+2])/3
imageData.data[i+0] = avg;
imageData.data[i+1] = avg;
imageData.data[i+2] = avg;
}
cxt.putImageData(imageData, 140, 10)
}
</script>
</body>
- 复古效果:是将红蓝绿三个通道的值,进行加权平均达到的效果
- 红色蒙版:是将红色通道的值赋值为红、绿、蓝三个通道的平均值,并且将绿色通道、蓝色通道都赋值为0
- 透明处理:将数组中每一个像素的透明度乘以n,然后保存像素数组。
变形操作
变形是一种更强大的方法,可以将原点移动到另一点、对canvas进行旋转和缩放。
状态保存和恢复
在了解变形之前,我先介绍两个在你开始绘制复杂图形时必不可少的方法。
- save(): 保存画布 (canvas) 的所有状态。
- restore(): 恢复canvas状态的。
Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。Canvas 状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。每一次调用 restore() 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。
一个绘画状态包括:
- 当前应用的变形(即移动,旋转和缩放)
- 以及下面这些属性:
strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,lineDashOffset,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline,direction,imageSmoothingEnabled - 当前的裁切路径(clipping path)
移动translate
translate(x, y):移动 canvas 和它的原点到一个不同的位置。x是左右偏移量,y是上下偏移量。
旋转rotate
rotate(angle):以原点为中心旋转 canvas。angle>0坐标系顺时针旋转,angle<0坐标系逆时针旋转。
缩放scale
scale(x, y):缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。
变形transform
transform(a, b, c, d, e, f):
- translate(e,f)等价于transform(1,0,0,1,e,f)
- scale(a,d)等价于transform(a,0,0,d,0,0)
- rotate(angle)等价于transform(cos, sin, -sin, cos, 0,0)
用canvas制作一个时钟
参考:
- developer.mozilla.org/zh-CN/docs/…
- 从0到1 HTML5 Canvas动画开发