HTML 5 Canvas 遞歸畫樹

2021-01-11 51CTO

上圖就是用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> 

接下來咱們開始tree.js:

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

代碼很好理解,創建一個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);  }  } 

接下來一點點解釋:

首先,解釋下各個變量的含義。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; 

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); 

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)';  } 

如果是已經畫到了***兩級,即為葉子,那麼就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(); 

這個線段就畫好了,是時候準備下它的分叉的時候了。

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~3中的一個數。然後有多少個分叉,就畫幾條線段,newAngle為原角度調整90度之內,新長度為原長度的0.7~1.0之間。

***畫出主幹,這棵樹就可以開始畫了。

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

大家可能注意到角度為負,不符合傳統觀念。但你要知道,畫布的縱坐標和傳統的坐標軸正好是相反的。

剩下可以發揮的東西還很多,比如大家可以調整各種參數,使樹的顏色、大小變化,或者用這種方法去做些其他的事~

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

原文連結:http://billyellow.com/?p=20

【編輯推薦】

【責任編輯:

張偉

TEL:(010)68476606】

點讚 0

相關焦點

  • 八大瘋狂的 HTML5 Canvas 及 WebGL 動畫效果
    我們挑選了8個由WebGL、HTML5 Canvas和Javascript製作的絕妙效果。每一個都非常簡單但卻發人深省,瘋狂並且極具創意。 黏糊糊的東西 用滑鼠拖拽,然後扔出去,就會粘在網頁邊緣。 蠕蟲 HTML5 Canvas製作的效果,無數條蠕蟲根據灰度組成圖片,你還可以拖拽一張本地圖片到右側。
  • html5 canvas畫布繪製矩形和圓形
    html5為我們提供了非常有特色的標籤,canvas標籤為我們可以實現在網頁中畫畫提供了便利,接下來我們列舉他的常用操作。新建一個html5的文檔,建立一個canvas畫布,設置長寬,這裡需要特別注意,canvas標籤可以在標籤內設置width,height,也能通過css來設置,但是通過css來設置的標籤,當繪製圖形的時候會變形,所以我們建議直接在標籤內設置。
  • 用HTML5把Canvas緩衝區內容輸出到屏幕
    我會儘量簡要說明如何使用HTML5 canvas元素和JavaScript創建簡單的遊戲。本教程將省略一些代碼,但絕非故意。您可以隨時查看我的遊戲演示。  HTML5有許多的神奇功能,諸如:  畫布元素  視頻和音頻的支持  本地存儲  離線Web應用程式  地理定位  …  這篇文章不打算覆蓋所有的HTML5規範,有關HTML5的更多信息,請參考HTML5:http://diveintohtml5.org/.
  • Canvas框架-FabricJS簡介
    demo通過fabric.Canvas獲取到canvas元素,並可以對canvas進行相應的設置,既可以通過獲取已存在的canvas元素,fabric也支持創建canvas元素,同樣也能對其進行相應操作與原生的異同
  • 如何優雅地使用javascript遞歸畫一棵結構樹
    當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。但是作為一個合格的程式設計師,我們也應該知道,遞歸算法相對常用的算法如普通循環等,運行效率較低。因此,應該儘量避免使用遞歸,除非沒有更好的算法或者某種特定情況,遞歸更為適合的時候。在遞歸調用的過程當中系統為每一層的返回點、局部量等開闢了棧來存儲,遞歸次數過多容易造成棧溢出等。
  • scratch3數學之美08-分形之樹
    這節,讓我們來學習繪製分形之樹,看看會是怎樣的精彩!編程描述:使用遞歸算法繪製一顆樹,一顆會長大的樹編程思路:這章的內容可能有點挑戰,使用遞歸算法繪製一顆二叉樹,並進一步完善,需要大家進一步理解開始編程:1. 一顆幼苗一棵樹由樹幹和樹枝組成,我們先繪製最簡單的樹,有一個樹幹和兩個樹枝,就像丫字。
  • 淺絳山水畫樹六法
    古今學畫樹者須知「樹分四枝」,即前、後、左、右枝。但在實踐中,未必非要畫上四枝,只是強調畫樹需要理解樹枝有前後之分。現將古今畫樹方法介紹如下: 1.雙勾法 初學畫樹者必學此法,也是傳統畫樹的基本方法之一。此法適應畫近景樹,雙勾筆順,一般是從左至右,從上至下,也可反之,無定法。 採用此法勾畫枯樹,枝幹要求疏密變化,前後有濃有淡。注意樹幹結構轉折以及粗細對比與穿插。
  • 高斯求和如何用遞歸實現,Python詳解遞歸那些事,看這1篇足夠!
    前段時間,有小夥伴留言,想了解一些有關Python遞歸函數的知識。最近,小編也惡補了一些這方面的內容。說實話,對於遞歸的認識過程,確實能讓我們從中探索出一些很有意思的內容。今天,我們來一探究竟。01什麼是遞歸?
  • Java之遞歸求階層
    各位小夥伴們大家好,在之前的文章中小編介紹了Java之使用遞歸計算1-n之間的和,這次小編要介紹的是,用遞歸求階乘。階乘:所有小於及等於該數的正整數的積n的階乘:n!練習:使用遞歸計算階乘,代碼如下:public class Demo03Recurison {public static void main(String args[]) {int s=sum(5);System.out.println(s);}/*定義一個計算階乘的方法5的階乘:5!
  • 畫樹畫出一個大數–TREE(3)漫談
    然後TREE(3)這個數,就可以用一種畫樹的遊戲來導出,畫的時候,我們會給每個節點,俗稱葉子的東西,畫上某種顏色。而對線段,俗稱樹枝,我們不關心它的顏色。而TREE(3),意思就是用三種顏色來畫這顆樹。我們還有一些畫樹的規則。這個畫樹的遊戲只有兩個規則。
  • matplotlib如何實現圖形繪製在tkinter的Canvas中?
    下面就是最重要的tkinter和matplotlib集成部分,matplotlib提供FigureCanvasTkAgg對象,只需三行代碼,實現圖形繪製在tkinter的Canvas中:canvas_l = FigureCanvasTkAgg(figure_l, frame_l)# 用draw代替canvas_l.draw()canvas_l.get_tk_widget
  • ——讓遞歸算法來幫你,只需「3步」
    今天我們來介紹一種很常見的算法——遞歸。遞歸函數什麼是遞歸?簡單的說,遞歸就是通過不斷調用自己,來完成不斷循環的一個過程。可能概念有些拗口,我們編寫一個遞歸函數來說明。斐波那契數列大家都知道,它從第三項開始,每一項都是前面兩項的和:1,1,2,3,5,8,13,21......
  • 數據結構之樹和二叉樹
    把它叫做「樹」是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點:1. 每個節點都只有有限個子節點或無子節點;2. 沒有父節點的節點稱為根節點;3. 每一個非根節點有且只有一個父節點;4. 除了根節點外,每個子節點可以分為多個不相交的子樹;5. 樹裡面沒有環路(cycle)。
  • Adobe CS5可將Flash動畫轉為HTML5 Canvas
    蘋果和Adobe之間因為對Flash的支持問題而鬧得很僵,賈伯斯曾直言HTML5將取代Flash,對於HTML5,Adobe也沒有完全忽視。隨著Adobe下一代產品CS5的臨近,一個新的工具浮出水面,利用該工具,Flash動畫可以轉換成HTML 5 Canvas。
  • HTML5+CSS+JS時間
    page.html<!DOCTYPE html><html><head><metahttp-equiv="Content-Type"content="text/html" ; charset="UTF-8"><title>登陸頁面</title><metaname="description"content="這是一個以日誌為主的博客,提供學習所需要的知識學習
  • 「通俗易懂的文字」+「經典案例」讓你順利入門「遞歸算法」
    遞歸是非常常見的一種算法,非常經典,可以解決非常多的問題。但我估計雖然大部分人知道遞歸,也能看得懂遞歸,但在實際運用中,很容易被遞歸給搞暈(數據,變量,函數等來回的出棧入棧)。今天寫篇文章分享下,或許,能夠給你帶來一些幫助。
  • 二叉搜索樹的構建
    1 二叉搜索樹BST二叉搜索樹(Binary Search Tree,簡寫BST),又稱為二叉排序樹或二叉查找樹。其定義為:對於樹中的每個節點,其左子樹的所有節點值都小於該節點的值,其右子樹的所有節點值都大於該節點的值。二叉搜索樹的任意一個子樹也是二叉搜索樹。
  • 基於HTML5 的 WebGL 3D 版俄羅斯方塊
    2, 3, 4,    4, 2, 5,    5, 0, 10,    10, 5, 6,    6, 7, 8,    8, 6, 9,    9, 10, 6  ]});與 2D 一樣,我們創建一個 ht.Node() 的基礎圖元,類型設置為我們新註冊的3D模型名稱:dataModel = new ht.DataModel();g3d = new
  • 如何用 JavaScript+Canvas 開發一款超級燒腦小遊戲?
    Canvas 繪圖時,會從兩個物理像素的中間位置開始繪製並向兩邊擴散 0.5 個物理像素。可參考微信官方縮放策略調整另外,需要注意的是,這裡的 canvas 是由 weapp-adapter 預先調用 wx.createCanvas() 創建一個上屏 Canvas,並暴露為一個全局變量 canvas。如何繪製任意多邊形圖形?