×

Canvas 画布

96
destiny904
2017.10.31 09:21* 字数 5036

一、简介

HTML5 中的定义:“它是依赖分辨率的位图画布,你可以在 canvas 上面绘制任何图形,甚至加载照片。”

  • 矩形空白区域
  • 通过 javascript 绘制图形
  • 可以加载图片

canvas 坐标系

二、HTML 部分

<canvas id="a" width="300" height="300">您的浏览器不支持 canvas</canvas>

简单的在 HTML 页面添加一个 canvas 元素,设定宽高,添加 id 便于 javascript 获取。

  • 每个 canvas 初始都是一个白板。
  • 样式除了宽高,尽量写在画布里,而不是使用 CSS
  • canvas 标签里如果添加文本,那么当浏览器不支持 canvas 时显示文本

三、绘图上下文环境

var a = document.getElementById('a');
var a_context = a.getContext("2d");
  • 获取到 canvas 元素
  • 调用它的 getContext() 方法获取绘图上下文环境,参数必须为 2d ,未来可能会有 3d
  • 基于上下文环境的方法进行绘图

绘图上下文包含所有绘制方法和属性的定义。

四、路径

4.1 beginPath() 开始新路径

表示重新开始新的路径。

canvas 是基于状态的绘图,开启一条新的路径,就可以设置新的状态。但是 beginPath() 不会将状态重置回默认值。

同一条路径上的线条和曲线都会是相同的颜色。所以需要绘制不同颜色的时候,必须开启新的路径。

4.2 closePath() 结束路径

用于结束路径,与 beginPath() 并不一定成对出现。

注意:默认结束路径后,图形自动封闭,即首尾相连。所以有些时候不会用到结束路径。

4.3 stroke() 绘制路径

绘制已定义的路径

4.4 fill() 填充路径

将准备画的路径块填充

fill() 会覆盖描边 stroke() 边框的一半。所以,在需要描边的填充色,需要先填充,后描边。

4.5 isPointInPath() 是否在路径中

如果指定的点位于当前路径中,则返回 true,否则返回 false

context.isPointInPath(x,y);
  • x 测试点的 x 坐标
  • y 测试点的 y 坐标

4.6 clip() 剪切

从原始画布剪切任意形状和尺寸的区域

context.clip();

注意:一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。您也可以在使用 clip() 方法前通过使用 save() 方法对当前画布区域进行保存,并在以后的任意时间通过 restore() 方法进行恢复。

五、线条以及填充颜色

5.1 fillStyle 填充样式

设置或返回用于填充绘画的颜色、渐变或模式,需要在填充前声明才有效

context.fillStyle=color|gradient|pattern;
  • color 指示绘图填充色的 CSS 颜色值。默认值是 #000000。
  • gradient 用于填充绘图的渐变对象
  • pattern 用于填充绘图的 pattern 对象

5.2 strokeStyle 线条样式

设置或返回用于笔触的颜色、渐变或模式,需要在绘制前声明才有效

context.strokeStyle=color|gradient|pattern;
  • color 指示绘图笔触颜色的 CSS 颜色值。默认值是 #000000。
  • gradient 用于填充绘图的渐变对象
  • pattern 用于创建 pattern 笔触的 pattern 对象

5.3 lineCap 线条结束端点样式

设置或返回线条的结束端点样式

context.lineCap="butt|round|square";
  • butt 默认。向线条的每个末端添加平直的边缘。
  • round 向线条的每个末端添加圆形线帽。
  • square 向线条的每个末端添加正方形线帽。

roundsquare 会使线条略微变长。

5.4 lineJoin 线条拐角类型

设置或返回两条线相交时,所创建的拐角类型

context.lineJoin="bevel|round|miter";
  • bevel 创建斜角
  • round 创建圆角
  • miter 默认。创建尖角

5.5 lineWidth 线条宽度

设置或返回当前的线条宽度

context.lineWidth=number;
  • number 当前线条的宽度,以像素计

5.6 miterLimit 线条最大斜接长度

设置或返回最大斜接长度

context.miterLimit=number;
  • number 正数
    如果斜接长度超过 miterLimit 的值,边角会以 lineJoinbevel 类型来显示。

斜接长度指的是在两条线交汇处内角和外角之间的距离。


