Canvas是HTML的API,我们可以用它在网页中实时的来生成图像。
文章导读
1.必备技能
2.用于画图的函数
例子:
-会话气泡- -心形- -钟表- -星球里的星星-
-调色板- -鼠标绘图- -旋转的小方块-
3.图像的处理
例子:
-图像的灰度和翻转效果- -拾色器-
-放大镜- -图像的高斯模糊-
一.必备技能
控制它的宽高是要写在行内样式中的,像上面那样。这样我们就有了一个canvas元素,然后我们就可以去操作它了:
var canvas = document.getElementById('Canvas'); if (canvas.getContext) { var content = canvas.getContext('2d'); }
获取元素的同时,还要获取canvas的2D绘图环境。要是用于3D绘图的话,就要用WebGL了。
二.用于画图的函数
然后,我们要开始在画布上绘图了。它的画布是这样的网格:
2.1矩形
canvas中只支持这一种形状的函数,别的形状就都要自己组合来实现了。
fillRect(x, y, width, height) //画一个填充的矩形 strokeRect(x, y, width, height) //画一个只有边框的矩形 clearRect(x, y, width, height) //清除指定的矩形区域
其中的(x,y)是指矩形左上角的坐标。
[查看源码][运行结果]
2.2路径
1.首先,创建一条路径--beginPath() 2.然后,通过一些绘图的方法做一些绘图操作 3.然后关闭路径--closePath() 4.我们已经把路径创建好了,然后就是填充或者绘制路径到我们的画布上--stroke()/fill()
比如说画一个三角形:
[查看源码][运行结果]
需要注意的是其中两个三角形,颜色不同,一不小心可能会出问题,所以我们有时可能需要save()和restore()函数的帮助来达到局部作用的效果。比如上面示例源码中所做的那样:
1 2 content.save();//局部作用效果 3 content.fillStyle = 'red'; 4 content.beginPath();//beginPath()不写的时候可能会出错,所以确保beginPath和closePath都相对应 5 content.moveTo(100,100); 6 content.lineTo(200,200); 7 content.lineTo(300,200); 8 content.closePath(); 9 content.fill(); 10 content.restore(); 11 12 13 content.beginPath(); 14 content.moveTo(100,200); 15 content.lineTo(200,300); 16 content.lineTo(300,300); 17 content.closePath(); 18 content.fill();
canvas还提供了两个移动画笔的函数:
moveTo(x, y) //将画笔移动到指定的(x,y)的位置 lineTo(x, y) //在当前画笔的位置到指定的(x,y)位置画一条线
尝试一下moveTo()方法我们可以画个笑脸:
[查看源码][运行结果]
结合使用moveTo和lineTo方法,我们可以实现鼠标像画笔一样在画板上绘图的效果:
[查看源码][运行结果]
然后我们严格的按照上面说的规范步骤,1,2,3,4并结合画圆的函数,可以自己绘制一个钟表,稍加改进就是个嘀嗒嘀嗒走的时钟了:
[查看源码][运行结果]
2.3文字
fillText('要显示的文本',x坐标,y坐标)此方法不支持文本断行,要显示多行文本只能多次调用
通过fillText()方法我们可以在canvas画布上写文字:
[查看源码][运行结果]
2.4圆形和扇形
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise); (x,y)--圆心坐标 radius--半径 startAngle--扇形的起始角度(弧度) endAngle--扇形的终止角度(弧度) anticlockwise--做图时是顺时针画(true)还是逆时针(false)画
[查看源码][运行结果]
结合对rgb颜色的相关操作,我们可以做出类似调色板的效果:
[查看源码][运行结果]
2.5不规则图形
我们可以通过画曲线来得到不规则的图形,canvas为我们提供了两个高大上的函数:
-------------------------------
#quadraticCurveTo(cp1x, cp1y, x, y)
(cp1x,cp1y)--控制点
此函数表示从当前的画笔位置到(x,y)画一条二次曲线
-------------------------------
#bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
(cp1x,cp1y)--控制点1 (cp2x,cp2y)--控制点2
此函数表示从当前的画笔位置到(x,y)画一条bezier曲线
-------------------------------
这两个曲线具体含义我也不太清楚,但大概是这个样子:
试一下quadraticCurveTo函数:
[查看源码][运行结果]
试一下bezierCurveTo函数:
[查看源码][运行结果]
2.6渐变和阴影
#渐变: var myGradient = ctx.createLinearGradient(x1, y1, x2, y2); (x1,y1)--起点坐标 (x2,y2)--终点坐标 myGradient.addColorStop(0, "#BABABA"); --添加起始颜色 myGradient.addColorStop(1, "#636363"); --添加终止的颜色 ----------------------------- #阴影 ctx.shadowOffsetX = 10; // 设置水平位移 ctx.shadowOffsetY = 10; // 设置垂直位移 ctx.shadowBlur = 5; // 设置模糊度 ctx.shadowColor = "rgba(0,0,0,0.5)"; // 设置阴影颜色
一个也不太搭边儿的例子,不管怎么说,也用到了渐变呢:
[查看源码][运行结果]
这里面用到了clip()方法来实现星星,这跟某css属性clip-path比较神似,我以前尝试过:
请戳[源码][示例]
2.7变换
canvas中有我们熟悉的几个变换函数:
translate(x, y) --平移
rotate(angle) --旋转
scale(x, y) --缩放
transform(a, b, c, d, e, f) --变换
上面的变换函数是根据变换矩阵进行的:
a c e
[ b d f ]
0 0 1
简单的小例子:
[查看源码][运行结果]
三.图像处理
var myImageData = ctx.createImageData(width, height); ctx.getImageData(left, top, width, height);//读取canvas的内容,返回一个对象且该对象有一个data属性,可以供我们操作页面的像素。 ctx.putImageData(myImageData, dx, dy);//将操作好的对象重新绘制在画布中 ctx.drawImage(img, 0, 0); // 我们常用的drawImage方法,设置对应的图像对象,以及它在画布上的位置
通过getImageData()方法获取到图像对象,访问它的data属性就可以得到一个像素数组,我们对像素进行处理,使我们可以用canvas处理图像。
3.1 灰度效果
灰度图(grayscale)就是取红、绿、蓝三个像素值的算术平均值,这实际上将图像转成了黑白形式。假定d[i]是像素数组中一个象素的红色值,则d[i+1]为绿色值,d[i+2]为蓝色值,d[i+3]就是alpha通道值。转成灰度的算法,就是将红、绿、蓝三个值相加后除以3,再将结果写回数组。
1 for(var i=0;i){ 2 var avg = (data[i]+data[i+1]+data[i+2]) / 3; 3 data[i] = avg; //r 4 data[i+1] = avg; //g 5 data[i+2] = avg; //b 6 }
3.2 复古效果
复古效果(sepia)则是将红、绿、蓝三个像素,分别取这三个值的某种加权平均值,使得图像有一种古旧的效果。
1 for (var i = 0; i < d.length; i += 4) { 2 var r = d[i]; 3 var g = d[i + 1]; 4 var b = d[i + 2]; 5 d[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red 6 d[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green 7 d[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue 8 }
3.3 反转效果
反转效果(invert)是指图片呈现一种色彩颠倒的效果。算法为红、绿、蓝通道都取各自的相反值(255-原值)。
1 for (var i = 0; i < d.length; i += 4) { 2 d[i] = 255 - d[i]; 3 d[i+1] = 255 - d[i + 1]; 4 d[i+2] = 255 - d[i + 2]; 5 }
我尝试了一下灰度图的效果和反转图的效果:
[查看源码]
注意,在我们自己本地写demo准备运行查看结果的时候,getImageData()方法可能会有问题,比如说报这个错:Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data
我们知道这是域和本地运行等相关的问题,这时我们自己本地启用服务器,localhost访问就可以了。
3.4 拾色器
实现思路:通过getImageData(x,y,1,1)获得当前鼠标所在位置的一像素的图像对象,通过其data属性操作拿到它的像素值,也就是我们想得到的rgb值。
[查看源码]
3.5 放大镜
实际上drawImage方法可以有多个参数,提供更加丰富的功能:
1 ctx.drawImage(image, dx, dy); 2 ctx.drawImage(image, dx, dy, dWidth, dHeight); 3 ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
各个参数就像下面的示意图这样:
然后我们就可以使用drawImage方法在原图像变换到绘制的图像中做一个等比放大的操作,就可以实现放大镜的效果啦。
「查看源码」
3.6图像的高斯模糊
其实,css中有一个兼容性不那么好的filter属性,可以简单的实现图像模糊的效果:
-webkit-filter: blur(20px); /* Chrome, Opera */ -moz-filter: blur(20px); -ms-filter: blur(20px); filter: blur(20px);
「查看源码」
但是使用canvas可以实现真正意义上的高斯模糊(就是算法那种balabala的)。
这里有一个实现的很好的高斯模糊的js:「StackBlur」
使用它我们就可以轻松的实现图像的高斯模糊了:「查看源码」
文章中的源码Demo都放在了github上,打开可能会有些慢,如果第一次打不开,刷新一下也会好了。
四.资源
canvas中绘图环境所有的属性和方法都可以在这里找到:「CanvasRenderingContext2D interface」
「使用CSS将图片转换成模糊(毛玻璃)效果」
「Canvas API」
「javascript标准参考教程Canvas」