概念
Canvas是什么?
<canvas>
是一个可以使用脚本来绘制图形的HTML元素。canvas是HTML5新增的标签,表示“油画布”。是HTML5中最最浓墨重彩的一笔,能够颠覆Flash。
例如,它可以用于绘制图表、制作图片构图或者制作简单的动画.
开始前的准备
HTML+Javascript知识
一些过时的浏览器不支持<canvas>
元素,但是所有的新版本主流浏览器都支持它。
Canvas基本用法。
如何去设置一个 canvas 2D 上下文以及如何在浏览器上创建第一个例子。
1.添加<canvas>
元素
<canvas id="tutorial" width="150" height="150"></canvas>
2.渲染上下文
<canvas>
元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。一般将主要用于2D渲染上下文中。其他种类的上下文提供了不同种类的渲染方式;比如,WebGL便可以进行3D渲染上下文。
//得到画布
var canvas = document.getElementById('tutorial');
//得到上下文
var ctx = canvas.getContext('2d');
之后的所有绘制,都是调用ctx的方法,而不是canvas的方法。
例如:
ctx.fillRect();
ctx.fillArc();
简单例子
<html>
<head>
<script type="application/javascript">
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, 55, 50);
}
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas" width="150" height="150"></canvas>
</body>
</html>
运行效果
绘制形状
坐标系:
canvas中有两个重要的部分:
1、stroke(笔触、描边)
2、fill(填充)
什么意思呢?
绘制矩形
fillRect(x,y,width,height)
绘制一个填充的矩形
strokeRect(x,y,width,height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明(当宽高等于画布的宽高时,也可用于清除画布内容)
//得到画布
var canvas=document.getElementById("mycanvas");
//得到2d上下文
var ctx=canvas.getContext('2d');
//更改笔触颜色
ctx.strokeStyle='red';
//设置笔触粗细
ctx.lineWidth="4px";
//开始绘制
ctx.strokeRect(30,30,50,100);
填充矩形:
//得到画布
var canvas=document.getElementById("mycanvas");
//得到2d上下文
var ctx=canvas.getContext('2d');
//填充颜色
ctx.fillStyle="blue";
//绘制填充矩形
ctx.fillRect(30,30,50,50);
清除矩形:
//得到画布
var canvas=document.getElementById("mycanvas");
//得到2d上下文
var ctx=canvas.getContext('2d');
/*先绘制填充矩形*/
//填充颜色
ctx.fillStyle="blue";
//绘制填充矩形
ctx.fillRect(30,30,100,100);
/*清除矩形*/
ctx.clearRect(30,30,25,25);
直接在画布上绘制矩形的上面三个额外方法,同样,也有rect()方法,将一个矩形路径增加到当前路径上。
react(x,y,width,height)
当该方法执行的时候,moveTo()方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置回默认坐标。
这个方法绘制出的是路径,需要stroke()描边,或者fill()进行填充
绘制路径
路径就是线,路径没有fill,只有stroke。路径没有填充色,只有描边。
需要注意的是:
一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤。
- 首先,需要创建路径起始点。
- 然后使用“画图命令”去画出路径。
- 之后把路径封闭。
- 一旦路径生成,你就能通过描边或填充路径区域来渲染图形。
绘制路径常用的函数:
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。
strole()
通过线条来绘制图形轮廓。
fill()
通过填充路径的内容区域生成实心的图形。
案例
//得到画布
var canvas=document.getElementById("mycanvas");
//得到上下文
var ctx=canvas.getContext("2d");
//开始绘制路径
ctx.beginPath();
//绘制点移动到100,100的位置
ctx.moveTo(100,100);
//绘制一条线,从绘制点的位置到100,200
ctx.lineTo(100,200);
//绘制一条线,从100,200到150,150
ctx.lineTo(150,150);
//闭合路径,此时会自动绘制一条线,连接起点和终点
ctx.closePath();
//设置stroke的颜色
ctx.strokeStyle="black";
ctx.lineWidth="4";
ctx.stroke();
//填充色
ctx.fillStyle="red";
ctx.fill();
运行效果:
画线是虚的(不可见的),只有stroke()、fill()了,才能看见。
圆弧
绘制圆弧或者圆使用arc()
方法。
arc(x,y,radius,startAngle,endAngle,anticlockwise)
x,y : 圆心坐标
startAngle : 开始弧度
endAngle : 结束弧度
anticlewise :是否逆时针(true为逆时针,false为顺时针)
ctx.arc(200,200,100,0,90*Math.PI/180,false);
90角度
的圆弧
ctx.arc(200,200,100,0,360*Math.PI/180,false);
完整的圆弧
现在,我们利用这个方法来绘制一个卡通笑脸
//得到画布
var canvas=document.getElementById("mycanvas");
//得到上下文
var ctx=canvas.getContext("2d");
/*绘制笑脸*/
var wholeAngle=Math.PI*2;
ctx.beginPath();
//绘制脸
ctx.arc(100,100,80,0,wholeAngle,false);
//移动画笔
ctx.moveTo(70,80);
//绘制左眼
ctx.arc(60,80,10,0,wholeAngle,false);
//移动画笔
ctx.moveTo(150,80);
//绘制右眼
ctx.arc(140,80,10,0,wholeAngle,false);
//移动画笔
ctx.moveTo(50,120);
//绘制嘴巴
ctx.arc(100,120,50,0,0.5*wholeAngle,false);
ctx.stroke();
运行效果 |
---|
贝塞尔曲线
用来绘制复杂又规律的图形
quadraticCurveTo(cp1x,cp1y,x,y)
绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点(蓝色),x,y为结束点(红色)
其中有一个蓝色点可以是绘制的起点,也可以是上一个二次贝塞尔曲线的结束点。
做个实例来看一下:
//得到画布
var canvas=document.getElementById("mycanvas");
//获取上下文
var ctx=canvas.getContext("2d");
var cpx1=350;
var cpy1=250;
var x=400;
var y=500;
//绘制一个三角形的辅助线
ctx.font="14px 微软雅黑";
ctx.beginPath();
ctx.moveTo(300,300);
//标注坐标
ctx.fillText("(起点x:300,起点y:300)",180,280);
//移动笔,绘制直线
ctx.lineTo(cpx1,cpy1);
//标注坐标
ctx.fillText("(cpx1:"+cpx1+",cpy1:"+cpy1+")",cpx1,cpy1);
//移动笔,绘制直线
ctx.lineTo(x,y);
//标注坐标
ctx.fillText("(x:"+x+",y:"+y+")",x,y);
//闭合路径
ctx.closePath();
ctx.stroke();
//使用贝塞尔二次曲线函数
ctx.beginPath();
ctx.strokeStyle="coral";
ctx.moveTo(300,300);
ctx.quadraticCurveTo(cpx1,cpy1,x,y);
ctx.stroke();
运行效果:
当改变cpx1和cpy1的值,就可以看出它的规律啦。
关于三次贝塞尔曲线参看下面的博客讲解
https://www.cnblogs.com/joyho/articles/5817170.html
通过利用可是化工具可以大致画出图形
//得到画布
var canvas=document.getElementById("mycanvas");
//获取上下文
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(50,250);
ctx.lineTo(50,50);
ctx.lineTo(250,50);
ctx.lineTo(250,250);
ctx.closePath();
ctx.stroke();
ctx.strokeStyle="coral";
ctx.beginPath();
ctx.moveTo(50,250);
ctx.bezierCurveTo(50+100,250-80,50,50,250,50);
ctx.stroke();
文本(基本用法)
ctx.font="16px 微软雅黑";
ctx.fillText=("文本内容",100,100);//100,100为坐标位置
运动
在canvas上,要想让元素运动起来,需要使用定时器setinterval()
然而canvas有个特性,就是上屏的元素,将会立刻被像素化,将得不到这个“对象”的引用,因此不能像操作dom那样操作上屏的元素。也就是说,想要通过改变元素属性使其运动是行不通的。
那要想实现canvas中上屏元素的运动,应该怎么做呢?
其实原理就是:清除→重绘→清除→重绘→……
使它看起来像是在运动
<script type="text/javascript">
//使用DOM方法得到画布
var mycanvas = document.querySelector("canvas");
//使用画布的上下文
var ctx = mycanvas.getContext("2d");
var x = 100;
setInterval(function(){
x++;
//清屏
ctx.clearRect(0,0,600,400);
//重新绘制一个新圆形
ctx.beginPath();
ctx.arc(x,100,50,0,Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = "orange";
ctx.fill();
},20);
</script>
绘制图片
canvas中不可能所有形状都自己画,美工会有素材给我们使用。而且有些复杂的,像图片这样的图像是很难一点一点画出来的。所以canvas是可以绘制图片的。
一个重要的图片绘制函数
drawImage
它有三种形态
需要注意的是
:在使用canvas绘制图片时,一定要在图片加载完成后进行。否则不会有任何效果,甚至有些浏览器还会报错。
var img = new Image(); // 创建img元素
img.onload = function(){
// 执行drawImage语句
}
img.src = 'myImage.png'; // 设置图片源地址
最基础的一种
drawImage(img,x,y)
img就是图片对象,x,y是图片在目标canvas中的起点坐标
<body>
<canvas id="mycanvas" width="800" height="800"></canvas>
</body>
<script type="text/javascript">
//获取画布
var canvas=document.getElementById("mycanvas");
//获取上下文
var ctx=canvas.getContext("2d");
var xiaolu=new Image();
xiaolu.src="../img/lu.jfif";
xiaolu.onload=function(){
ctx.drawImage(xiaolu,0,0);
}
</script>
运行效果:
这样图片便可以按照原本的样子被绘制到canvas画布上了。
但在有些时候,我们不想要图片按照原本的大小绘制怎么办呢?
drawImage()的第二种用法
缩放Scaling
drawImage(img,x,y,width,height)
这个方法增加了2个参数:width
和height
,这两个参数决定了图片是放大还是缩小
<body>
<canvas id="mycanvas" width="800" height="800"></canvas>
</body>
<script type="text/javascript">
//获取画布
var canvas=document.getElementById("mycanvas");
//获取上下文
var ctx=canvas.getContext("2d");
var xiaolu=new Image();
xiaolu.src="../img/lu.jfif";
xiaolu.onload=function(){
ctx.drawImage(xiaolu,0,0,400,200);
}
</script>
这样图片就能被固定到w:400,h:200的大小了
切片
drawImage()的第三个形态,就是切片。
当我们只想要图片的某一部分,并且绘制到canvas上应该怎么做呢?
drawImage(img , sx , sy , sWidth , sHeight , dx , dy , dWidth , dHeight);
看起开比较复杂实际上很容易理解,这里是火狐MDN的一张解释图片。
当我们只想要下图中的小鹿子的时候,我们可以借助图片工具,获取到小鹿在原图中的大小和位置
然后通过代码来进行切片
//获取画布
var canvas=document.getElementById("mycanvas");
//获取上下文
var ctx=canvas.getContext("2d");
var xiaolu=new Image();
xiaolu.src="../img/lu.jpg";
xiaolu.onload=function(){
ctx.drawImage(xiaolu,472,314,161,296,0,0,167,296);
}
运行效果:
Path2D()
所有的路径方法比如moveTo
, rect
, arc
或quadraticCurveTo
等,都可以在Path2D中使用。
Path2D API 添加了 addPath
作为将path
结合起来的方法。当想要从几个元素中来创建对象时,这将会很实用。
事例
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
var rectangle = new Path2D();
rectangle.rect(10, 10, 50, 50);
var circle = new Path2D();
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Math.PI);
ctx.stroke(rectangle);
ctx.fill(circle);
}
}