一、概述
canvas它和其它的HTML5标签的使用基本一致,但是它相当于在浏览器中建立一个画布,可以再这个画布上画图、创建动画甚至是3D游戏。由于canvas要适配不同终端的分辨率,所以尽可能的在标签内设置高度和宽度,这个也符合W3C的标准。代码格式如下,当浏览器不支持canvas标签的时候,会显示其中的文字。
而在canvas的坐标体系中,是以左上角为坐标原点,向右为x轴正方向,向下为y轴正方向,如下图
而在canvas中,进行绘制需要首先获取canvas的上下文环境context,而后调用API进行图像的绘制
var canvas = document.getElementById("main"), ctx = canvas.getContext("2d");
二、线条的绘制和填充
在canvas中,各个图像绘制代码可以通过beginPath()和closePath()这两个函数进行包裹,主要用于分割各个画图,表示开始和结束。线条的绘制主要调用方法是moveTo(x,y)、lineTo(x,y)、stroke()、arc()、arcTo()、fill(),使用的属性包括lineWidth、lineCap、lineJoin、strokeStyle、fillStyle等。
1、画出边角为圆角的一条线段
ctx.beginPath();ctx.strokeStyle = "black";ctx.lineWidth = 6;ctx.lineCap = "round";ctx.moveTo(400,400);ctx.lineTo(600,400);ctx.stroke();ctx.closePath();
效果图为:
其中strokeStyle表示线条的颜色,lineWidth表示线条的宽度,lineCap设置线条的边缘为圆角,lineCap的属性有butt|round|square,第一个是默认值表示平直的边缘,round为圆角,square为正方的边缘。moveTo(x,y)表示划线的起点为(x,y)坐标,而lineTo(x,y)设置线条的终点为(x,y),最后通过调用stroke()方法进行绘制。
2、画出两条线段,焦点为圆角
ctx.beginPath();ctx.strokeStyle = "black";ctx.lineWidth = 10;ctx.lineJoin = "round";ctx.moveTo(400,500);ctx.lineTo(600,500);ctx.lineTo(600,600);ctx.stroke();ctx.closePath();
效果图为:
和上面的demo的不同点在于使用的属性为lineJoin,同样它也有三个属性bevel|round|miter,第一个是默认值表示斜角,而miter表示尖角。同时lineTo(x,y)可以调用多次,进行线段的绘制,所以可以通过moveTo()和lineTo()这两个方法进行多边形的绘制
3、矩形的绘制并填充颜色
ctx.beginPath(); ctx.moveTo(50,50);ctx.lineTo(100,50);ctx.lineTo(100,100);ctx.lineTo(50,100);ctx.lineTo(50,50);ctx.lineWidth = 4;ctx.strokeStyle = "red";ctx.stroke();ctx.fillStyle = "blue";ctx.fill();ctx.closePath();
效果图为:
通过moveTo()和lineTo()方法进行多边形的绘制后,得到了一个闭合区间,就可以调用fill()方法对其中的颜色进行填充,fillStyle则是设置闭合区间内的颜色。如果不用stroke()方法,也就是不绘制外边框的线条,则可以省去最后的那个回到起点的方法ctx.lineTo(50,50),因为fill()会自动将起点和终点进行连接得到一个闭合区间。
如果是单纯的矩形而非不规则的多变型的时候,可以直接调用canvas的api方法strokeRect(x,y,w,h)和fillRect(x,y,w,h);前两个参数表示起点的坐标,后两个表示矩形的宽度和高度。
ctx.beginPath();ctx.lineWidth = 3;ctx.strokeStyle = "darkgray";ctx.strokeRect(50,50,200,100);ctx.closePath();ctx.beginPath();ctx.fillStyle = "coral";ctx.fillRect(300,50,200,100);ctx.closePath();
效果图为:
4、弧形的绘制
首先是arc(x,y,r,beginPi,endPi,anticlockwise)函数,前两个参数表示圆心的x,y坐标,中间的那个r表示圆的半径,后两个参数表示起始弧度和结束弧度,最后表示是否是逆时针绘制,默认是false即顺时针绘制。在canvas中,无论是顺时针还是逆时针,圆的弧度都是一个定值,如下图:
ctx.beginPath();ctx.arc(320,200,50,0,Math.PI*2);ctx.lineWidth = 3;ctx.strokeStyle = "black";ctx.stroke();ctx.fillStyle = "chartreuse";ctx.fill();ctx.closePath();
效果图为:
还可以通过arcTo(x1,y1,x2,y2,r);绘制圆弧,它与moveTo(x,y)一起进行使用,(x,y)(x1,y1)与(x1,y1)(x2,y2)以这两条线段为切线,绘制半径为r的圆弧,起点和终点为那两个切点。
ctx.beginPath();ctx.lineTo(400,200);ctx.arcTo(500,200,500,300,100);ctx.strokeStyle = "aqua";ctx.stroke();ctx.closePath();
效果图为:
最后就是贝塞尔曲线绘制曲线,由于数学算法比较复杂,也没有过多研究
a、二次贝塞尔曲线
cxt.quadraticCurveTo(x1,y1,x2,y2);
同样是与 cxt.moveTo(x0,y0);混用,其是通过(x1,y1)为控制点画圆弧
http://blogs.sitepointstatic.com/examples/tech/canvas-curves/quadratic-curve.html
该网址是二次贝塞尔曲线的测试网址
b、三次贝塞尔曲线
cxt.bezierCurveTo(x1,y1,x2,y2,x3,y3);
同样是与 cxt.moveTo(x0,y0);混用,其是通过(x1,y1),(x2,y2)为控制点画圆弧
http://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html
该网址是三次贝塞尔曲线的测试网址
(ps:其中三次曲线比二次曲线好用,他可以绘制会各种突出弧形以及波浪)
三、图形变换
无论哪种语言处理图像时,都有一个思想。那就是先确定好图形画法函数,然后通过图形变换函数将图形进行位移、旋转角度、大小的改变。
在canvas中,由于canvas是一种基于状态的编程,所以之前提到在绘制点与点之间的直线以及颜色时使用
context.beginPath();
context.closePath();
这两个函数可以将点与点之间的函数的状态进行隔离,并且还可以完成封闭的图形,即首尾点会自动连接
而在图形变换中也需要这样的规范写法,它们分别是
context.save();
context.restore();
通过这两个函数将函数变换的函数隔离开
1、translat
context.translat(x,y)
它是将图像进行平移,x是水平方向平移的距离,y是垂直方向平移的距离
ctx.save(); ctx.translate(50,50); ctx.beginPath(); ctx.strokeRect(10,10,20,20);
ctx.closePath(); ctx.restore();
效果图为:
本来这个矩形应该绘制在左上角,经过图形变换把其向x,y两个方向各偏移了50像素(PS:需要注意的是图形变换的函数调用,要在绘制函数之前执行)
2、rotate
context.rotate(rot);
该方法是用来设置图片的旋转角度,其中rot应该是弧度,若传入的是角度的话需要转换,如80,需要些为Math.PI*80/180
ctx.save();ctx.rotate(20*Math.PI/180);ctx.beginPath();ctx.fillRect(100,100,50,50); ctx.closePath();ctx.restore();
效果图为: 向顺时针方向偏移了20度
3、scale
context.scale(x,y)
该方法是用来进行图像缩放的,其中x为水平方向缩放的比例,y是垂直方向缩放的比例
(PS: 该函数存在一个问题,就是在缩放时,图像的左上角的位移也会发生同样比例的改变并且图像的边框线也会发生同样的改变)
ctx.save();ctx.scale(0.5,0.5);ctx.beginPath();ctx.fillRect(100,100,200,200); ctx.closePath();ctx.restore();
就是将正方形的x和y方向均缩放到一半的大小
4、transform
context.transform(a,b,c,d,e,f);
首先该方法是上述方法的总和,因为该方法是通过单位矩阵的方式对图像进行改变,图像在本质上就是许多由0,1的矩阵组合而成,如下表格
a | c | e |
b | d | f |
0 | 0 | 1 |
a代表水平缩放,默认为1;b代表水平倾斜,默认为0;c代表垂直倾斜,默认为0;
d代表垂直缩放,默认为1;e代表水平位移,默认为0;f代表垂直位移,默认为0;
所以用transfrom函数可以实现,上面3种图像变换。
四、其它杂七杂八
1、文字显示
ctx.fillText(string,x,y,[maxlen]);
ctx.strokeText(string,x,y,[maxlen]);
其中第一个函数是需要写出的文本值,其中x,y是文本的坐标。而maxlen是可选参数,设置其文字的最大长度。
其文字可以设置相关参数
ctx.font的默认值是"20px sans-serif"
其参数包括context.font = font-style font-variant font-weight
font-size font-family其中各个参数有个字的值
context.textAlign = left center right该属性是设置文字的居中、居左、居右
context.textBaseline = top middle bottom该属性是设置文字的垂直居上、居中、居下。
ctx.beginPath();var str = "古月枫"ctx.strokeStyle = "red";ctx.fillStyle = "aqua";ctx.font = "40px Arial";ctx.textAlign = "center";ctx.textBaseline = "middle";ctx.strokeText(str,100,100,200);ctx.fillText(str,100,150,200);ctx.closePath();
效果图为:
2、阴影
在canvas中并没有一个针对阴影的函数,它是通过状态进行添加,无论是线条、矩形、圆或者是文字都可以通过以下函数添加阴影效果
ctx.shadowColor = "gray"; //设置阴影背景的颜色
ctx.shadowOffsetX = 10; //设置阴影x轴方向的突出像素,该值可以为负数
ctx.shadowOffsetY = 10; //意思同上,只不过这个是针对Y轴的
ctx.shadowBlur = 5; //设置阴影的模糊程度,0为无模糊,值越大模糊越重
ctx.beginPath();var str = "古月枫"ctx.fillStyle = "aqua";ctx.font = "40px Arial";ctx.textAlign = "center";ctx.textBaseline = "middle";ctx.shadowColor = "gray"; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; ctx.shadowBlur = 3; ctx.fillText(str,100,150,200);ctx.closePath();
效果图为:
3、全局变量,透明度
ctx.globalAlpha设置全局的透明度,它的默认值为1,而将其改变为0到1的值时,画布上的图形就有了透明效果。由其作用范围为全局,所以要用save()和restore()方法进行包裹使用
4、剪辑 ctx.clip();
这个功能只有上面所说的一个函数,它是与lineTo、fillRect、arc等可绘制闭合空间的函数混用,其用处是为了canvas只能在一个封闭的空间内进行绘制,超出这个空间的图形绘制不显示,比较常用的运用方式是制作探照灯的效果。
ctx.save();ctx.beginPath();ctx.arc(200,200,100,0,Math.PI*2);ctx.clip();ctx.fillStyle = "chartreuse";ctx.fillRect(100,100,200,200);ctx.closePath();ctx.restore();
效果图为:
先定义了一个圆形的剪辑区域,然后画了一个大范围的正方形,但是只能显示这个圆形范围的图像
5、交互
由于在canvas中整个canvas是作为一个画布,而且其中画出的各种图形都无法将其作为一个对象通过事件绑定的形式进行交互,所以在canvas中的事件绑定是直接绑定在canvas上,然后通过对用户在canvas画布上操作的坐标的判断进行交互。
其中最基本的方法如下
a、对canvas标签进行事件绑定,JS以及jQuery都成
b、获取在画布上用户操作的坐标
var x = event.clientX - canvas.getBoundingClientRect().left;
var y = event.clientY - canvas.getBoundingClientRect().top;
它是通过计算用户在整个页面的操作坐标与canvas在页面的左上边距进行计算的