本文将对Canvas绘图技术进行简单介绍,主要包括Canvas标签、CanvasRenderingContext2D对象核心API的使用以及复杂图形的绘制等内容。

Canvas简单介绍

基本信息

Canvas 是HTML5提供的一种新标签。

1
<canvas id="canvas" width="400" height="300"></canvas>

Canvas 是一个矩形区域的画布,在画布上面我们可以通过javaScript控制每一个像素来绘制图形。

Canvas 标签使用javaScript在网页上绘制图像,其本身不具备绘图功能。通过使用canvas并调用相关API,可用多种方式来绘制路径、矩形、圆形、字符以及图像等。

拓展 最早CanvasApple公司引入到WebKit内核,用于Mac OSX的Dashboard,后来又在SafariGoogle Chrome中被实现。Canvas标签是WhatWG Web applications 1.0 规范的内容,也包含于HTML5中。

应用的领域和趋势

① 炫酷的场景秀:用Canvas实现动态的广告效果能够非常融洽的跨平台运行。
② 数据的可视化:各种统计类的图表(趋势图、饼状图、折线图等),已经有成熟的开源框架。
③ 游戏开发领域:Canvas是HTML5游戏开发首选,其在基于Web的图像方面比Flash更立体和精巧。

[1] Web图形编辑器Photoshop图形编辑器将能够100%基于Web实现。
[2] 远程可视化控制:Canvas能更好的实现基于Web的数据传输以gous可视化控制界面。
[3] 各种类型模拟器:从视觉效果和核心功能等方面来说,模拟器可以完全由JavaScript来实现。

参考资料 W3schoolMDN_Canvas_API
HTML Canvas 2D Context

绘图准备和初体验

Canvas 标签默认拥有300 * 150的宽高,可以通过设置边框来查看。
Canvas 标签支持鼠标右键·(复制图片)·以及(图片另存为)的操作,同图片一致。

Canvas 标签的参考坐标系如上图所示,其Y轴的方向区别于常见的数学坐标系。
Canvas 标签的浏览器兼容很好(IE9+),若浏览器不兼容建议设置标签内容友好提示。
Canvas 标签本身并不能绘制图形只是画布,具体绘图工作主要有Canvas上下文对象完成。
Canvas 标签上下文对象是javaScript操作Canvas的接口,常用类型是CanvasRenderingContext2D
Canvas 标签在设置画布宽度和高度的时候建议在标签中直接通过widthheight属性节点来实现。

1
<canvas id="canvas" width="400px" height="300px">当前浏览器不支持canvas,请升级浏览器</canvas>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
//01 获取canvas画布
var canvas = document.getElementById("canvas");
//02 获取canvas上下文对象
var ctx = canvas.getContext("2d");
//03 设置路径
//开启路径(可省略)
ctx.beginPath();
//设置路径的起点
ctx.moveTo(20,50);
//设置路径对应值
ctx.lineTo(100,50);
//设置线条(描边)颜色
ctx.strokeStyle = "red";
//04 绘制线条(描边)
ctx.stroke();
</script>

代码说明 上面的代码将会在canvas画布上绘制出一条红色的线条。

注意 请不要使用CSS来控制Canvas 标签的宽高,这样会导致内部图片拉伸和变形,如果重新设置Canvas 标签的宽高属性将会擦除画布中已有的所有内容。

Canvas的基本使用

CanvasRenderingContext2D 核心API介绍

这里列出CanvasRenderingContext2D原型对象上面几乎所有的核心成员供参考。

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
canvas                      //当前的画布对象
filter //设置模糊和灰度等过滤效果
globalAlpha //设置透明度(0~1)
shadowBlur //阴影的模糊级别
shadowColor //阴影的颜色
shadowOffsetX //阴影距形状的水平距离
shadowOffsetY //阴影距形状的垂直距离
fillStyle //设置矩形填充的样式(颜色)
strokeStyle //设置描边样式
lineCap //线条末端的类型 round butt(默认) square
lineJoin //相交线的拐点类型 round miter(默认) bevel
lineWidth //设置线条的宽度
miterLimit //最大斜接长度(两条线交汇处内角和外角之间的距离)
lineDashOffset //设置虚线偏移量
font //设置字体的绘制参数(字号、字体、粗体等)
textAlign //设置文字的水平对齐方式
textBaseline //设置文字基线(垂直对齐方式)
globalCompositeOperation //设置如何将一个源(新)图像绘制到目标(旧)图像上
imageSmoothingEnabled //设置图片是否平滑(非稳定)
imageSmoothingQuality //设置图像平滑度的属性(非稳定)

