Fraktallar, matematiksel denklemlerin tekrarlanmasıyla oluşturulan sonsuz desenlerdir. Sadece Vanilla JS ve HTML5 Canvas API kullanarak en iyi bilinen Fraktallardan birini çizeceğiz.Fraktallar, matematiksel denklemlerin tekrarlanmasıyla oluşturulan sonsuz desenlerdir. Sadece Vanilla JS ve HTML5 Canvas API kullanarak en iyi bilinen Fraktallardan birini çizeceğiz.

JavaScript ve HTML5 ile Fraktal Ağaç Kodlama

2025/10/11 03:00

\ 分形,那些神秘的圖形,它們無處不在,但未經訓練的眼睛卻看不見。今天我們將使用純 JavaScript 和 HTML5 Canvas API 繪製一個最著名的分形。讓我們開始編碼吧!

你將學到什麼

  • 什麼是分形樹?
  • 用純 JavaScript 編寫分形樹
  • 超越分形樹

什麼是分形樹?

要定義分形樹,首先,我們當然必須知道分形的定義。

分形是通過重複數學方程式創建的無盡圖案,在任何尺度、任何縮放級別上,看起來大致相同。換句話說,一個幾何物體,其基本結構,無論粗糙或碎片化,都在不同尺度上重複自身。

所以如果我們分割一個分形,我們會看到整體的縮小版本。

Benoit Mandelbrot,1975年創造"分形"一詞的人,說:

\

\ 很清楚,對吧?

這裡有一些例子:

Animated Von Koch Curve

\ Animated Sierpinski Carpet

現在,什麼是分形樹?

想像一個分支,然後從中長出分支,然後每個分支又長出兩個分支,如此類推...這就是分形樹的樣子。

它的形式來源於謝爾賓斯基三角形(或謝爾賓斯基墊)。

如你所見,當改變分支之間的角度時,一個會變成另一個:

From Sierpinski Triangle to Fractal

今天,我們最終會得到一個類似於該 GIF 最終形態的圖形。

用純 JavaScript 編寫分形樹

首先,這是最終成品(你可以在過程中調整它):

Final Fractal Tree

現在讓我們一步步繪製它。

首先,我們用一個合理尺寸的畫布和一個包含所有 JS 代碼的腳本標籤初始化我們的 index.html 文件。

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script></script>   </body> </html> 

然後,我們開始編寫 JavaScript。

我們通過 myCanvas 變量訪問畫布元素,並使用 ctx(上下文)變量創建 2D 渲染上下文,從而在 JS 中初始化我們的畫布元素。

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script>       var myCanvas = document.getElementById("my_canvas");       var ctx = myCanvas.getContext("2d");     </script>   </body> </html> 

是的,getContext 方法添加了允許你繪圖的屬性和方法,在這種情況下是 2D 繪圖。

現在是時候思考了。我們如何定義繪製分形樹的算法呢?嗯... 🤔

讓我們看看,我們知道分支會越來越小。而且每個分支末端都會長出兩個分支,一個向左,一個向右。

換句話說,當一個分支足夠長時,在它上面附加兩個更小的分支。重複這個過程。

這聽起來像是我們應該在某處使用遞迴語句,不是嗎?

回到代碼,我們現在定義我們的函數 fractalTree,它應該至少接受四個參數:分支起始的 X 和 Y 坐標,分支的長度,以及它的角度。

在我們的函數內部,我們用 beginPath() 方法開始繪圖,然後用 save() 方法保存畫布的狀態。

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script>       var myCanvas = document.getElementById("my_canvas");       var ctx = myCanvas.getContext("2d");       function draw(startX, startY, len, angle) {           ctx.beginPath();           ctx.save();       }     </script>   </body> </html> 

beginPath 方法通常在你開始一個具有固定樣式的新線條或圖形時使用,比如整條線具有相同的顏色,或相同的寬度。save 方法通過將當前狀態推入堆棧來保存畫布的整個狀態。

現在我們將通過繪製一條線(分支),旋轉畫布,繪製下一個分支,等等來繪製我們的分形樹。它是這樣的(我將在代碼示例下面解釋每個方法):

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script>       var myCanvas = document.getElementById("my_canvas");       var ctx = myCanvas.getContext("2d");       function draw(startX, startY, len, angle) {           ctx.beginPath();           ctx.save();            ctx.translate(startX, startY);           ctx.rotate(angle * Math.PI/180);           ctx.moveTo(0, 0);           ctx.lineTo(0, -len);           ctx.stroke();            if(len < 10) {               ctx.restore();               return;           }            draw(0, -len, len*0.8, -15);           draw(0, -len, len*0.8, +15);            ctx.restore();       }       draw(400, 600, 120, 0)     </script>   </body> </html> 