只有当 lineJoin 属性为 miter 时,miterLimit 才有效。

边角的角度越小,斜接长度就会越大。
为了避免斜接长度过长,我们可以使用 miterLimit 属性。
如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示(图解 3):


六、直线路径

6.1 moveTo() 起点坐标

把路径移动到画布中的指定点,不创建线条。声明直线开始的起点坐标。括号里面填写坐标。

context.moveTo(100,100);

6.2 lineTo() 终点坐标

声明直线结束的终点坐标。括号里面填写坐标。

context.moveTo(100,100);//起点
context.lineTo(700,700);//终点

连续出现相当于以前一个为起点继续走向另一个坐标。

context.moveTo(100,100);//起点 
context.lineTo(700,700);//终点
context.lineTo(100,700);//以前一个终点为起点坐标

lineTo()beginPath() 后面使用时,可以代替 moveTo(),和 moveTo() 起到相同效果。

6.3 多边形

moveTo() 开始,使用 lineTo() 画直线到三个顶点,最终回到起点坐标。

如三角形:

//路径描述
context.moveTo(100,100);
context.lineTo(700,700);
context.lineTo(100,700);
context.lineTo(100,100);
//绘制
context.stroke();

七、贝塞尔曲线

7.1 quadraticCurveTo() 二次贝塞尔

通过使用表示二次贝塞尔曲线的指定控制点,向当前路径添加一个点。

二次贝塞尔曲线需要两个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。最后添加的是结束点


注意:曲线的开始点是当前路径中最后一个点。如果路径不存在,那么请使用 beginPath()moveTo() 方法来定义开始点。

context.quadraticCurveTo(cpx,cpy,x,y);
  • cpxcpy 贝塞尔控制点的坐标
  • xy 结束点的坐标

7.2 bezierCurveTo() 三次贝塞尔

通过使用表示三次贝塞尔曲线的指定控制点,向当前路径添加一个点。

三次贝塞尔曲线需要三个点。前两个点是用于三次贝塞尔计算中的控制点,第三个点是曲线的结束点。


context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
  • cp1xcp1y 第一个贝塞尔控制点的坐标
  • cp2xcp2y 第二个贝塞尔控制点的坐标
  • xy 结束点的坐标

八、画弧线、圆

8.1 arc() 创建圆路径

创建弧/曲线(用于创建圆形或部分圆)

context.arc(centerX, centerY, radius, startingAngle, endingAngle, anticlockwise=true);
  • centerx , centery 表示圆心位置
  • radius表示半径
  • startingAngleendingAngle表示开始位置和结束位置
  • anticlockwise 表示 true 时为顺时针绘制,false 为逆时针绘制。默认为 true

其中角度参数的值:0 表示圆的最右边,0.5*Math.PI 表示最下面,1*Math.PI 表示最左边,1.5*Math.PI 表示最上面,2*Math.PI 表示最右边。这些规定是固定的,不会因为顺逆时针改变。

8.2 arcTo() 两切线弧

创建两切线之间的弧/曲线

context.fillRect(x1,y1,x2,y2,r);
  • x1y1 弧的起点坐标
  • x2y2 弧的终点坐标
  • r 弧的半径

使用 stroke() 方法在画布上绘制确切的弧。

8.3 绘制

  • lineWidth 定义线条粗细
  • strokeStyle 定义描边样式
  • stroke() 描边
  • fillStyle 定义填充样式
  • fill() 填充

8.4 圆

context.arc(100,100,80,0,2*Math.PI,true);

表示从右边(0)开始,顺时针画圆,到右边(2 PI)结束。

九、文本

不同于网页中的文本,绘制在 canvas 中的文本是没有盒模型的,没有浮动、边距、留白、自动换行等。

9.1 fillText() 填充文本

context.fillText("text",x,y);
  • text 规定在画布上输出的文本
  • xy 开始绘制文本的坐标位置

9.2 strokeText() 描边文本

context.strokeText(text,x,y,maxWidth);
  • text 规定在画布上输出的文本
  • xy 开始绘制文本的坐标位置
  • maxWidth 可选。允许的最大文本宽度,以像素计

9.3 measureText() 测量文本宽度

measureText() 方法返回包含一个对象,该对象包含以像素计的指定字体宽度。

