HTML5canvas标签和JavaScript的结合运用

Canvas简介

Canvas是HTML5中重要的元素,其和audio、video元素类似,完全不需要任何外部插件就能运行。

Canvas中文翻译为“画布”。它提供了强大的图形处理功能(绘制,变换,像素处理等)。

Canvas浏览器支持:除IE8及以下不支持外,其他浏览器都支持Canvas。

Canvas标签

<canvas>标签定义图形,<canvas>标签只是图形容器,必须使用脚本来绘制图形。

<canvas>您的浏览器不支持canvas</canvas>canvas标签中的内容在支持的浏览器内,默认为不显示;在不支持的浏览器上才会显示。

canvas属性:width宽 height高,假如不设置宽高属性,默认为宽300像素高150像素。

在进行图形绘制时,我们是通过context绘图环境进行操作的。

大多数 Canvas 绘图 API 都没有定义在 <canvas> 元素本身上,而是定义在通过画布的 getContext() 方法获得的一个“绘图环境”对象上。

context是canvas的核心。context字面意思是上下文,我们可以理解为绘图的助手,用于存储操作步骤。

canvas坐标系:X轴:横向向右为正方向;Y轴:竖向向下为正方向。

canvas标签的使用:

1
2
3
4
5
6
7
8
9
10
11
<body>
<canvas id="canvas1" width="500" height="500">
您的浏览器不支持canvas,请使用高版本的浏览器
</canvas>
<script type="text/javascript">
//获取canvas
var canvas = document.getElementById("canvas1");
//获取绘制环境
var context = canvas.getContext("2d");
</script>
</body>

Canvas基本图形绘制

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
基本图形绘制

beginPath() 开始一条路径

moveTo(x,y) 设置绘制起点

lineTo(x,y) 设置下一个点

closePath() 闭合路径,会从当前点连接到起始点,形成一个封闭的路径

strokeStyle 设置线条的样式(颜色)

stroke() 绘制线条

fillStyle 设置填充样式(颜色)

fill() 填充当前绘图

lineWidth 设置线宽

strokeRect(x,y,w,h) 绘制矩形边框,x,y分别为起始绘制x轴y轴的位置,w为绘制宽度,h为绘制高度

fillRect(x,y,w,h) 填充矩形边框

arc(x,y,radius,startAngle,endAngle,anticlockwise)

x,y:圆心位置 ;radius:半径;startAngle,endAngle:开始/结束角度(以弧度计算);anticlockwise:true逆时针false顺时针;

strokeText() 绘制文字

fillText() 填充文字

createLinearGradient(x0,y0,x1,y1); x0,y0:渐变开始点;x1,y1:渐变结束点

font 字体样式

阴影设置(当设置阴影后,所有的图形都会有阴影)

shadowColor 阴影颜色

shadowOffsetX X方向偏移量

shadowOffsetY Y方向偏移量

shadowBlur 设置阴影的模糊级别

图形变换

translate(x,y) 平移(当设置平移时,整个context都会发生移动,也就是坐标系发生变化)

rotate(deg) 旋转,单位为弧度(当发生旋转时,坐标系也会发生变化,通常搭配translate使用)

scale(x,y) 缩放,x、y分别为x轴和y轴方向缩放(当发生缩放时,坐标系也会相应的变化)

状态保存和获取(遵循“先进后出,后进先出”的原则)

save() 存储绘制状态

restore() 获取之前的画布状态

贝塞尔曲线

quadraticCurvaTo(cpx,cpy,dx,dy) 创建一条表示二次曲线的路径(二次曲线就是二次函数形成的曲线)
cpx,cpy代表控制点,决定曲线的形状 dx,dy代表终点位置

bezierCurveTo(cpx,cpy,cpx2,cpy2,dx,dy) 创建一条表示贝塞尔曲线的路径
cpx,cpy,cpx2,cpy2代表两个控制点的位置,决定曲线的形状 dx,dy代表终点位置

设置文字及颜色渐变:

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
26
<style>
#canvasfont{
box-shadow:0 0 20px lightgreen;
}
</style>
<canvas id="canvasfont" width="300" height="300">
您的浏览器不支持;
</canvas>
<script>
var canvasfont = document.getElementById("canvasfont");
var contextfont = canvasfont.getContext("2d");
//设置文字
var text = "hello World!";
contextfont.font = "40px 宋体";
//设置渐变
var fontgradient = contextfont.createLinearGradient(10,50,300,300);
fontgradient.addColorStop("0","blue");
fontgradient.addColorStop("0.5","gold");
fontgradient.addColorStop("1","purple");
//设置填充颜色
contextfont.fillStyle = fontgradient;
//开始填充文字
contextfont.fillText(text,30,50);
//填充矩形
contextfont.fillRect(10,60,280,230);
</script>
    
    
        您的浏览器不支持;
    
    

