Canvas入门

Canvas基础知识

canvas是HTML中的一个元素,使用JavaScript来绘制图形。可以添加一些HTML属性,也可以通过style设置一些样式

1
2
3
<canvas id="canvas" width="400" height="400">
你的浏览器不支持canvas
</canvas>

默认大小为300*150,如果浏览器不支持,就会显示标签内的文本。

获取上下文

绘制图形,先要获取到canvas的上下文对象getContext()。也可以通过该方法检测浏览器是否支持canvas,getContext()只有一个参数,用来指定上下文环境,比如2Dwebgl

1
2
3
4
5
6
7
8
9
10
function canvasSupport(e){
return !!e.getContext
}
function canvasApp(){
var canvas = document.getElementById('canvas');
if(!canvasSupport(canvas)){
return false;
}
var ctx = canvas.getContext('2d')
}

坐标系统

在Canvas中的2D环境中的坐标系统和Web的坐标系统是一样的(笛卡尔坐标),坐标原点(0,0)canvas的左上角,向右为x轴正向,向下为y轴正向

3D环境中的坐标系统,多了一个z轴,z轴正向从屏幕穿出

图形绘制

Canvas只支持一种原生的图形绘制:矩形。所有其他的图形绘制都需要先生成路径,然后描边或填充。Canvas提供了三种绘制矩形的方法

1
2
3
4
5
6
7
8
<!--绘制一个填充的矩形-->
fillRect(x,y,width,height)
<!--绘制一个描边的矩形-->
strokeRect(x,y,width,height)
<!--清除一个矩形区域,让清除部分完全透明-->
fillRect(x,y,width,height)

绘制路径

  • 创建路径的起点
  • 画出路径
  • 封闭路径
  • 描边或者填充路径区域来渲染图形
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--新建一条路径(重新开始一条路径,它将重置内存中现有的路径)-->
    beginPath()
    <!--闭合路径 如果路径是打开的,使用当前点和起始点的连线闭合。-->
    closePath()
    <!--描边-->
    stroke()
    <!--填充,所有没闭合的形状都会自动闭合-->
    fill()

线

moveTo(x,y)移动到某一点,通常用来设置路径的起点
lineTo(x,y)绘制一条从当前到指定位置的直线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function canvasSupport(e){
return !!e.getContext
}
(function canvasApp(){
var canvas = document.getElementById('canvas');
if(!canvasSupport(canvas)){
return false;
}
var ctx = canvas.getContext('2d')
<!--填充三角形-->
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(110,50);
ctx.lineTo(110,130);
ctx.fill();
<!--描边三角形-->
ctx.beginPath();
ctx.moveTo(200,50);
ctx.lineTo(140,50);
ctx.lineTo(140,130);
ctx.closePath();
ctx.stroke();
})();

路径使用填充时,路径自动闭合,使用描边则不会,如果没有使用closePath(),则只会绘制出两条线段

lineWidth设置线宽

圆弧

arc(x,y,radius,startAngle,endAngle,anticlockwise),以(x,y)为圆心,以radius为半径的圆弧(圆),startAngle表示开始弧度,endAngle表示结束弧度,anticlockwise为布尔值表示方向(默认顺时针,true为逆时针)。

1
2
3
4
5
6
7
8
9
<!--四分之一圆弧-->
ctx.beginPath();
ctx.arc(150,150,50,0,Math.PI/2,false);
ctx.stroke();
<!--四分之三圆弧-->
ctx.beginPath();
ctx.arc(150,300,50,0,Math.PI/2,true);
ctx.stroke();

arcTo(x1,y1,x2,y2,radius)以(x1,y1)和(x2,y2)为控制点,以radius为半径画一段圆弧。

贝塞尔曲线

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设置填充颜色,strokeStyle设置描边颜色。属性值可以是一个表示CSS颜色值的字符串,也可以是CanvasGradientCanvasPattern对象

透明度

可以通过设置globalAlpha属性或者使用一个包含透明度颜色作为描边或填充的样式来实现包含透明度的图形,该属性值范围氏0.0~1.0,默认为1.0不透明

线型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--ctx为画布上下文对象 -->
<!--线宽 -->
ctx.lineWidth=value;
<!--线型末端类型 -->
ctx.lineCap=type;
<!--两条线接合处类型 -->
ctx.lineJoin=type;
<!--限制当两条线相交时交接处最大长度 -->
ctx.miterLimit=value;
<!--获取当前虚线样式 -->
ctx.getLineDash();
<!--虚线样式 -->
ctx.setLineDash(segments);
<!--虚线样式起始偏移量 -->
ctx.lineDashOffset=value;

lineCap线段端点有三个值,buttroundsquare,其中butt是默认值

  • butt线段末端以方形结束
  • round线段末端以圆形结束,增加了以线段宽度为直径的半圆区域
  • square线段末端以方形结束,增加了宽度和线段相同,高度是线段厚度的一半的矩形区域

lineJoin线段连接点有三个值,miterroundbevel,其中miter是默认值

  • miter通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。这个设置可以通过miterLimit属性看到效果。
  • round通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。圆角的半径是线段的宽度。
  • bevel在相连部分的末端填充一个额外的以三角形为底的区域,每个部分都有各自独立的矩形拐角。

miterLimit设定外延交点与连接点的最大距离,斜线长度与二分之一线宽的比值,如果大于设定的miterLimit,就会以bevel方式处理连接处

setLineDash接受一个参数segments,这个参数是一个数组,一组描绘交替绘制线段和间距长度的数字

渐变

新建一个canvasGradient对象,并赋值给图形的fillStylestrokeStyle属性,来实现线性渐变和径向渐变的填充或者描边

