HTML 5 Canvas 递归画树

开发 前端
上图就是用html5随机生成的大树 : ) 但是你应该没想到40+行代码就可以搞定了吧~接下来就跟大家说说这棵大树是如何实现的。同样必须要有html容器。新建Index.html,代码如下.....

QQ20120923 4QQ20120923 5

上图就是用html5随机生成的大树 : ) 但是你应该没想到40+行代码就可以搞定了吧~接下来就跟大家说说这棵大树是如何实现的。

同样必须要有html容器。新建Index.html,代码如下:

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title>canvas tree</title> 
</head> 
<body> 
<script type="text/javascript" src="tree.js"></script> 
</body> 
</html> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

接下来咱们开始tree.js:

var canvas = document.createElement("canvas");  
var ctx = canvas.getContext("2d");  
canvas.width = 640;  
canvas.height = 480;  
document.body.appendChild(canvas); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

代码很好理解,创建一个canvas画布,然后选择为2d画布,设置长宽,***将这个画布添加到body标签下。

这个脚本最重要的函数在下面,大树就是递归调用这个函数实现的,调用一次画一条线段:

var drawTree = function (ctx, startX, startY, length, angle, depth, branchWidth){  
var rand = Math.random,  
newLength, newAngle, newDepth, maxBranch = 3,  
endX, endY, maxAngle = 2 * Math.PI / 4,  
subBraches;  
ctx.beginPath();  
ctx.moveTo(startX, startY);  
endX = startX + length * Math.cos(angle);  
endY = startY + length * Math.sin(angle);  
ctx.lineCap = 'round';  
ctx.lineWidth = branchWidth;  
ctx.lineTo(endX, endY);  
if (depth <= 2){  
ctx.strokeStyle = 'rgb(0,' + (((rand() * 64) + 128) >> 0) + ',0)';  
} else {  
ctx.strokeStyle = 'rgb(' + (((rand() * 64) + 64) >> 0) + ',50,25)';  
}  
ctx.stroke();  
newDepth = depth - 1;  
if (!newDepth)  
return;  
subBranches = (rand() * (maxBranch - 1)) + 1;  
branchWidth *= 0.7;  
for (var i = 0; i < subBranches; i++){  
newAngle = angle + rand() * maxAngle - maxAngle * 0.5;  
newLength = length * (0.7 + rand() * 0.3);  
drawTree(ctx, endX, endY, newLength, newAngle, newDepth, branchWidth);  
}  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

接下来一点点解释:

首先,解释下各个变量的含义。ctx就是前面我们的2d画布;startX是线段开始的横坐标,同理startY是纵坐标;length是线段长度;angle是角度;depth是深度,叶子深度为1,树干为12(可自己设定);branchWidth就线段的粗细。有了这些信息,其实就描述了一个线段,通过这些信息我们才能画一个线段。

接下来又很可耻地一大段定义:

var rand = Math.random,  
newLength, newAngle, newDepth, maxBranch = 3,  
endX, endY, maxAngle = 2 * Math.PI / 4,  
subBraches; 
  • 1.
  • 2.
  • 3.
  • 4.

rand其实就是随机一个0~1之间的实数,顾名思义,接下来这些new的就是下一节线段的各种参数。maxBranch就是最多有3个分叉,***的角度 PI/2 即为,下一级调整角度在90%范围内。subBranches就是分叉的个数。

好了,重要可以画了:

ctx.beginPath();  
ctx.moveTo(startX, startY);  
endX = startX + length * Math.cos(angle);  
endY = startY + length * Math.sin(angle);  
ctx.lineCap = 'round';  
ctx.lineWidth = branchWidth;  
ctx.lineTo(endX, endY); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

beginPath()表示告诉浏览器“我要开始画了!”,把之前的记录放弃了,这点有点像ps。moveTo()把光标移动到(startX, startY),再计算终点坐标,endX,endY,有点像高中学的参数方程。然后告诉浏览器,lineCap要round,线段的两头要是圆形的。有多粗呢?等于branchWidth。线段一直画到(endX, endY)。

if (depth <= 2){  
ctx.strokeStyle = 'rgb(0,' + (((rand() * 64) + 128) >> 0) + ',0)';  
} else {  
ctx.strokeStyle = 'rgb(' + (((rand() * 64) + 64) >> 0) + ',50,25)';  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

如果是已经画到了***两级,即为叶子,那么就rgb就为(0, 128~192, 0)(rgb代表颜色,分别为红绿蓝,red green blue)。还没的话,就在(64~128, 50 ,25)中取。大家可能发现了,rgb必须为整数,但是rand()只能rand实数。大家其实也注意到了有个” >>  0″,js当中表示位运算,整体向右移动n位,0就是移动0位。其实它的作用和Math.floor()一样,但是速度更快。

动手画!

ctx.stroke(); 
  • 1.

这个线段就画好了,是时候准备下它的分叉的时候了。

newDepth = depth - 1;  
if (!newDepth)  
return; 
  • 1.
  • 2.
  • 3.

如果这个线段是***一级,就没有分叉了,也是一个递归的终止条件。

subBranches = (rand() * (maxBranch - 1)) + 1;  
branchWidth *= 0.7;  
for (var i = 0; i < subBranches; i++){  
newAngle = angle + rand() * maxAngle - maxAngle * 0.5;  
newLength = length * (0.7 + rand() * 0.3);  
drawTree(ctx, endX, endY, newLength, newAngle, newDepth, branchWidth);  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

分叉数是1~3中的一个数。然后有多少个分叉,就画几条线段,newAngle为原角度调整90度之内,新长度为原长度的0.7~1.0之间。

***画出主干,这棵树就可以开始画了。

drawTree(ctx, 320, 470, 60, -Math.PI / 2, 12, 12); 
  • 1.

大家可能注意到角度为负,不符合传统观念。但你要知道,画布的纵坐标和传统的坐标轴正好是相反的。

剩下可以发挥的东西还很多,比如大家可以调整各种参数,使树的颜色、大小变化,或者用这种方法去做些其他的事~

打完收工~附上文件:tree.zip

原文链接:http://billyellow.com/?p=20

责任编辑:张伟 来源: Billyellow's
相关推荐

2012-06-04 10:16:18

HTML5

2012-06-12 09:53:14

HTML5

2011-11-09 10:05:26

HTML 5

2012-05-09 09:41:58

HTML5

2011-11-25 14:20:57

HTML 5

2012-02-22 15:41:50

HTML 5

2012-02-24 15:28:36

ibmdw

2012-05-29 09:57:10

HTML5

2017-07-05 16:22:09

HTML5canvas动态

2022-03-23 14:57:48

canvasjavascript运动小球

2012-08-30 10:18:09

HTML5CanvasHTML5实例

2015-10-08 08:48:44

HTML5canvas动画

2011-07-21 15:34:36

iPhone HTML5 Canvas

2011-07-18 13:35:14

HTML 5

2012-05-09 12:18:14

HTML5Canvas

2016-01-20 10:11:56

华丽CanvasHTML5

2012-04-18 15:36:33

HTML5Canvas交互式

2012-05-31 09:54:13

HTML5

2013-03-06 16:14:16

UCHTML5游戏引擎

2015-10-08 08:48:37

HTML53D网络拓扑树
点赞
收藏

51CTO技术栈公众号