Canvas进阶

globalCompositeOperation属性

设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上。源图像就是打算放置到画布上的绘图。目标图像是已经放置在画布上的绘图。

其属性值为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
source-over			默认。在目标图像上显示源图像

source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的

source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的

source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的

destination-over 在源图像上方显示目标图像

destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示

destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的

destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的

lighter 显示源图像 + 目标图像(会使重叠部分颜色叠加)

copy 显示源图像。忽略目标图像

source-over 使用异或操作对源图像与目标图像进行组合
图像绘制
1
2
3
4
5
6
drawImage(image,x,y)				在canvas中x,y处绘制图片

drawImage(image,x,y,width,height) 在canvas中x,y处绘制图片,并将其缩放到指定的宽度和高度

drawImage(image,sourceX,sourceY,sourceWidth,sourceHeight,x,y,width,height)
从图片中切割出一个矩形区域(sourceX,sourceY,sourceWidth,sourceHeight),缩放到指定的宽度和高度,并在canvas中x,y绘制出来
1
2
3
4
5
6
7
8
9
10
var img = new Image();
img.src = "图片路径";
img.onload = function (){
//载入图片
context.drawImage(img,0,0);
//控制图片
context.drawImage(img,0,0,canvas,width,canvas.height);
//裁减
context.drawImage(img,0,0,100,100,50,50,img.width,img.height);
}
像素

getImageData()返回ImageData对象,该对象拷贝了画布指定矩形的像素数据。

ImageData中三个属性:width,height和data。width和height表示访问像素区域大小,data是一个包含访问区域所有像素信息的CanvasPixeArray,CanvasPixeArray是一个一维数组。

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

  1. R - 红色(0-255)
  2. G - 绿色(0-255)
  3. B - 蓝色(0-255)
  4. A - alpha通道(0-255;0是透明,255是完全可见的)
1
2
3
4
getImageData(x,y,width,height)		获取像素。x,y像素区域雨点坐标,width,height像素区域的宽度和高度

putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
插入像素。imgData像素对象、在画布上显示的x,y、从哪个位置开始展示x,y,展示的宽度,高度(后四个为可选参数)

插入图片示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var img = new Image();
img.src = "图片路径";
img.onload = function (){
context.drawImage(img,0,0);
var imgData = context.getImageData(0,0,canvas.width,canvas.height);
var pixs = imgData.data;
//因为一个参数是以四个参数组合的,所以i+=4
for(var i=0;i<pixs.length;i+=4){
var r = pixs[i];
var g = pixs[i+1];
var b = pixs[i+2];
var gray = parseInt((r+g+b)/3);
//图像反色
pixs[i] = gray;
pixs[i+1] = gray;
pixs[i+2] = gray;
}
context.putImageData(imgData,img.width,img.height);
}
视频的处理
1
2
3
4
5
6
7
8
9
10
11
12
function animate(){
if(!video.ended){
//将视频的每一帧都绘制在canvas上
context.drawImage(video,0,0,canvas,width,canvas.height);
widow.requestAnimationFrame(animate);
}
}
//当视频可以播放时,进行播放调用循环
video.oncanplay = function(){
video.play();
window.requestAnimationFrame(animate);
}

requestAnimationFrame:动画帧

requestAnimationFrame不需要使用者指定循环间隔时间,浏览器会基于当前页面是否可见、CPU的负荷情况等来自行决定最佳的帧速率,从而更合理地使用CPU。

通过setTimeout和setInterval方法在脚本中可实现动画,但是这样的效果可能不够流畅,而且会占用额外的资源。

  1. 即使向其传递毫秒为单位的参数,它们也不可能达到毫秒的准确性。这是因为JavaScript是单线程的,可能会发生阻塞。
  2. 没有对调用动画的循环机制进行优化。
  3. 没有考虑到绘制动画的最佳时机,只是一味地以某个大致的事件间隔来调用循环。
图形的存储

通过toDataURL()来生成图片链接实现

1
2
3
4
5
6
7
8
9
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillRect(100,100,100,100);
//输出
var url = canvas.toDataURL();
//在网页中显示
window.location.href = url;
</script>