context.measureText(text).width;
  • text 要测量的文本

9.4 font 字体样式

canvas 中的字体会继承 canvas 元素的字体大小和样式风格。
设置 font 属性覆盖继承值。符合 CSS 规则。

context.font = "bold 12px sans-serif";

属性值里面的每个取值用空格隔开

  • font style
  • font variant
  • font size
  • font weight
  • lineheight
  • font family

使用相对字体大小,如 1.5em150%,是基于 canvas 元素本身的字体大小。rem 仍是基于根元素。

9.5 textAlign 对齐方式

类似 CSS 中的 text-align

context.textAlign = "start";

取值:start(默认)、endleftrightcenter

9.6 textBaseline 相对于起点的位置

控制文本相对于起点的位置。

context.textBaseline = "top";

必须使用引号。

取值:topbottomhangingmiddlealphabeticideographic

十、矩形

10.1 rect() 创建矩形

context.rect(x,y,width,height);
  • xy 矩形左上角的坐标
  • widthheight 矩形的宽高

使用 stroke()fill() 方法在画布上实际地绘制矩形。

10.2 fillRect() 已填充矩形

fillRect(x,y,width,height);
  • xy 表示矩形左上角坐标
  • widthheight表示宽高

使用 fillStyle 属性来设置用于填充绘图的颜色、渐变或模式。

10.3 strokeRect() 已描边矩形

strokeRect(x,y,width,height);
  • xy 表示矩形左上角坐标
  • widthheight表示宽高

使用 strokeStyle 属性来设置笔触的颜色、渐变或模式。

10.4 clearRect() 清空矩形区域

context.clearRect(x,y,width,height);
  • xy 表示矩形左上角坐标
  • widthheight表示宽高

十一、添加图片

11.1 drawImage() 添加图片

三种用法:

context.drawImage(img,x,y);
context.drawImage(img,x,y,width,height);
context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
  • image 为图片对象,必须
  • sxsy 为裁剪开始位置,左上角坐标,可选
  • swsh 为裁剪宽高,可选
  • dxdy 为绘制起点,左上角坐标,必须
  • dwdh 为自定义的图片宽高,可选

11.2 图片对象

  1. 已存在的 <img> 元素
//HTML部分
<img id="cat" src="images/cat.png">
//javascript部分
window.onload = function() {
  .
  .
  var cat = document.getElementById('cat');
  context.drawImage(cat,0,0); 
}

window.onload 事件处理器中,获取已有图片对象,然后在 canvas 中安全绘制图片。

  1. 自己创建的图片对象
var cat = new Image();
cat.src = "images/cat.png";
cat.onload = function() {
  context.drawImage(cat,0,0);
};

创建图片对象,然后在 cat.onload 事件处理器中安全地把图片绘制在 canvas 中。

十二、特殊样式

12.1 shadowColor 阴影颜色

设置或返回用于阴影的颜色

context.shadowColor=color;
  • color 用于阴影的 CSS 颜色值。默认值是 #000000。

12.2 shadowBlur 阴影模糊程度

设置或返回用于阴影的模糊级别

context.shadowBlur=number;
  • number 阴影的模糊级数

12.3 shadowOffsetX 阴影水平偏移

设置或返回阴影距形状的水平距离

context.shadowOffsetX=number;
  • number 正值或负值,定义阴影与形状的水平距离。

12.4 shadowOffsetY 阴影垂直偏移

设置或返回阴影距形状的垂直距离

context.shadowOffsetY=number;
  • number 正值或负值,定义阴影与形状的垂直距离

12.5 createPattern() 重复

在指定的方向内重复指定的元素。

元素可以是图片、视频,或者其他 canvas 元素。
被重复的元素可用于绘制/填充矩形、圆形或线条等等。

context.createPattern(image,"repeat|repeat-x|repeat-y|no-repeat");
  • image 规定要使用的图片、画布或视频元素。
  • repeat 默认。该模式在水平和垂直方向重复。
  • repeat-x 该模式只在水平方向重复。
  • repeat-y 该模式只在垂直方向重复。
  • no-repeat 该模式只显示一次(不重复)。

12.6 createLinearGradient() 创建线性渐变

调用 createLinearGradient() 方法创建线性渐变

createLinearGradient(x0,y0,x1,y1);

