HTML 5 canvas 与 svg 都是画布,用用于绘制图像,HTML 5 canvas
是新增的属性,而svg历史比canvas久远,起源于xml;两者虽然都是用于绘制图像,但是两者却有着很大的区别;
svg 是矢量图,矢量图的特性的不会失真,所以一般用于绘制地图; canvas 是位图,位图是通过像素点来绘制图像,一般用于游戏界面的绘制。
当然我们这片文章主要讲解一下canvas里一些常用的API。提起画图,那肯定就离不开画写矩形,圆形,线条,文字呀等等;
既然画图,我们肯定需要找到一个可以画图的小画布,所以我们需要创建一块小画布,我们创建了一块宽高都为500的小画布,当然此时他就是一块小白块,所以我们需要给他一些样式让我们更加直观的看见他。
<canvas id="mycanvas" width="500" height="500px" style="border: 1px solid"></canvas>
画布创建完成后,那么问题来了,我们怎么样才可以画图呢?在小黑板上画图还需要一直粉笔,在画布上我们也需要一直画笔,此时我们需要获取这只画笔。
var mycanvas = document.getElementById('mycanvas');
var cxt = mycanvas.getContext('2d');
当我们创建了一只画笔后,就可以开始绘制一些简单的图形,我们先来画一个坐标为(100,100),宽高为100的矩形看看效果。
cxt.fillRect(100,100,100,100);
此时是一个黑色填充的正方形,如果只是黑白图像,那么这个图像肯定就是不好看的,那么我们再来创建一个不同颜色的矩形。
cxt.fillStyle = 'blue';
圆形也是不可缺少的一种常见的图片,画图少了他怎么能够行,让我们一起来看看效果。
cxt.fillStyle = 'red';
cxt.arc(0,0,100,0,Math.PI)
cxt.fill();
我们可能会要疑问,为什么一个圆却只显示了四分之一呢?
我们都知道圆有自己的坐标,半径,如上图我们就知道,原来我们的坐标点在(0,0),所以只显示出了四分之一,我们把圆给位置调整看一下
那为什么调整了位置后,却只显示了二分之一的圆呢?
我们在数学中学过的弧度,π是180度,而在JavaScript中π是Math.PI,那么我们就是Math.PI是180度,也就是一个半圆,由此我们就可以尝试画出四分之一的圆,半圆,四分之三的圆和整圆。
cxt.fillStyle = 'red';
// 四分之一的圆
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.fill();
//半圆
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.fill();
//四分之三的圆
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.fill();
//整圆
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.fill();
我们看效果,于是很奇怪,我什么不是我想要的效果呢?而是成为了四个有着圆的弧度,但是不是四个弧形的不规则图形呢?
fill()是实心填充,这样我们不好看效果,我们把它给转化成不填充的样式,来分析他们的路径。
cxt.strokeStyle = 'red';
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.stroke();
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.stroke();
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.stroke();
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.stroke();
变成线条后我们可以清楚直观的看见路径的走向,原来我们上次绘制的弧形的终点与我们下一次绘制的起点也自动的链接起来了,那么我们设置起点和终点开看一看。
cxt.strokeStyle = 'red';
// 四分之一的圆
cxt.beginPath()
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.stroke();
cxt.closePath()
//半圆
cxt.beginPath()
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.stroke();
cxt.closePath()
//四分之三的圆
cxt.beginPath()
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.stroke();
cxt.closePath()
//整圆
cxt.beginPath()
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.stroke();
cxt.closePath()
调整好了起点到终点,我们来看一下实心填充之后的状态。
cxt.fillStyle = 'red';
//四分之一的圆
cxt.beginPath()
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.fill();
cxt.closePath()
//半圆
cxt.beginPath()
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.fill();
cxt.closePath()
//四分之三的圆
cxt.beginPath()
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.fill();
cxt.closePath()
//整圆
cxt.beginPath()
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.fill();
cxt.closePath()
造成这个的原因是因为开始路径到截止路径,canvas默认会链接起来,只不过我们看不见,所以我们从圆心创建起点,然后空心填充看一下效果
cxt.strokeStyle = 'red';
//四份之一的圆
cxt.beginPath()
cxt.moveTo(60,200)
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.stroke();
cxt.closePath()
//半圆
cxt.beginPath()
cxt.moveTo(180,200)
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.stroke();
cxt.closePath()
//四分之三的圆
cxt.beginPath()
cxt.moveTo(310,200)
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.stroke();
cxt.closePath()
//整圆
cxt.beginPath()
cxt.moveTo(430,200)
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.stroke();
cxt.closePath()
此时我们以圆心为起点连接到圆的起点,我们需要将圆的终点在连接至圆心将弧形给闭合起来(此时这里默认会链接起来,做实心填充无需这一步),一起来看一下效果。
cxt.strokeStyle = 'red';
//四份之一的圆
cxt.beginPath()
cxt.moveTo(60,200)
cxt.arc(60,200,50,0,Math.PI * 0.5)
cxt.lineTo(60,200)
cxt.stroke();
cxt.closePath()
//半圆
cxt.beginPath()
cxt.moveTo(180,200)
cxt.arc(180,200,50,0,Math.PI * 1)
cxt.lineTo(180,200)
cxt.stroke();
cxt.closePath()
//四分之三的圆
cxt.beginPath()
cxt.moveTo(310,200)
cxt.arc(310,200,50,0,Math.PI * 1.5)
cxt.lineTo(310,200)
cxt.stroke();
cxt.closePath()
//整圆
cxt.beginPath()
cxt.moveTo(430,200)
cxt.arc(430,200,50,0,Math.PI * 2)
cxt.lineTo(430,200)
cxt.stroke();
cxt.closePath()
在画图工具中,创建文本是不可缺少的一部分,比如说给图片添加水印等等,我们给画布添加一段文字,看看效果
cxt.fillText('Hello World',0,0);
我们会很奇怪的发现我们在填充的文字竟然在canvas中没有显示出来,原来文字有自己的文本基线,我们只需要设置一下文本的基线就可以了,
值 | 描述 |
---|---|
alphabetic | 默认。文本基线是普通的字母基线。 |
top | 文本基线是 em 方框的顶端。 |
hanging | 文本基线是悬挂基线。 |
middle | 文本基线是 em 方框的正中。 |
ideographic | 文本基线是表意基线。 |
bottom | 文本基线是 em 方框的底端。 |
cxt.textBaseline = 'top'
cxt.fillText('Hello World',0,0)
一看这个文本,好像有点小,字体也不太好看,我们来设置一下字体的样式
cxt.font = '24px 宋体'
cxt.textBaseline = 'top'
cxt.fillText('Hello World',250,0)
奇怪的是我们字体的位置调整在中间,文本却整体靠右,设置一下文本的对齐方式
值 | 描述 |
---|---|
start | 默认。文本在指定的位置开始。 |
end | 文本在指定的位置结束。 |
center | 文本的中心被放置在指定的位置。 |
left | 文本在指定的位置开始。 |
right | 文本在指定的位置结束。 |
cxt.textBaseline = 'top'
cxt.textAlign = 'center'
cxt.fillText('Hello World',250,0)
模仿那些水印的生成,我们将字体旋转45°。
cxt.textBaseline = 'middle'
cxt.textAlign = 'center'
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',250,250)
纳尼?为什么会在这个角落里,原来是旋转的时候我们的圆心在(0,0)的位置,我们来修改一下将圆心修改至中间再来旋转。
cxt.translate(250,250)
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',250,250)
不见了,为什么呢?原来我们绘图本来是以(0,0)作为相对左边绘制的,此时我们将坐标改至(250,250);在以(250,250)的坐标绘制距离坐标(250,250)的文本,就是在(500,500)处,超出画布的界限,自然而然的就显示不了啦。我们更改一下坐标。
cxt.translate(250,250)
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',0,0)
当画布设置旋转之后,我们在继续绘制其他路径时也是旋转的状态,再次设置旋转是我们的旋转的角度是当前旋转的元素在继续旋转,是一个累加的过程。
cxt.translate(250,250)
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',0,0)
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',100,100)
那么我们每次旋转完成后,我们将旋转的角度在旋转回去,就不会出现这样的问题,但是这样感觉也太麻烦了吧,我们每次旋转之前保存当前环境,在旋转完成后在返回当前环境。
cxt.translate(250,250)
cxt.save();
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',0,0)
cxt.restore();
cxt.rotate(45*Math.PI/180)
cxt.fillText('Hello World',100,100)
//阴影的模糊级别
cxt.shadowBlur = 10;
//阴影的颜色
cxt.shadowColor = 'red'
//阴影距离文本的距离
cxt.shadowOffsetX = 10;
cxt.shadowOffsetY = 10;