所以我們首先添加三個方法,translate、rotate 和 moveTo,它們"移動"畫布、它的原點和我們的"鉛筆",這樣我們就可以以我們想要的角度繪製分支。就像我們在繪製一個分支,然後居中這個分支(通過移動整個畫布),然後從我們前一個分支的末端繪製一個新分支。

if 語句之前的最後兩個方法是 lineTo 和 stroke;第一個向當前路徑添加一條直線,第二個則渲染它。你可以這樣想:lineTo 下達命令,stroke 執行它。

現在我們有一個 if 語句,告訴何時停止遞迴,何時停止繪圖。restore 方法,正如 MDN 文檔中所述,"通過彈出繪圖狀態堆棧中的頂部條目來恢復最近保存的畫布狀態"。

在 if 語句之後,我們有遞迴調用和另一個對 restore 方法的調用。然後是對我們剛剛完成的函數的調用。

現在在你的瀏覽器中運行代碼。你最終會看到一棵分形樹!

Fractal Tree First Iteration

很棒,對吧?現在讓我們讓它變得更好。

我們將向我們的 draw 函數添加一個新參數,branchWidth,使我們的分形樹更加逼真。

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script>       var myCanvas = document.getElementById("my_canvas");       var ctx = myCanvas.getContext("2d");       function draw(startX, startY, len, angle, branchWidth) {           ctx.lineWidth = branchWidth;            ctx.beginPath();           ctx.save();            ctx.translate(startX, startY);           ctx.rotate(angle * Math.PI/180);           ctx.moveTo(0, 0);           ctx.lineTo(0, -len);           ctx.stroke();            if(len < 10) {               ctx.restore();               return;           }            draw(0, -len, len*0.8, angle-15, branchWidth*0.8);           draw(0, -len, len*0.8, angle+15, branchWidth*0.8);            ctx.restore();       }       draw(400, 600, 120, 0, 10)     </script>   </body> </html> 

所以在每次迭代中,我們都使每個分支變得更細。我還更改了遞迴調用中的角度參數,使樹更"開放"。

現在,讓我們添加一些顏色!還有陰影,為什麼不呢。

<!doctype html> <html lang="en">   <head>     <meta charset="UTF-8" />   </head>   <body>     <canvas id="my_canvas" width="1000" height="800"></canvas>     <script>       var myCanvas = document.getElementById("my_canvas");       var ctx = myCanvas.getContext("2d");       function draw(startX, startY, len, angle, branchWidth) {           ctx.lineWidth = branchWidth;            ctx.beginPath();           ctx.save();            ctx.strokeStyle = "green";           ctx.fillStyle = "green";            ctx.translate(startX, startY);           ctx.rotate(angle * Math.PI/180);           ctx.moveTo(0, 0);           ctx.lineTo(0, -len);           ctx.stroke();            ctx.shadowBlur = 15;           ctx.shadowColor = "rgba(0,0,0,0.8)";            if(len < 10) {               ctx.restore();               return;           }            draw(0, -len, len*0.8, angle-15, branchWidth*0.8);           draw(0, -len, len*0.8, angle+15, branchWidth*0.8);            ctx.restore();       }       draw(400, 600, 120, 0, 10)     </script>   </body> </html> 

兩種顏色方法都是不言自明的(strokeStyle 和 fillStyle)。還有陰影相關的,shadowBlur 和 shadowColor。

就是這樣!保存文件並用瀏覽器打開它,查看最終成品。

現在我鼓勵你玩轉代碼!更改 shadowColor、fillStyle,製作更短或更長的分形樹,更改角度,或嘗試添加葉子,這應該很有挑戰性 😉

超越分形樹

正如我在這篇文章開頭所展示的,有不同的分形。用 Canvas API 製作所有這些可能不容易,但應該是可能的。我用 C 程式語言製作了其中一些,我也玩過 p5.js。

p5.js 是一個由藝術家為藝術家製作的開源

Sorumluluk Reddi: Bu sitede yeniden yayınlanan makaleler, halka açık platformlardan alınmıştır ve yalnızca bilgilendirme amaçlıdır. MEXC'nin görüşlerini yansıtmayabilir. Tüm hakları telif sahiplerine aittir. Herhangi bir içeriğin üçüncü taraf haklarını ihlal ettiğini düşünüyorsanız, kaldırılması için lütfen [email protected] ile iletişime geçin. MEXC, içeriğin doğruluğu, eksiksizliği veya güncelliği konusunda hiçbir garanti vermez ve sağlanan bilgilere dayalı olarak alınan herhangi bir eylemden sorumlu değildir. İçerik, finansal, yasal veya diğer profesyonel tavsiye niteliğinde değildir ve MEXC tarafından bir tavsiye veya onay olarak değerlendirilmemelidir.