表示沿直线从(x0,y0)到(x1,y1)绘制渐变。

如水平渐变:

var my_gradient = context.createLinearGradient(0,0,300,0);

设置两个 y 值为 0,渐变会沿水平从左到右。

注意:创建渐变需要赋给一个变量,通过这个变量设置色标

12.7 createRadialGradient() 创建径向渐变

调用 createRadialGradient() 方法创建径向渐变

createRadialGradient(x0,y0,r0,x1,y1,r1)

表示沿着两个圆之间的锥面绘制渐变。
前三个参数代表开始圆,后三个参数表示结束圆。

12.8 addColorStop() 添加色标

addColorStop(index,color);
  • index 渐变位置,可以在 0 - 1 之间取任意值
  • color 渐变颜色,关键字及十六进制颜色要添加引号

注意:这个方法属于创建的渐变对象,也就是前面创建渐变时的变量。

my_gradient.addColorStop(0,"block");
my_gradient.addColorStop(1,"white");

12.9 绘制渐变

context.fillStyle = my_gradient;
context.fillRect(0,0,300,225);
  • 将填充颜色设置为创建的渐变
  • 填充所需要的图形

十三、转换

转换都应该放在绘制之前

13.1 scale() 缩放

缩放当前绘图至更大或更小

注意:如果您对绘图进行缩放,所有之后的绘图也会被缩放。定位也会被缩放,线条大小也会被缩放。

context.scale(scalewidth,scaleheight);
  • scalewidth 缩放当前绘图的宽度 (1=100%, 0.5=50%, 2=200%, 依次类推)
  • scaleheight 缩放当前绘图的高度 (1=100%, 0.5=50%, 2=200%, etc.)

13.2 rotate() 旋转

旋转当前绘图

conntext.rotate(angle);
  • angle 旋转角度,以弧度计。

将角度转换为弧度,请使用 degrees*Math.PI/180 公式进行计算。

13.3 translate() 改变原点坐标

重新映射画布上的 (0,0) 位置,改变坐标原点的位置

context.translate(x,y);
  • x 添加到水平坐标上的值
  • y 添加到垂直坐标上的值

当您在 translate() 之后调用诸如 fillRect() 之类的方法时,值会添加到 xy 坐标值上。,即后面的绘图涉及到坐标都会在此基础上增加值。

13.4 transform() 变换矩阵

画布上的每个对象都拥有一个当前的变换矩阵。
transform() 方法替换当前的变换矩阵。

它以下面描述的矩阵来操作当前的变换矩阵:

a  c  e
b  d  f
0  0  1

也就是说,transform() 允许您缩放、旋转、移动并倾斜当前的环境。

注意:该变换只会影响 transform() 方法调用之后的绘图。
前面的 rotate(), scale(), translate(), transform() 方法都会影响到当前的 transform()
例如:如果您已经将绘图设置为放到两倍,则 transform() 方法会把绘图放大两倍,您的绘图最终将放大四倍。

context.transform(a,b,c,d,e,f);
  • a 水平缩放绘图
  • b 水平倾斜绘图
  • c 垂直倾斜绘图
  • d 垂直缩放绘图
  • e 水平移动绘图
  • f 垂直移动绘图

13.5 setTransform()

将当前转换重置为单位矩阵。然后以同样的参数运行 transform(),这样就可以不受前面的影响了。

context.setTransform(a,b,c,d,e,f);
  • a 水平缩放绘图,默认值为 1
  • b 水平倾斜绘图,默认值为 0
  • c 垂直倾斜绘图,默认值为 0
  • d 垂直缩放绘图,默认值为 1
  • e 水平移动绘图,默认值为 0
  • f 垂直移动绘图,默认值为 0

所以矩阵默认为单位矩阵:

1  0  0
0  1  0
0  0  1

13.6 save()、 restore()

  • save() 保存当前环境的状态
    • 原点位置
    • 缩放大小
    • 旋转
    • 矩阵变换
    • 裁剪块
  • restore() 返回之前保存过的路径状态和属性

十四 ImageData 对象

对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:

  • R - 红色 (0-255)
  • G - 绿色 (0-255)
  • B - 蓝色 (0-255)
  • A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)

因此 ,transparent black 表示 (0,0,0,0)

