canvas JavaScript API学习(二)

接下来的内容是我对canvas绘图进一步学习心得,这次会介绍更多API方法的使用,来提高我们绘图的能力,创建更多丰富的图形,如果你有一点点图形学基础,那将对你的学习有很大帮助。

写在前面
看过前面的那篇文章,你就大概了解使用JavaScript的canvas api来绘图是怎么一回事。你需要得到一个渲染环境(rendering context),然后在指定位置通过api画出你要的图形。这里涉及到canvas的“网格”或叫“坐标系”。
 

Canvas_default_grid

Canvas_default_grid


如图中所示的,canvas坐标系的原点就是canvas左上角坐标(0,0)的位置,所画图形的位置就是相对这个原点水平偏移x个像素,垂直偏移y个像素的位置。

 

canvas绘图:矩形
canvas只支持一种图形的绘图方法,那就是矩形,其他的图形都是通过路径(path)构造出来的,因此,在以后的绘图过程中,你可能更多的要使用它来构建复杂的图形,这就是你需要一点图形学的基础的原因。

与矩形绘图相关的函数有:

fillRect(x,y,width,height) : 填充的矩形
strokeRect(x,y,width,height) : 矩形框
clearRect(x,y,width,height) : 清除指定区域使之透明,该区域是矩形区域

上一篇文章中我们演示了fillRect的用法,也提到了clearRect,具体的内容请查看之前的文章或查看demo:html5_canvas_basic html5_canvas_rebound

strokeRect函数的用法与其他两个一样,直接上代码。

<!DOCTYPE html>
<html>
<head>
<meta  charset="utf-8" />
<title>Canvas javascript api demo</title>
<style type="text/css">
canvas {
	border:1px #000 solid;
}
</style>
 
</head>
<body>
<h1>this is a canvas api test page!</h1>
<canvas id="canvas" width="300" height="300">this browser does not support canvas...</canvas>
<a href="http://blog.wanz.im/2010/04/17/canvas_javascript_api_learning_two/">返回文章</a>
<script type="text/javascript">
var $=function(id){
	return document.getElementById(id);
}
window.onload=function(){
	var ctx=$('canvas').getContext('2d');
 	ctx.strokeStyle='rgb(255,0,0)';
	ctx.strokeRect (10, 10, 50, 50); 
}
</script>
</body>
</html>