moveTo() //设置路径(起点)
lineTo() //设置路径
beginPath() //开启路径
closePath() //关闭路径
setLineDash() //设置虚线宽度数据
getLineDash() //获取虚线宽度集合

rect() //绘制矩形
fillRect() //矩形填充
strokeRect() //设置描边(矩形)
clearRect() //擦除矩形区域内容

stroke() //设置描边
fill() //设置填充
clip() //剪切指定形状和尺寸的区域
arc() //绘制圆弧(圆)
arcTo() //绘制曲线
ellipse() //添加椭圆路径(非稳定)
bezierCurveTo() //绘制贝塞尔曲线(3)
quadraticCurveTo() //绘制贝塞尔曲线(2)
isPointInPath() //检查某个点是否在指定的路径中
isPointInStroke() //检查某个点是否在指定(范围)
createLinearGradient() //创建线性渐变
createRadialGradient() //创建放射状/环形的渐变

fillText() //矩形填充(绘制文字)
strokeText() //设置描边(文字绘制)
measureText() //获取并计算文本宽度

drawImage() //绘制图片
createImageData() //创建新的ImageData对象
getImageData() //获取ImageData对象(矩形区域的像素数据)
putImageData() //从指定ImageData对象中把图像放到画布上面
createPattern() //在指定的方向上重复指定的元素
drawFocusIfNeeded() //如有必要则绘制焦点

save() //保存状态
scale() //设置缩放
rotate() //设置旋转
restore() //返回之前保存过的路径状态和属性
translate() //平移(重新映射画布上的(0,0)位置)
transform() //替换绘图的当前转换矩阵
setTransform() //将当前转换重置为单位矩阵,然后运行transform()
resetTransform() //使用单位矩阵重新设置当前变形(非稳定)

画布的上下文CanvasRenderingContext2D对象为图形的绘制提供了丰富的接口,我们可以直接调用相关的API来绘制路径、圆弧和矩形等图案。此外,要得到目标图案其实有很多种方法到达罗马的路途并非只有一条,而所有复杂的图案都离不开点、线和面,而且它们应该是渐进的

点-线-面

这里先在页面中提供一个400 * 300的画布,获取画布的上下文对象。

1
<canvas id="canvas" width="400px" height="200px"></canvas>
1
var ctx = document.getElementById("canvas").getContext("2d");

矩形点和圆形点的绘制

1
ctx.fillRect(10,10,5,5);            //矩形点

1
2
ctx.arc(11.5,40,3,0,2 * Math.PI);   //圆形点
ctx.fill(); //设置填充

线条的绘制

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
//方式(一) 通过绘制连续的矩形来绘制线条
//示例:(实线)
for(var i = 0 ; i < 80 ; i++)
{
ctx.fillRect(40 + (i * 1),25,1,1);
}

//示例:(虚线)
for(var i = 0 ; i < 20 ; i++)
{
ctx.fillRect(40 + (i * 4),40,2,2);
}

/*********************************************/

//方式(二) 通过路径的方式来绘制线条
//示例:(色度稀释的线条)
ctx.moveTo(40,60);
ctx.lineTo(320,60);

//示例:(色度正常的线条)
ctx.moveTo(40,70.5);
ctx.lineTo(320,70.5);

//设置描边
ctx.stroke();

面(矩形)的绘制

1
2
3
4
5
6
7
8
9
//方式(一) 以“矩形点” + 循环的方式来绘制矩形
for(var i = 0 ; i < 40 ; i++)
{
ctx.fillRect(20 + (i * 3),100,3,50);
}

//方式(二) 直接绘制矩形
ctx.fillStyle = "red";
ctx.fillRect(200,100,50,50);

这里贴出上面代码运行的结果图。

备注 在使用canvas上下文绘制线条的时候,我们会发现线条最终的颜色看上去并不是黑色的感觉比较淡,此外线条的宽度看上去也并不是1px而是2px。其实,主要原因是在canvas在进行绘制的时候,对齐的点是线的中心位置,因此就会把线分成上下两个0.5px,在进行显示的时候会补齐,因此其色度自然也是不饱和的。在绘制的时候,可以考虑给绘制坐标设置0.5px的偏移量来解决。