canvas基础
canvas 又称画布, 是html5的核心技术之一。
- 使用canvas可以绘制各种基本图形,如矩形、曲线、圆等。
- 很多公司的图表的底层都是用canvas来绘制的。
- canvas也可以用来做游戏
canvas 与svg
他们的区别如下:
canvas是位图,适用于像素处理和动态渲染,放大会使图形失真;而svg是基于矢量的,适合静态描述,放大图形也不会使图形失真
canvas与svg的关系 简单来说就像美术与几何的关系
canvas元素
<canvas id="canvas" width="150" height="150"></canvas>
使用canvas元素来绘制图形 需要以下三步:
- 获取canvas对象
- 获取上下文环境对象context
- 开始绘制图形
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
// 绘制图形
ctx.moveTo(50,100)
ctx.lineTo(150, 50)
ctx.stroke();
} else {
// canvas-unsupported code here
}
上面的代码会画出一个2点之间的直线
如图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(X轴)x像素,距离上边(Y轴)y像素(坐标为(x,y))
后面主要通过以下几个方面去介绍canvas的用法:
- 图形的绘制
- 事件操作
- 物理动画
- 边界检测
图形的绘制
- 直线的绘制
- 曲线的绘制
- 文本操作
- 图片的操作
- canvas的路径
canvas 对象
canvas对象的常用属性有width和height。 设置宽和高可以通过在canvas的标签里面给定。 通常使用cnv.width和cnv.height来获取canvas宽和高
保存为图片
在canvas中可以使用toDataURL(type)将画布另存为一张图片
type是可选的参数,默认是png。图片是base64格式的
let dataURL = canvas.toDataURL()
// console.log(dataURL);
let a = document.createElement('a');
a.download = 'canvas';
a.href = dataURL;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
直线
在canvas中,我们可以用moveTo()和 lineTo()这两个方法配合来画直线 语法:
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
- x1,y1 是起点, moveTo表示将画笔移到该位置,然后开始绘画。
- x2,y2 是终点,lineTo表示 使用画笔从起点开始画直线,一直画到终点。
- 上面的代码仅仅是确定起点终点坐标,实际上笔还没动。因此需要调用stroke方法才有效。stroke表示用笔连线。
矩形
绘制矩形油strokeRect、fillRect和rect 3个方法 重点说下rect方法 语法
- rect(x,y,width, height) 分别表示起点左上角的坐标和宽度、高度
清空矩形
ctx.clearRect(x,y,width,height) 参数和画矩形的参数是一样的,该方法用来清空指定矩形区域
也可以常用作把整个canvas画布清空 ctx.clearRect(0,0,cnv.width, cnv.height) 把宽、高设置为整个canvas的宽、高,就可以使整个canvas画布被清空
曲线
曲线分为圆形和弧线 这2个是不同概念。
弧线
在canvas中可以用arc()方法来画一个弧线
ctx.beginPath()
ctx.arc(x,y, 半径, 开始弧度, 结束弧度, 是否逆时针boolean值)
ctx.strokeStyle = '颜色值'
ctx.stroke();
我们必须先调用beginPath 方法来声明一个新路径,然后才可以开始画弧线,之后不需要closePath来关闭路径,因为曲线不是闭合图形
注意:arc()函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式:
弧度=(Math.PI/180)*角度。
文本
canvas 提供了两种方法来渲染文本:
fillText(text, x, y [, maxWidth]) 在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的. strokeText(text, x, y [, maxWidth]) 在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的. fillText是实心的,strokeText是空心的。
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = "48px serif";
ctx.fillText("Hello world", 10, 50);
}
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = "48px serif";
ctx.strokeText("Hello world", 10, 50);
}
使用样式和颜色
色彩 Colors 到目前为止,我们只看到过绘制内容的方法。如果我们想要给图形上色,有两个重要的属性可以做到:fillStyle 和 strokeStyle。
fillStyle = color 设置图形的填充颜色。 strokeStyle = color 设置图形轮廓的颜色。 color 可以是表示 CSS 颜色值的字符串,渐变对象或者图案对象。
// 这些 fillStyle 的值均为 '橙色'
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
lineWidth 属性
这个属性设置当前绘线的粗细。属性值必须为正数。默认值是1.0
使用虚线
用 setLineDash 方法来制定虚线样式. setLineDash 方法接受一个数组,来指定线段与间隙的交替;
var ctx = document.getElementById('canvas').getContext('2d');
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.setLineDash([4, 2]);
ctx.strokeRect(10,10, 100, 100);
}
绘制路径
路径的概念很重要。除了矩形,其他所以的基本图形,包括直线、园、曲线都是以路径为基础的。
图形的基本元素是路径。
- 首先,你需要创建路径起始点。
- 然后你使用画图命令去画出路径。
- 之后你把路径封闭。
一旦路径生成,你就能通过描边或填充路径区域来渲染图形。 以下是所要用到的函数:
beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。 closePath() 闭合路径之后图形绘制命令又重新指向到上下文中。 stroke() 通过线条来绘制图形轮廓。 fill() 通过填充路径的内容区域生成实心的图形。
闭合路径closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
绘制一个三角形 例如,绘制三角形的代码如下:
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill();
}
}
二次贝塞尔曲线及三次贝塞尔曲线 下一个十分有用的路径类型就是贝塞尔曲线。二次及三次贝塞尔曲线都十分有用,一般用来绘制复杂有规律的图形。
quadraticCurveTo(cp1x, cp1y, x, y) 绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。 bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。 右边的图能够很好的描述两者的关系,二次贝塞尔曲线有一个开始点(蓝色)、一个结束点(蓝色)以及一个控制点(红色),而三次贝塞尔曲线有两个控制点。
参数x、y在这两个方法中都是结束点坐标。cp1x,cp1y为坐标中的第一个控制点,cp2x,cp2y为坐标中的第二个控制点。
使用图像
canvas更有意思的一项特性就是图像操作能力。浏览器支持的任意格式的外部图片都可以使用,比如PNG、GIF或者JPEG。
由零开始创建图像
var img = new Image(); // 创建一个<img>元素
img.src = 'myImage.png'; // 设置图片源地址
当脚本执行后,图片开始装载。
若调用 drawImage 时,图片没装载完,那什么都不会发生(在一些旧的浏览器中可能会抛出异常)。因此你应该用load事件来保证不会在加载完毕之前使用这个图片:
var img = new Image(); // 创建img元素
img.onload = function(){
// 执行drawImage语句
}
img.src = 'myImage.png'; // 设置图片源地址
img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
base64图像也是可以的
绘制图片 一旦获得了源图对象,我们就可以使用 drawImage 方法将它渲染到 canvas 里。drawImage 方法有三种形态,下面是最基础的一种。
drawImage(image, x, y) 其中 image 是 image 或者 canvas 对象,x 和 y 是其在目标 canvas 里的起始坐标。
canvas状态
canvas是基于‘状态’来绘制图形的。每一次绘制,都会检测整个程序定义的所有状态,颜色、lineWidth等。当一个状态值没有被改变时,canvas就一直使用最初的值。当一个状态值被改变时,分为两种情况考虑。
如果用了beginPath()方法开始一个新路径,则不同路径使用不用的值 。
如果没有用新路径,则后面的值会覆盖前面的值。
canvas为我们提供了两个操作状态的方法: save()和restore()。
save() 是 Canvas 2D API 通过将当前状态放入栈中,保存 canvas 全部状态的方法。
restore() 是 Canvas 2D API 通过在绘图状态栈中弹出顶端的状态,将 canvas 恢复到最近的保存状态的方法。 如果没有保存状态,此方法不做任何改变
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.save(); // 保存默认的状态
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);
ctx.restore(); // 还原到上次保存的默认状态
ctx.fillRect(150, 75, 100, 100);
事件操作
事件主要有鼠标事件、键盘事件。
这里主要讲一下鼠标事件。click\mousedown\mouseup和mousemove 几种常用事件等。
事件主要运用在canvas对象上。
通过对canvas.addEveentListener上添加鼠标事件,然后通过e.pageX\e.pageY来获取鼠标坐标。也可以通过offsetX、offsetY来获取相对于带有定位的父盒子的x,y坐标
基本的动画
动画的基本步骤 你可以通过以下的步骤来画出一帧:
清空 canvas 除非接下来要画的内容会完全充满 canvas (例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。 保存 canvas 状态 如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。 绘制动画图形(animated shapes) 这一步才是重绘动画帧。 恢复 canvas 状态 如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。
为了实现动画,我们需要一些可以定时执行重绘的方法。有两种方法可以实现这样的动画操控。首先可以通过 setInterval 和 setTimeout 方法来控制在设定的时间点上执行重绘。
边界检测
在canvas动画中,物体应该有一个运动范围。这个范围就需要对其上、下、左、右的边界进行检测。
简单的方法就是判断物体运动时当前的x\y值是否大于设定的范围的x\y。以及超出之后需要对物体做出的一系列处理。比如 边界限制(不允许超出边界)、边界环绕(一边界消失从 对面的边界重新出现)、边界反弹(超出反弹回来)、边界生成(超出 会在最开始的位置重新生成)。这里一般涉及到canvas游戏开发,(包括碰撞检测--检测物体与物体之间是否发生碰撞)感兴趣的可以自己深入学习。