概述
Canvas(画布)用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。
开始使用
- 新建一个
<canvas>
网页元素。
复制代码
- 替换内容
- 支持
<canvas>
的浏览器将会忽略在容器中包含的内容,正常渲染canvas。 - 不支持
<canvas>
的浏览器会显示代替内容
- 支持
width
和height
- 默认宽度为300像素,默认高度为150像素。
html
属性设置width/height
时只影响画布本身不影画布内容css
属性设置width/height
时不但会影响画布本身的高宽,还会使画布中的内容等比例缩放(缩放参照于画布默认的尺寸)
<canvas>
元素只是创造了一个固定大小的画布,要想在它上面去绘制内容,需要用getContext()
方法找到它的渲染上下文。
//获取canvas容器var canvas = document.getElementById('myCanvas');//创建一个渲染上下文if (canvas.getContext) { var ctx = canvas.getContext('2d');}复制代码
上面代码中,getContext
方法指定参数2d
,表示该canvas
节点用于生成2D图案(即平面图案)。如果参数是webgl
,就表示用于生成3D图像(即立体图案),这部分实际上单独叫做WebGL API。
绘图方法
canvas
画布提供了一个用来作图的平面空间,该空间的每个点都有自己的坐标,x表示横坐标,y表示竖坐标。原点(0, 0)位于图像左上角,x轴的正向是原点向右,y轴的正向是原点向下
样式和颜色
fillStyle
:设置填充颜色,默认黑色strokeStyle
:设置轮廓颜色,默认黑色lineWidth
:设置线条宽度,属性值为任意正整数,默认值是1.0。lineJoin
:控制线条相交的方式(默认是miter
)round
: 圆角bevel
: 斜角miter
: 直角
lineCap
:线段末端的形状(默认值是butt
)butt
:线段末端以方形结束。round
:线段末端以圆形结束square
:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域
save()、restore()、beginPath()
- 样式容器
- 每次调用样式api时,都会往样式容器里做登记
- 调用
save()
时,将样式容器中的状态压栈,保存上下文环境 - 调用
restore()
时,将样式栈的栈顶状态弹出到样式容器中,恢复到上一次保存的上下文环境
//用save方法,保存了当前设置ctx.save();ctx.shadowOffsetX = 10;ctx.shadowOffsetY = 10;ctx.shadowBlur = 5;ctx.shadowColor = 'rgba(0,0,0,0.5)';//绘制了一个有阴影的矩形ctx.fillStyle = '#CC0000';ctx.fillRect(10,10,150,100);//使用restore方法,恢复了保存前的设置ctx.restore();//绘制了一个没有阴影的矩形ctx.fillStyle = '#000000';ctx.fillRect(180,10,150,100);复制代码
- 路径容器
- 每次调用路径api时,都会往路径容器里做登记
- 调用
beginPath
时,清空整个路径容器
ctx.save();//关于样式的设置ctx.beginPath();//关于路径的设置ctx.restore();复制代码
变换
translate(x, y)
:将canvas坐标原点移动到(x,y),translate是累加的rotate(angle)
:围绕原点旋转图像angle弧度(顺时针),rotate是累加的scale(x, y)
:缩放图像;x和y分别是横轴和纵轴的缩放因子(正值),scale是累加的- 比 1.0 小:缩小
- 比 1.0 大:放大
- 为 1.0 时什么效果都没有
(1)绘制矩形
//填充矩形(x, y是横纵坐标,原点在canvas的左上角)ctx.fillRect(x, y, width, height);//边框矩形,默认1px 黑色。 ctx.strokeRect(x, y, width, height);//清除指定的矩形区域,变为透明ctx.clearRect(x, y, width, height); //绘制动态效果时,常用来清除整个画布复制代码
rect(x, y, width, height)
:绘制矩形路径
(2)绘制路径
//新建路径,beginPath是绘制新图形的开始ctx.beginPath()//路径(线)的起点,一般在上面这条命令后执行ctx.moveTo(x, y) //线的终点ctx.lineTo(x, y) //闭合路径,不是必须的,如果线的终点跟起点一样,会自动闭合。ctx.closePath()//通过线条绘制轮廓(边框)ctx.stroke() //不会自动调用closePath() //通过路径填充区域(实心)ctx.fill() //自动调用closePath()复制代码
例:绘制一个三角形
ctx.beginPath();ctx.moveTo(75, 50); //路径起点ctx.lineTo(100, 75);ctx.lineTo(100, 25);ctx.fill(); //自动将路径闭合,并默认填充黑色。复制代码
quadraticCurveTo(cp1x, cp1y, x, y)
:绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,起始点为moveto时指定的点,x,y为结束点。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
:绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,起始点为moveto时指定的点,x,y为结束点。ctx.isPointInPath(x, y)
:判断在当前路径中是否包含检测点- x:检测点的X坐标
- y:检测点的Y坐标
- 注意,此方法只作用于最新画出的canvas图像
(3)绘制文本
fillText(string, x, y)
:在指定的(x,y)位置填充指定的文本- 4个参数:文本字符串、起点的x坐标、y坐标、可选的最大像素宽度。
strokeText(string, x, y)
:在指定的(x,y)位置填充指定的文本
// 设置字体,必须要有大小和字体ctx.font = "Bold 20px Arial"; // 设置对齐方式,可选值包括: left, right centerctx.textAlign = "left";// 设置填充颜色ctx.fillStyle = "#008600"; // 设置字体内容,以及在画布上的位置ctx.fillText("Hello!", 10, 50); // 绘制空心字ctx.strokeText("Hello!", 10, 100); 复制代码
measureText()
方法:返回一个TextMetrics 对象,包含关于文本尺寸的信息(例如文本的宽度)
(4)绘制圆形和扇形
//绘制圆形ctx.arc(x, y, r, start, end, true/false) //(x, y)圆心,r半径,start和end是开始和结束角度,false表示顺时针(默认),true表示逆时针。//绘制弧线ctx.arcTo(x1, y1, x2, y2, r); //当前端点、(x1,y1)和(x2,y2)这三个点连成的弧线,r是半径。复制代码
例:绘制实心的圆形
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.fillStyle = "#000000"; ctx.fill();复制代码
例:绘制空心圆形
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.lineWidth = 1.0; ctx.strokeStyle = "#000"; ctx.stroke();复制代码
(5)设置阴影
ctx.shadowOffsetX = 10; // 设置水平位移ctx.shadowOffsetY = 10; // 设置垂直位移ctx.shadowBlur = 5; // 设置模糊度ctx.shadowColor = "rgba(0,0,0,0.5)"; // 设置阴影颜色ctx.fillStyle = "#CC0000"; ctx.fillRect(10,10,200,100);复制代码
(6)设置渐变
createLinearGradient(x1, y1, x2, y2)
:创建一个canvas渐变(线性渐变)- 渐变起点 (x1,y1) 与终点 (x2,y2)
gradient.addColorStop(position, color)
gradient
:createLinearGradient
的返回值addColorStop
方法接受 2 个参数:position
参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置,例如,0.5 表示颜色会出现在正中间。color
参数必须是一个有效的 CSS 颜色值,如 #FFF, rgba(0,0,0,1)等等
//创建一个canvas线性渐变,返回`CanvasGradient`对象的实例var myGradient = ctx.createLinearGradient(0, 0, 0, 160); myGradient.addColorStop(0, "#BABABA"); myGradient.addColorStop(1, "#636363");//绘制渐变填充的矩形ctx.fillStyle = myGradient;ctx.fillRect(10,10,200,100);复制代码
createRadialGradient(x1, y1, r1, x2, y2, r2)
:canvas渐变(径向渐变)- 前三个参数则定义另一个以(x1,y1) 为原点,半径为 r1 的圆
- 后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆
图像处理方法
drawImage()方法
Canvas API 允许将图像文件插入画布,做法是读取图片后,使用
drawImage
方法在画布内进行重绘。
- canvas操作图片时,必须要等图片加载完才能操作
drawImage(image, x, y, width, height)
image
:图像文件的DOM元素x
和y
:绘制该图像的起始坐标width
和height
:目标宽高
var image = new Image();image.src = 'image.png';image.onload = function() { var canvas = document.createElement('canvas'); canvas.width = image.width; canvas.height = image.height; canvas.getContext('2d').drawImage(image, 0, 0); // 插入页面底部 document.body.appendChild(image); return canvas;}复制代码
createPattern()方法:设置背景模式
createPattern(image, repetition)
image
:图像源epetition
repeat
repeat-x
repeat-y
no-repeat
一般情况下,我们都会将fillstyle
的值设置为createPattern
返回的对象,只表示在某个特定的区域内显示重复的图像。
getImageData()方法,putImageData()方法
通过
getImageData
方法和putImageData
方法,可以处理每个像素,进而操作图像内容。
ctx.getImageData(sx, sy, sw, sh)
:获得一个包含画布场景像素数据的ImageData
对象,它代表了画布区域的对象数据- 参数
- sx:要被提取的画面区域的 x 坐标。
- sy:要被提取的画面区域的 y 坐标。
- sw:要被提取的像素宽度。
- sh:要被提取的像素高度。
ImageData
对象中存储着canvas对象真实的像素数据,它包含以下几个只读属性:width
:图片宽度,单位是像素height
:图片高度,单位是像素data
:Uint8ClampedArray类型的一维数组, 包含着RGBA
格式的整型数据,范围在0至255之间(包括255)
- 参数
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);复制代码
putImageData(myImageData, dx, dy)
:把图像数据绘制到画布上
context.putImageData(imageData, 0, 0);复制代码
- 套路代码
假定filter是一个处理像素的函数,那么整个对Canvas的处理流程,可以用下面的代码表示。
if (canvas.width > 0 && canvas.height > 0) { var imageData = context.getImageData(0, 0, canvas.width, canvas.height); filter(imageData); context.putImageData(imageData, 0, 0);}复制代码
createImageData()方法
ctx.createImageData(width, height)
:创建一个ImageData对象- width : ImageData 新对象的宽度。
- height: ImageData 新对象的高度。
- 默认创建出来的是透明的
合成
globalAlpha = value
:设置全局透明度,这个属性影响到 canvas 里所有图形的透明度- 有效的值范围是 0.0 (完全透明)到 1.0(完全不透明)
- 默认是 1.0
globalCompositeOperation
:覆盖合成(source--->新的图像(源);destination--->已经绘制过的图形(目标))source-over
(默认值):源在上面,新的图像层级比较高source-in
:只留下源与目标的重叠部分(源的那一部分)source-out
:只留下源超过目标的部分source-atop
:砍掉源溢出的部分destination-over
:目标在上面,旧的图像层级比较高destination-in
:只留下源与目标的重叠部分(目标的那一部分)destination-out
:只留下目标超过源的部分destination-atop
:砍掉目标溢出的部分
toDataURL():将画布导出为图像
注意是canvas元素接口上的方法
function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL('image/png'); return image;}复制代码
上面的代码将Canvas数据,转化成PNG data URI。
常见效果
灰度效果
灰度图(grayscale)就是取红、绿、蓝三个像素值的算术平均值。假定d[i]是像素数组中一个象素的红色值,则d[i+1]为绿色值,d[i+2]为蓝色值,d[i+3]就是alpha通道值。转成灰度的算法,就是将红、绿、蓝三个值相加后除以3,再将结果写回数组。
grayscale = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = d[i + 1] = d[i + 2] = (r+g+b)/3; } return pixels;};复制代码
复古效果
复古效果(sepia)则是将红、绿、蓝三个像素,分别取这三个值的某种加权平均值,使得图像有一种古旧的效果。
sepia = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red d[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green d[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue } return pixels;};复制代码