标签:canvas 简单示例 入门知识
作者: 张耀国 ( IgorZhang )
E-mail: igorzhangcn@163.com
canvas 是 HTML5 新增的元素,可使用JavaScript脚本来绘制图形。例如:画图,合成照片,创建动画甚至实时视频处理与渲染。
基本用法
<canvas id="canvas" width="500px" height="500px" > 您的浏览器不支持canvas,请升级您的浏览器!</canvas>
canvas 标签只有两个属性—— width 和 height。这些都是可选的,当没有设置宽度和高度的时候,canvas会初始化宽度为300像素和高度为150像素。宽高只可以通过 JavaScript 进行修改。该元素可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲。
如果浏览器版本过低,或者浏览器内核不支持canvas标签的话,那么标签内部的替换内容将会对用户做出提示,若浏览器支持canvas,替换内容将不会出现。
绘制前准备
在绘制之前我们必须先获取canvas元素以及开启2d绘图的渲染上下文(简称获取画笔)
var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");
代码的第一行通过使用 document.getElementById() 方法来为 canvas 元素得到DOM对象。一旦有了元素对象,你可以通过使用它的getContext() 方法来访问绘画上下文。
栅格
栅格
在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。如右图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(Y轴)x像素,距离上边(X轴)y像素(坐标为(x,y))。
绘制路径
直线
绘制一条直线,我们需要两个点,即起点和终点。这两个点都将用坐标(x,y)表示。
// 获取元素var canvas = document.getElementById("canvas");// 获取上下文对象// 获取“画笔”,大多数操作都是使用画笔进行var ctx = canvas.getContext("2d");// 画一条直线// 1.开始绘制ctx.beginPath();// 2,放置起始点ctx.moveTo(100, 100);// 3.放置后续的点 (可以写任意多个)ctx.lineTo(200, 200);// 4.结束路径绘制(闭合路径) (非必需)ctx.closePath();// 5.画线ctx.stroke();
此时,我们已经画出了一条直线
我们这里要注意了:
ctx.closePath(); 使用这个方法之后,会自动将起点与终点链接起来,如果不需要连接的话,可以不用写这个方法。但是如果要绘制第二个图形的话,第二个图形必须先使用ctx.beginPath(); 方法,防止与上个图形连接。
绘制一个三角形
var canvas = document.getElementById('canvas');var ctx = canvas.getContext('2d');// 1.开始绘制ctx.beginPath();// 2.放置起始点ctx.moveTo(75,50);// 3.放置后续两个点ctx.lineTo(100,75); ctx.lineTo(100,25);// 4.闭合路径ctx.closePath();// 5.画线ctx.stroke();
我们通过获取三个点之后用ctx.stroke()方法进行连接。就可以得到一个三角形。但是:我们此时绘制的仅仅是三条细长的直线连接。有没有什么方法可以修改它的样式呢? 有的,这里我们只需要设置几个属性即可。
// 设置线条宽度ctx.lineWidth = 20;// 设置线条颜色ctx.strokeStyle = "red";// 设置填充颜色ctx.fillStyle = "brown";// 设置线两端为圆角// 在使用lineCap的时候,一定要非常小心closePathctx.lineCap = "round";// 设置交叉线的交接为圆角ctx.lineJoin = "round";
这里我们要介绍另一个方法了:fill(); (填充)
fill ( ) 方法能够将绘制的图形进行填充。在刚刚我们绘制三角形时,如果使用 fill ( ) 方法,我们将会获得一个经过颜色填充的三角形。那么我们可以 stroke()和 fill()两个方法同时使用吗? 没问题,这是可以的。
综合实例:绘制一个边框宽度为20像素,边框颜色为红色,填充颜色为黄色的三角形
ctx.beginPath(); ctx.moveTo(75,50); ctx.lineTo(100,75); ctx.lineTo(100,25); ct.lineWidth = 20; ctx.strokeStyle = "red"; ctx.stroke(); ctx.fillStyle = "yellow"; ctx.fill();
绘制矩形
绘制矩形,canvas 给我们提供了非常便捷的方法:
绘制一个矩形边框strokeRect(x, y, width, height);
绘制一个填充后的矩形fillRect(x, y, width, height);
擦除指定大小的矩形区域(可以理解为橡皮擦)clearRect(x, y, width, height);
x , y 是相对于canvas左上角(原点)的坐标,同样。我们要绘制的矩形也将以 x, y为原点进行绘制。 width 和 height 即为我们要绘制矩形的宽和高。
简单实例:
ctx.fillRect(25,25,100,100); ctx.clearRect(45,45,60,60); ctx.strokeRect(50,50,50,50);//fillRect()函数绘制了一个边长为100px的黑色正方形。clearRect()函数从正方形的中心开始擦除了一个60*60px的正方形,接着strokeRect()在清除区域内生成一个50*50的正方形边框。
实现效果:
综合实例:绘制一个长宽为200px,边框为10px红色,填充颜色为绿色的,且中间部分矩形区域透明的矩形
ctx.fillStyle = "green"; ctx.lineWidth = "10px"; ctx.strokeStyle = "red"; ctx.strokeRect( 100, 100, 200, 200); ctx.strokeRect( 100, 100, 200, 200); ctx.clearRect( 150, 150, 100, 100);
绘制圆和圆弧
绘制圆弧或者圆,我们使用arc()方法。
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1, y1, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
该方法有五个参数:x,y为绘制圆弧所在圆上的圆心坐标。radius为半径。startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准。参数anticlockwise 为一个布尔值。为true时,是逆时针方向,否则顺时针方向。
注意:arc()函数中的角度单位是弧度,不是度数。角度与弧度的js表达式:radians=(Math.PI/180)*degrees。
小例子:绘制笑脸
// 笑脸ctx.beginPath(); ctx.arc(250,430,70, 0,Math.PI*2, true); ctx.stroke(); ctx.beginPath(); ctx.arc(250,430,50, 0,Math.PI, false); ctx.stroke(); ctx.beginPath(); ctx.arc(230,410,10, 0,Math.PI*2, true); ctx.stroke(); ctx.beginPath(); ctx.arc(270,410,10, 0,Math.PI*2, true); ctx.stroke();
小例子:绘制一个绘制一个由多个随机颜色不同大小的圆组成的镖靶
// 定义一个函数,用于获取随机颜色function random () { return parseInt(Math.random() * 255); }// 用for循环创建10个填充了随机颜色的圆形for( var i = 10; i > 0 ; i--){ ctx.beginPath(); ctx.arc(200, 200, 20 * i, 0, Math.PI * 2, true); ctx.fillStyle = "rgb(" + random() + "," + random() + "," +random() + ")"; ctx.fill(); ctx.stroke(); }
绘制二次贝塞尔曲线及三次贝塞尔曲线
贝塞尔曲线
在绘制图形时,贝塞尔全非常有用,常用来绘制复杂的有规律的图形。
quadraticCurveTo(cpx, cpy, x, y)
绘制二次贝塞尔曲线,cpx,cpy表示控制点的坐标, x,y表示终点坐标;
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
上边的图能够很好的描述两者的关系,贝塞尔曲线有一个开始、结束点(蓝色)以及一个控制点(红色),而三次贝塞尔曲线使用两个控制点。
参数x、y在这两个方法中都是结束点坐标。cp1x,cp1y为坐标中的第一个控制点,cp2x,cp2y为坐标中的第二个控制点。
二次贝塞尔曲线
quadraticCurveTo(cpx, cpy, x, y)
cpx,cpy表示控制点的坐标, x,y表示终点坐标;
P0 为起点, P2为终点, P1为控制点。
// 先简单绘制一个二次贝塞尔曲线var canvas=document.getElementById('canvas');var context=canvas.getContext('2d');//绘制起始点、控制点、终点 context.beginPath(); context.moveTo(20,170); context.lineTo(130,40); context.lineTo(180,150); context.stroke(); //绘制二次贝塞尔曲线 context.beginPath(); context.moveTo(20,170); context.quadraticCurveTo(130,40,180,150); context.strokeStyle = "red"; context.stroke();
效果如图:
实例: 用二次贝塞尔曲线绘制对话气泡
// 二次贝尔赛曲线ctx.beginPath(); ctx.moveTo(75,25); ctx.quadraticCurveTo(25,25,25,62.5); ctx.quadraticCurveTo(25,100,50,100); ctx.quadraticCurveTo(50,120,30,125); ctx.quadraticCurveTo(60,120,65,100); ctx.quadraticCurveTo(125,100,125,62.5); ctx.quadraticCurveTo(125,25,75,25); ctx.stroke();
代码效果如下:
三次贝塞尔曲线
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
P0 和 P3 为起点和终点, P1 和 P2 为控制点
先简单绘制一个三次贝塞尔曲线模型感受一下。
var canvas=document.getElementById('canvas');var context=canvas.getContext('2d'); //绘制起始点、控制点、终点 context.beginPath(); context.moveTo(25,175); context.lineTo(60,80); context.lineTo(150,30); context.lineTo(170,150); context.stroke();//绘制3次贝塞尔曲线 context.beginPath(); context.moveTo(25,175); context.bezierCurveTo(60,80,150,30,170,150); context.strokeStyle = "red"; context.stroke();
效果图如下:
实例:使用三次贝塞尔曲线绘制一个心形
// 三次贝塞尔曲线ctx.beginPath(); ctx.moveTo(75,40); ctx.bezierCurveTo(75,37,70,25,50,25); ctx.bezierCurveTo(20,25,20,62.5,20,62.5); ctx.bezierCurveTo(20,80,40,102,75,120); ctx.bezierCurveTo(110,102,130,80,130,62.5); ctx.bezierCurveTo(130,62.5,130,25,100,25); ctx.bezierCurveTo(85,25,75,37,75,40); ctx.fill();
代码效果如下:
!
绘制文本
canvas 提供了两种方法来渲染文本:
fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
strokeText(text, x, y [, maxWidth])
在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的
上代码:
var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");// 获取canvas的宽度和高度var canvasWidth = canvas.width;var canvasHeight = canvas.height;// 设置字体ctx.font = "50px 宋体"// 设置水平对其方式// 水平对齐选项. 可选的值包括:start, end, left, right or center. 默认值是 start。ctx.textAlign = "center";// 设置垂直对齐方式// 基线(垂直)对齐选项. 可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。ctx.textBaseline = "middle"// 绘制文字ctx.storkeText("今天要是啊",100,100);// 让文字水平垂直居中ctx.font = "40px 楷体"ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("哈哈哈", canvasWidth/2, canvasHeight/2);
文本同样可以使用 strokeText() 和 fillText() 来绘制空心或实心文字,并且可以添加各种样式
使用图片
从零创建一个图片
我们可以用脚本创建一个新的Image对象。要实现这个方法,我们可以使用很方便的Image()构造函数。
var img = new Image(); // 创建一个<img>元素img.src = 'myImage.png'; // 设置图片源地址
当脚本执行后,图片开始装载。
若调用 drawImage 时,图片没装载完,那什么都不会发生(在一些旧的浏览器中可能会抛出异常)。因此你应该用load时间来保证不会在加载完毕之前使用这个图片:
var img = new Image(); // 创建img元素img.src = 'myImage.png'; // 设置图片源地址// 当图片加载完毕之后,才把图片绘制到canvas中img. = function(){ // 执行drawImage语句 ctx.drawImage(img, 100, 100); } img.src = 'myImage.png'; // 设置图片源地址
使用视频帧
你还可以使用<video> 中的视频帧(即便视频是不可见的)。例如,如果你有一个ID为“myvideo”的<video> 元素,你可以这样做:
function getMyVideo() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); return document.getElementById('myvideo'); } }
它将为这个视频返回HTMLVideoElement对象,抓取当前视频帧作为一个图像。
形变
旋转、位移、缩放
旋转:
ctx.rotate(deg);
以坐标原点进行 deg 角度的旋转,可以为负值
位移:
ctx.translate(x, y);
以坐标原点进行横向(x 像素),纵向(y 像素)的位移,可以为负值
缩放:
ctx.scale(x, y);
以坐标原点进行横向(x 倍数),纵向(y 倍数)的缩放。
综合实例: 利用一个综合性的小实例进行学习(制作一个表盘)
var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");// 获取canvas的宽度和高度var canvasWidth = canvas.width;var canvasHeight = canvas.height;// 将坐标原点移动至画布中心ctx.translate(canvasWidth/2, canvasHeight/2);// 设置线的两端为圆角ctx.lineCap = "round";// 设置线条宽度为10pxctx.lineWidth = 10;// 用foru循环绘制表盘的时间刻度for(var i = 0; i < 12; i++) { ctx.beginPath(); // 绘制一条长度为20的线 ctx.moveTo(0,-200); ctx.lineTo(0, -180); ctx.stroke(); // 绘制完成后将坐标原点旋转30度 ctx.rotate(Math.PI / 6); }
建议将代码拷贝到你自己的编辑器中多进行修改,可更快的了解每个方法和属性的作用。祝你学习愉快。
作者:IgorZhang
链接:https://www.jianshu.com/p/e23ebc4731cb
共同学习,写下你的评论
评论加载中...
作者其他优质文章