线性渐变使用createLinearGradient(x1, y1, x2, y2)创建canvasGradient对象,(x1,y1),(x2,y2)表示渐变的起点和终点

径向渐变使用createRadialGradient(x1, y1, r1, x2, y2, r2)创建canvasGradient对象,以3个参数为一组,圆心坐标,半径,表示两个圆。

创建完canvasGradient对象,调用addColorStop(position,color)方法定义渐变的颜色,position表示位置,值范围在0.0~1.0之间,color制定渐变中的颜色

1
2
3
4
5
6
7
var lingrad = ctx.createLinearGradient(50,50,50,250);
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(0.5, '#fff');
lingrad.addColorStop(0.5, '#26C000');
lingrad.addColorStop(1, '#fff');
ctx.fillStyle = lingrad;
ctx.fillRect(50,50,200,200);
1
2
3
4
5
6
var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
radgrad.addColorStop(0, '#A7D30C');
radgrad.addColorStop(0.9, '#019F62');
radgrad.addColorStop(1, 'rgba(1,159,98,0)');
ctx.fillStyle = radgrad;
ctx.fillRect(0, 0, 150, 150);

图案样式

通过createPattern(image,type)创建一个CanvasPattern对象,参数image可以是一个Image对象的引用,或者另一个canvas对象,
type参数的值有repeatrepeat-xrepeat-yno-repeat

1
2
3
4
5
6
7
var img = new Image();
img.src = 'image/wallpaper.jpg';
img.onload = function(){
var ptrn = ctx.createPattern(img,'no-repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(50,50,300,300);
}

阴影

  • shadowOffsetX = floatshadowOffsetY = float用来设定阴影在X和Y轴的延伸距离
  • shadowBlur = float阴影模糊值
  • shadowColor = color阴影颜色,默认黑色

赋值给fillStyle前,先要确保图片已经加载完毕,不然效果可能不对

绘制文本

canvas提供了两个方法绘制文本,fillText(text,x,y,[,maxWidth])strokeText(text,x,y,[,maxWidth]),分别表示填充文本和
描边文本

文本样式

  • font=value
    绘制文本的样式,和CSS font属性相同的语法,默认字体为10px sans-serif

  • textAlign=value
    文本对齐方式,可选值包括:leftrightcenterstartend默认为start

endstart表示界限结束地方对齐,文本界限开始地方对齐,当direction=ltr,则leftstart效果相同
center表示基于x位置居中,相对于x左右均分

  • textBaseline=value
    基线对齐方式,可选的值包括:tophangingmiddlealphabeticideographicbottom。默认值是 alphabetic

  • direction=value
    文本方向,可能的值包括:ltrrtlinherit。默认值是 inherit

1
2
3
ctx.font='48px serif';
ctx.textAlign = 'center';
ctx.strokeText('hello world',200,200);

文本测量

当需要更多文本细节时,可以通过measureText()方法获得,该方法返回TextMetrics对象,包含一个width属性

图像操作

  • 获得一个指向HTMLImageElement的对象或者另一个canvas元素的引用作为源,也可以通过提供一个URL的方式来使用图片
  • 使用drawImage()函数将图片绘制到画布上

绘制图片

通过drawImage()方法渲染到canvas里,drawImage方法有三种不同形态

  • drawImage(image,x,y),其中image时image,vedio或者canvas对象,xy表示其在canvas里的起始坐标
  • drawImage(image,x,y,width,height),其中widthheight用来控制其在canvas中的大小
  • drwaImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight),第一个参数和其他的是相同的,其他8个参数
    ,前4个表示对图片的裁剪,后4个表示裁剪后的图片在canvas里显示的位置和大小

变形

状态的保存和恢复

save()restore()用来保存和恢复canvas状态,canvas的状态就是当前画面应用的所有样式和变形的一个快照

save()方法被调用后,当前的状态就被推送到栈中保存,绘画状态包括

  • 当前变形
  • 样式,strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation
  • 裁切路径

可以多次调用save()方法,每次调用restore(),上一个保存的状态就从栈中弹出

移动

translate(x,y),移动canvas的坐标原点,xy分别表示x,y方向的偏移量

旋转

rotate()以canvas坐标原点为中心旋转,该方法接受一个参数:旋转角度,它是以顺时针方向,以弧度
为单位的值

缩放

scale(x,y)xy表示缩放的比例,不能为负数,1.0表示保持原样

变形

transform(m11,m12,m21,m22,dx,dy),这个方法是将当前的变形矩阵乘上一个基于自身参数的矩阵,
m11:水平方向的缩放,m12:水平方向的偏移,m21:竖直方向的偏移,m22:竖直方向的缩放,dx:水平方向的移动,dy:竖直方向的移动

setTransform(m11,m12,m21,m22,dx,dy)这个方法会将当前的变形矩阵重置为单位矩阵

resetTransform(),重置当前变形为单位矩阵,等同ctx.setTransform(1, 0, 0, 1, 0, 0);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var sin = Math.sin(Math.PI/6);
var cos = Math.cos(Math.PI/6);
ctx.translate(200, 200);
var c = 0;
for (var i=0; i <= 12; i++) {
c = Math.floor(255 / 12 * i);
ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
ctx.fillRect(0, 0, 100, 10);
ctx.transform(cos, sin, -sin, cos, 0, 0);
}
ctx.setTransform(-1, 0, 0, 1, 100, 100);
ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
ctx.fillRect(0, 50, 100, 100);

组合

globalCompositeOperation

globalCompositeOperation=type设置图形与图形之间的层叠方式,效果

裁切路径

clip() 方法来创建一个新的裁切路径。默认情况下,canvas 有一个与它自身一样大的裁切路径