color/alpha 以数组形式存在,并且既然数组包含了每个像素的四条信息,数组的大小是 ImageData 对象的四倍。获得数组大小的办法,就是使用 ImageDataObject.data.length

包含 color/alpha 信息的数组存储于 ImageData 对象的 data 属性中。

14.1 createImageData() 创建 ImageData 对象

创建新的空白 ImageData 对象。

有两个版本的 createImageData() 方法:

//以指定的尺寸(以像素计)创建新的 ImageData 对象
var imgData=context.createImageData(width,height);
//创建与指定的另一个 ImageData 对象尺寸相同的新 ImageData 对象(不会复制图像数据)
var imgData=context.createImageData(imageData);

新对象的默认像素值 transparent black

  • width ImageData 对象的宽度,以像素计。
  • height ImageData 对象的高度,以像素计。
  • imageData 另一个 ImageData 对象。

14.2 getImageData() 复制画布像素数据

返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据,进行操作后,通过 putImageData() 将图像数据放回画布

var imgData = context.getImageData(x,y,width,height);
  • xy 开始复制的左上角位置的坐标
  • widthheight 将要复制的矩形区域的宽高

14.3 putImageData() 放入像素数据

将图像数据(从指定的 ImageData 对象)放回画布上。

context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
  • imgData 规定要放回画布的 ImageData 对象
  • xy ImageData 对象放置在画布上的位置左上角的坐标,以像素计
  • dirtyXdirtyY 可选。以像素计,在画布上绘制的图像在 ImageData 对象上的位置坐标
  • dirtyWidthdirtyHeight 可选。在画布上绘制图像的宽高

后面四个属性相当于裁剪,但是,在画布上,依然是整个 ImageData 对象。
如:

var imgData=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData,10,70,20,40,30,10);

在画布上放置裁剪部分的位置就变成了(10+20,70+40),宽高是 30, 10。

注意:如果裁剪位置加上裁剪宽度,超出了原来的宽高,超出部分不会绘制

14.4 widthheight宽高

返回 ImageData 对象的宽高,以像素计。

imgData.width;
imgData.height;

14.5 data 图像数据

返回一个对象,该对象包含指定的 ImageData 对象的图像数据。

对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
R - 红色 (0-255)
G - 绿色 (0-255)
B - 蓝色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。

将 ImageData 对象中的第一个像素变为红色的语法:

imgData=ctx.createImageData(100,100);

imgData.data[0]=255;
imgData.data[1]=0;
imgData.data[2]=0;
imgData.data[3]=255;

将 ImageData 对象中的第二个像素变为绿色的语法:

imgData=ctx.createImageData(100,100);

imgData.data[4]=0;
imgData.data[5]=255;
imgData.data[6]=0;
imgData.data[7]=255;

十五、合成

15.1 globalAlpha 透明度

设置或返回绘图的当前 alpha 或透明值

context.globalAlpha=number;
  • number 透明值。必须介于 0.0(完全透明) 与 1.0(不透明) 之间。

15.2 globalCompositeOperation

设置或返回新图像如何绘制到已有的图像上

源图像 = 您打算放置到画布上的绘图。
目标图像 = 您已经放置在画布上的绘图。

context.globalCompositeOperation="source-in";
  • source-over 默认。在目标图像上显示源图像。
  • source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
  • source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
  • source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
  • destination-over 在源图像上方显示目标图像。
  • destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
  • destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
  • destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
  • lighter 显示源图像 + 目标图像。
  • copy 显示源图像。忽略目标图像。
  • xor 使用异或操作对源图像与目标图像进行组合。

十六、兼容IE

虽然 IE 浏览器不支持 canvas API,但是他有一个叫 VML 的技术,可以完成 canvas 元素能做的大部分工作。

16.1 ExplorerCanvas——excanvas.js

excanvas.js 是一个开源的,采用 Apache license 许可的 javascript 类库,在 IE 中实现了 canvas 的 API。

<!--[if lt IE9]>
  <script src="excanvas.js"></script>
<![endif]-->

16.2 限制

  • 颜色渐变只支持线性渐变
  • 模式必须在两个方向上重复
  • 不支持裁剪
  • 非等比缩放
  • 很慢
HTML
Web note ad 1