Canvas 学习
栅格
首先我们要先了解下栅格,因为canvas的坐标和数学的坐标不同,改下我们惯性的坐标,这样才可以设计出正确的图案。
在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。如图1-1所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(X轴)x像素,距离上边(Y轴)y像素(坐标为(x,y))。
canvas的画布栅格和传统数学的Y轴的方向相反,如果没有提前了解,到时我们画出的图案就是垂直翻转的。
.
绘制矩形
< canvas >只支持两种形式的图形绘制:矩形和路径(由一系列点连成的线段)。所有其他类型的图形都是通过一条或者多条路径组合而成的。不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能。
canvas提供了三种方法绘制矩形:
fillRect(x, y, width, height)
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
上面提供的方法之中每一个都包含了相同的参数。x与y指定了在canvas画布上所绘制的矩形的左上角(相对于原点)的坐标。width和height设置矩形的尺寸。
<html>
<head>
<title>Canvas</title>
<script>
//效果图如 图2-4 所示
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillRect(25, 25, 100, 100); //填充的矩形 代码效果 图2-1 所示
ctx.clearRect(45, 45, 60, 60); //1-2句代码效果图2-2所示
ctx.strokeRect(50, 50, 50, 50); //代码效果 图2-3 所示
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px soild #000">
</canvas>
</body>
</html>
绘制路径
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。
stroke()
通过线条来绘制图形轮廓。
fill()
通过填充路径的内容区域生成实心的图形。
生成路径的第一步叫做beginPath()。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置,然后我们就可以重新绘制新的图形。
注意:当前路径为空,即调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo(),无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。
第二步就是调用函数指定绘制路径,本文稍后我们就能看到了。
第三,就是闭合路径closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
注意:当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()函数。但是调用stroke()时不会自动闭合。
绘制一个三角形
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(100,25);
ctx.fill();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px soild #000">
</canvas>
</body>
</html>
效果如下图所示
移动笔触
个非常有用的函数,而这个函数实际上并不能画出任何东西,也是上面所描述的路径列表的一部分,这个函数就是moveTo()。或者你可以想象一下在纸上作业,一支钢笔或者铅笔的笔尖从一个点到另一个点的移动过程。
moveTo(x, y)
将笔触移动到指定的坐标x以及y上。
当canvas初始化或者beginPath()调用后,你通常会使用moveTo()函数设置起点。我们也能够使用moveTo()绘制一些不连续的路径。
线
绘制直线,需要用到的方法lineTo()。
lineTo(x, y)
绘制一条从当前位置到指定x以及y位置的直线。
该方法有两个参数:x以及y ,代表坐标系中直线结束的点。开始点和之前的绘制路径有关,之前路径的结束点就是接下来的开始点,等等。。。开始点也可以通过moveTo()函数改变。
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
//填充三角形
ctx.beginPath();
ctx.moveTo(25,25);
ctx.lineTo(105,25);
ctx.lineTo(25,105);
ctx.fill();
//描边三角形
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();//上面说明过 fill()方法会自动闭合路径,但是我们这里是用stroke()方法。
ctx.stroke();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px solid #000">
</canvas>
</body>
</html>
圆弧
绘制圆弧或者圆,我们使用arc()方法。当然可以使用arcTo(),不过这个的实现并不是那么的可靠,所以我们这里不作介绍。
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1, y1, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
这里详细介绍一下arc方法,该方法有六个参数:x,y为绘制圆弧所在圆上的圆心坐标。radius为半径。startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准。参数anticlockwise为一个布尔值。为true时,是逆时针方向,否则顺时针方向。
注意:arc()函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式:
弧度=(Math.PI/180)*角度。
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.arc(75,75,50,0,Math.PI*2,true); // 绘制
ctx.moveTo(110,75);
ctx.arc(75,75,35,0, Math.PI,false); // 口(顺时针)
ctx.moveTo(65,65);
ctx.arc(60,65,5,0, Math.PI*2,true); // 左眼
ctx.moveTo(95,65);
ctx.arc(90,65,5,0, Math.PI*2,true); // 右眼
ctx.stroke();
ctx.closePath();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px solid #000">
</canvas>
</body>
</html>
下面的例子比上面的要复杂一下,下面绘制了12个不同的角度以及填充的圆弧。
下面两个for循环,生成圆弧的行列(x,y)坐标。每一段圆弧的开始都调用beginPath()。代码中,每个圆弧的参数都是可变的,实际编程中,我们并不需要这样做。
x,y坐标是可变的。半径(radius)和开始角度(startAngle)都是固定的。结束角度(endAngle)在第一列开始时是180度(半圆)然后每列增加90度。最后一列形成一个完整的圆。
clockwise语句作用于第一、三行是顺时针的圆弧,anticlockwise作用于二、四行为逆时针圆弧。if语句让一、二行描边圆弧,下面两行填充路径。
二次贝塞曲线
quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。
如图所示 P1为控制点 ,P0 为起始点,P2为结束点
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(75,25);
ctx.quadraticCurveTo(25,25,25,60);
ctx.stroke();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px solid #000">
</canvas>
</body>
</html>
将控制点坐标改为 (75,75)来改变方向
我们可以通过修改控制点来修改圆弧的方向
以下通过绘制聊天气泡例子来看看 ==quadraticCurveTo(cp1x, cp1y, x, y)==的运用
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
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();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px solid #000">
</canvas>
</body>
</html>
效果图如下
三次贝塞曲线
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
如图所示 P1,P2 为控制点 ,P0为起始点,P3为结束点。
运用三次贝塞曲线来绘制爱心
<html>
<head>
<title>Canvas</title>
<script>
function draw(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillStyle="red"; //设置填充颜色
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();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300px" height="300px" style="border:1px solid #000">
</canvas>
</body>
</html>
效果如下图所示