代码很简单,strokeStyle用法同fillStyle,用来设置边框颜色,同样支持rgb或rgba值,十六进制值(如:#F00)和hsl或hsla值。但是你可能注意到了,我们设定的矩形框宽度和高度都是50px,但是实际绘图出来的是52px,边框宽度为2px,如下图的测量结果,这显然不是我们想看到的。不知道为什么要这样设计,希望有知道的朋友可以告诉我一下,先谢过了。
 

strokeRect_border

strokeRect_border_extra_width

 

canvas绘图:使用路径(path)绘图——线段
正如前面所说的,只有矩形是可以直接使用api函数绘出的,其他的图形都需要通过路径来构造。要使用路径来绘图,我们需要先了解下面几个函数:

beginPath()
closePath()
stroke()
fill()

beginPath函数是为画路径而准备的,是一个初始化的过程,在调用函数后就可以开始画路径了,所有的用来构成一个图形的路径将被保存起来,每调用一次这个函数,之前保存的路径就都被重置清空。

closePath函数用来得到将被画出的路径,并且可以用来闭合路径。

stroke函数是可选的,该方法可以配合closePath函数,它会尝试将路径闭合,在当前位置到起始位置用一条直线连接起来。如果路劲已经闭合或者当前“画布”上只有一个点,那么这个函数将不起任何作用。

fill函数使用fillStyle的颜色来填充图形,使用这个函数可以不需要调用closePath函数而直接闭合路径。

让我们看看下面的代码,查看demo

<!DOCTYPE html>
<html>
<head>
<meta  charset="utf-8" />
<title>Canvas javascript api demo</title>
<style type="text/css">
canvas {
	border:1px #000 solid;
}
</style>
</head>
<body>
<h1>this is a canvas api test page!</h1>
<canvas id="canvas" width="300" height="300">this browser does not support canvas...</canvas>
<a href="http://blog.wanz.im/2010/04/17/canvas_javascript_api_learning_two/">返回文章</a>
<script type="text/javascript">
var $=function(id){
	return document.getElementById(id);
}
window.onload=function(){
	var ctx=$('canvas').getContext('2d');
	ctx.beginPath();
	ctx.moveTo(75,50);
	ctx.lineTo(100,75);
	ctx.lineTo(100,25);
	ctx.closePath();//使用closePath配合stroke闭合路径
	ctx.stroke();
	ctx.beginPath();
	ctx.moveTo(140,30);
	ctx.lineTo(140,75);
	ctx.lineTo(160,25);
	ctx.stroke();
	ctx.beginPath();
	ctx.moveTo(100,100);
	ctx.lineTo(200,100);
	ctx.lineTo(100,200);
	ctx.fillStyle='#f00';
	ctx.fill();
}
</script>
</body>
</html>

代码中除了前面介绍的四个函数外,还提到moveTo跟lineTo两个函数。这两个函数都只带两个参数,分别为canvas上某点的坐标值。moveTo什么都不做,如果把canvas解释成一块画布,那么它的作用就是将画笔移动到画布上的某个位置,在canvas初始化时或者beginPath被调用时,画笔的默认位置是canvas坐标系的原点。lineTo函数用来画一条线段,该函数的两个参数指定了线段的终点坐标,起始坐标为moveTo指定的位置或者上一个路径的终点。

canvas绘图:使用路径(path)绘图——圆弧
我们使用arc函数来画圆弧或一个完整的圆,这个函数有6个参数,函数原型如下:

arc(x, y, radius, startAngle, endAngle, anticlockwise)

参数x和y是圆心坐标值,radius为圆半径;startAngle和endAngle为圆弧起始位置弧度和和终点位置弧度,该值为弧度而不是角度值,角度转弧度的公式为:var radians = (Math.PI/180)*degrees;anticlockwise是一个布尔值,当它为true时,圆弧绘制方向为逆时针方向,false是为顺时针方向。

圆或圆弧的绘制相对前面提到的那些图形稍微复杂了点。查看demo

<!DOCTYPE html>
<html>
<head>
<meta  charset="utf-8" />
<title>Canvas javascript api demo</title>
<style type="text/css">
canvas {
	border:1px #000 solid;
}
</style>
 
</head>
<body>
<h1>this is a canvas api test page!</h1>
<canvas id="canvas" width="300" height="300">this browser does not support canvas...</canvas>
<a href="http://blog.wanz.im/2010/04/17/canvas_javascript_api_learning_two/">返回文章</a>
<script type="text/javascript">
var $=function(id){
	return document.getElementById(id);
}
window.onload=function(){
	var ctx=$('canvas').getContext('2d');
	ctx.beginPath();  
	var x= 50;               // x coordinate  
	var y= 50;               // y coordinate  
	var radius= 20;                    // Arc radius  
	var startAngle= 0;                     // Starting point on circle  
	var endAngle=(Math.PI/180)*120;
	var anticlockwise= true; // anticlockwise       
	ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
	ctx.stroke();
 
	ctx.beginPath();  
	var x= 150;               // x coordinate  
	var y= 50;               // y coordinate  
	var radius= 20;                    // Arc radius  
	var startAngle= 0;                     // Starting point on circle  
	var endAngle=(Math.PI/180)*120;
	var anticlockwise= false; // clockwise    
	ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
	ctx.stroke();
 
	ctx.beginPath();  
	var x= 150;               // x coordinate  
	var y= 125;               // y coordinate  
	var radius= 50;                    // Arc radius  
	var startAngle= 0;                     // Starting point on circle  
	var endAngle=(Math.PI/180)*360;
	var anticlockwise= false; // clockwise or anticlockwise       
	ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
	ctx.fillStyle='rgba(255,0,0,0.5)';
	ctx.fill();
 
	ctx.beginPath();  
	var x= 125;               // x coordinate  
	var y= 150;               // y coordinate  
	var radius= 50;                    // Arc radius  
	var startAngle= 0;                     // Starting point on circle  
	var endAngle=(Math.PI/180)*360;
	var anticlockwise= false; // clockwise or anticlockwise       
	ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
	ctx.fillStyle='rgba(0,255,0,0.5)';
	ctx.fill();
 
	ctx.beginPath();  
	var x= 175;               // x coordinate  
	var y= 150;               // y coordinate  
	var radius= 50;                    // Arc radius  
	var startAngle= 0;                     // Starting point on circle  
	var endAngle=(Math.PI/180)*360;
	var anticlockwise= false; // clockwise or anticlockwise       
	ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);  
	ctx.fillStyle='rgba(0,0,255,0.5)';
	ctx.fill();
}
</script>
</body>
</html>

canvas绘图:使用路径(path)绘图——贝塞尔二次和三次曲线
通过使用这两种曲线绘制的api,你可以画出更复杂的图形。它们的区别在于二次曲线只有一个控制点,而三次曲线有两个。你可以在wiki上查看更多关于贝塞尔二次和三次曲线的资料。它们的函数原型如下:

quadraticCurveTo(cp1x, cp1y, x, y) //二次曲线,在Firefox 1.5下有bug
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)//三次曲线

Canvas_curves

二次曲线和三次曲线


红色为控制点,蓝色为起点跟终点

 

两个函数的x和y参数都是终点坐标值,cp1x和cp1y是第一个控制点的坐标值,cp2x和cp2y是第二个控制点的坐标值,起点坐标可以用moveTo来确定。

虽说这两个函数能构造出复杂的图形,但是使用二次和三次贝塞尔曲线是有很大难度的,因为你根本无法想象一个复杂的图形,它所对应的曲线参数是多少,无法直观的得到它们。要做到这点,你需要有足够的时间和耐心慢慢尝试,或者借助图形学工具来得到这些参数。接下来我来演示一个比较复杂的demo。查看demo
 

canvas_poker

canvas_poker

上面的这个demo比较复杂,原因在于前面说的,你必须很清楚的知道贝塞尔曲线的各个参数,这里我借助了我上大学时候图形学的课程设计的帮助得到这些必要的参数的,希望它也能帮到你。这个工具文件只有28k,请使用右键另存为下载:贝塞尔二次和三次曲线生成工具
先看看工具界面,各个节点都可以调整到你所希望的样子,并有对应的坐标值。
 

bezierCurvetool

bezierCurvetool

 

Firefox 1.5 quadraticCurveTo() bug
这个bug出现在Firefox1.5中,在调用quadraticCurveTo函数的时候,得到的却是bezierCurveTo函数一样的结果。这是核心中将二次的控制点重复使用一次导致的,正如前面所说的,二次只有一个控制点,这里却变成了两个。解决的办法是将原本使用二次曲线函数的方式用三次曲线函数来表示该曲线。

原文地址: canvas JavaScript API学习(二)

XeonWell Studio