1. 程式人生 > 實用技巧 >JavaScript圖形例項:遞迴生成樹

JavaScript圖形例項:遞迴生成樹

觀察自然界中樹的分叉,一根主幹生長出兩個側幹,每個側幹又長出兩個側幹,以此類推,便生長出疏密有致的結構。這樣的生長結構,使用遞迴演演算法可以模擬出來。

例如,分叉的側幹按45°的偏轉角度進行生長的遞迴示意圖如圖1所示。

圖1 生成樹的遞迴示意圖

按照樹分叉生長側乾的遞迴思想,編寫如下的HTML程式碼。

<!DOCTYPE html>

<head>

<title>遞迴分形樹(一)</title>

</head>

<body>

<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

var canvas = document.getElementById('myCanvas');

var ctx = canvas.getContext('2d');

var maxdepth =4;

var curdepth = 0;

var alph=Math.PI/4;

function growtree()

{

ctx.translate(300,380);

branch(-Math.PI/2);

}

function branch(angle)

{

curdepth++;

ctx.save();

ctx.strokeStyle = "green";

ctx.lineWidth = 6;

ctx.rotate(angle);

ctx.beginPath();

ctx.moveTo(0,0);

ctx.lineTo(100,0);

ctx.stroke();

ctx.translate(100,0);

ctx.scale(0.75,0.75);

if(curdepth <= maxdepth)

{

branch(alph);

branch(-alph);

}

ctx.restore();

curdepth--;

}

growtree();

</script>

</body>

</html>

在瀏覽器中開啟包含這段HTML程式碼的html檔案,可以看到在瀏覽器視窗中繪製出分叉樹形,如圖2所示。

圖2 遞迴深度maxdepth =4,alph=45°的分叉樹形

若將遞迴深度“maxdepth=4”修改為“maxdepth=12”,則在瀏覽器視窗中繪製出如圖3所示的分叉樹形。

圖3 遞迴深度maxdepth =12,alph=45°的分叉樹形

若將遞迴深度“maxdepth=4”修改為“maxdepth=10”,分叉偏轉角度從45°(alph=Math.PI/4)修改為30°(alph=Math.PI/6),則在瀏覽器視窗中繪製出如,4所示的分叉樹形。

圖4 遞迴深度maxdepth =10,alph=30°的分叉樹形

由圖3和圖4可知,分叉的偏轉角度不同,樹形也會不同。實際上,自然界中樹的側乾的生長不會按同一個角度進行分叉的,若將分叉的偏轉角度取隨機值,編寫如下的HTML程式碼。

<!DOCTYPE html>

<head>

<title>遞迴分形樹(二)</title>

</head>

<body>

<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;"></canvas>

<script type="text/javascript">

var canvas = document.getElementById('myCanvas');

var ctx = canvas.getContext('2d');

var maxdepth =10;

var curdepth = 0;

function growtree()

{

ctx.translate(300,380);

branch(-Math.PI/2);

}

function branch(angle)

{

curdepth++;

ctx.save();

ctx.strokeStyle = "green";

ctx.lineWidth = 6;

ctx.rotate(angle);

ctx.beginPath();

ctx.moveTo(0,0);

ctx.lineTo(100,0);

ctx.stroke();

ctx.translate(100,0);

ctx.scale(0.75,0.75);

if(curdepth <= maxdepth)

{

branch(randomRange(0,Math.PI/4));

branch(randomRange(-Math.PI/4,0));

}

ctx.restore();

curdepth--;

}

function randomRange(min,max)

{

return Math.random()*(max-min) + min;

}

growtree();

</script>

</body>

</html>

在瀏覽器中開啟包含這段HTML程式碼的html檔案,在瀏覽器視窗中可能會繪製出如圖5所示的分叉樹形。

圖5 分叉樹形

不斷地重新整理瀏覽器視窗,可以隨機繪製出不同的分叉樹形,如圖6所示。

圖6 繪製出的不同分叉樹形

如果將遞迴樹形的生成元改為如圖7所示的三分叉,即在上面HTML檔案中的兩行程式碼

branch(randomRange(0,Math.PI/4));

branch(randomRange(-Math.PI/4,0));

中間加上一行程式碼 branch(0); 再將遞迴深度“var maxdepth =10;”修改為“var maxdepth =6;”,則在瀏覽器視窗中可能會繪製出如圖8所示的分叉樹形。

圖7 三分叉生成元

圖8 三分叉遞迴樹形

我們可以在樹梢畫一個紅色小圓,表示樹兒開花了,編寫如下的HTML檔案。

<!DOCTYPE html>

<head>

<title>遞迴分形樹(三)</title>

</head>

<body>

<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;"></canvas>

<script type="text/javascript">

var canvas = document.getElementById('myCanvas');

var ctx = canvas.getContext('2d');

var maxdepth =10;

var curdepth = 0;

function growtree()

{

ctx.translate(300,380);

branch(-Math.PI/2);

}

function branch(angle)

{

curdepth++;

ctx.save();

ctx.strokeStyle = "green";

ctx.lineWidth = 6;

ctx.rotate(angle);

ctx.beginPath();

ctx.moveTo(0,0);

ctx.lineTo(100,0);

ctx.stroke();

ctx.translate(100,0);

ctx.scale(0.75,0.75);

if(curdepth < maxdepth)

{

branch(randomRange(0,Math.PI/4));

branch(randomRange(-Math.PI/4,0));

}

if(curdepth == maxdepth)

{

ctx.fillStyle = '#ff0000';

ctx.beginPath();

ctx.arc(0,0,20,0,Math.PI*2,true);

ctx.fill();

}

ctx.restore();

curdepth--;

}

function randomRange(min,max)

{

return Math.random()*(max-min) + min;

}

growtree();

</script>

</body>

</html>

在瀏覽器中開啟包含這段HTML程式碼的html檔案,在瀏覽器視窗中可能會繪製出如圖9所示的分叉樹形。

圖9 樹梢開紅花的分叉樹形

不斷地重新整理瀏覽器視窗,可以隨機繪製出不同的分叉樹形,如圖10所示。

圖10 繪製出的不同樹梢開紅花的分叉樹形