Фракталы - это бесконечные узоры, созданные повторяющимися математическими уравнениями. Мы нарисуем один из самых известных фракталов, используя только Vanilla JS и HTML5 Canvas API.Фракталы - это бесконечные узоры, созданные повторяющимися математическими уравнениями. Мы нарисуем один из самых известных фракталов, используя только Vanilla JS и HTML5 Canvas API.

Программирование фрактального дерева с помощью JavaScript и HTML5

2025/10/11 03:00

\ Фракталы, эти загадочные фигуры, которые повсюду, но не видны неподготовленному глазу. Сегодня мы нарисуем один из самых известных фракталов, используя только Vanilla JS и HTML5 Canvas API. Давайте программировать!

Что вы узнаете

  • Что такое фрактальное дерево?
  • Написание фрактального дерева на Vanilla JS
  • За пределами фрактального дерева

Что такое фрактальное дерево?

Чтобы определить фрактальное дерево, сначала мы должны знать определение фрактала, конечно.

Фракталы — это бесконечные узоры, созданные повторяющимися математическими уравнениями, которые в любом масштабе, на любом уровне увеличения выглядят примерно одинаково. Другими словами, геометрический объект, основная структура которого, грубая или фрагментированная, повторяется в разных масштабах.

Так что если мы разделим фрактал, мы увидим уменьшенную копию целого.

Бенуа Мандельброт, который придумал термин "фрактал" в 1975 году, сказал:

\

\ Довольно ясно, правда?

Вот несколько примеров:

Animated Von Koch Curve

\ Animated Sierpinski Carpet

Теперь, что такое фрактальное дерево?

Представьте ветвь, и ветви, выходящие из нее, а затем две ветви, выходящие из каждой ветви, и так далее... вот как выглядит фрактальное дерево.

Его форма происходит от треугольника Серпинского (или салфетки Серпинского).

Как видите, одно становится другим при изменении угла между ветвями:

From Sierpinski Triangle to Fractal

Сегодня мы закончим с фигурой, похожей на конечную форму этого GIF.

Написание фрактального дерева на Vanilla JS

Прежде всего, вот конечный продукт (вы можете настраивать его по ходу дела):

Final Fractal Tree

Теперь давайте нарисуем это, шаг за шагом.

Прежде всего, мы инициализируем наш файл index.html с холстом любых разумных размеров и тегом script, где будет весь наш JS-код.

<!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.

Мы инициализируем наш элемент canvas в JS, получая к нему доступ через переменную myCanvas и создавая 2D-контекст рендеринга с переменной ctx (context).

<!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.

И это все! Сохраните файл и откройте его в браузере, чтобы увидеть конечный продукт.

Теперь я призываю вас поиграть с кодом

Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу service@support.mexc.com для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.

Вам также может быть интересно

Gemini выходит на рынки прогнозов после 5-летнего ожидания, бросая вызов Kalshi и Polymarket

Gemini выходит на рынки прогнозов после 5-летнего ожидания, бросая вызов Kalshi и Polymarket

После пяти лет ожидания лицензии Комиссии по торговле товарными фьючерсами (CFTC), Gemini теперь может напрямую конкурировать с устоявшимися соперниками Kalshi и Polymarket. Gemini впервые подала заявку на лицензию Designated Contract Market (DCM) в марте 2020 года, хотя регулятор одобрил ее только в декабре 2025 года. Руководство Gemini представило это одобрение как преимущество более благоприятной политической среды. "Мы благодарим президента Трампа за прекращение войны администрации Байдена против криптовалют", - заявил генеральный директор Тайлер Уинклвосс в резком заявлении. "Невероятно освежающе иметь президента и финансового регулятора, которые поддерживают криптовалюты, инновации и Америку". Акции Gemini (NASDAQ: GEMI), публично торгуемые с сентября 2025 года, выросли на 13,7% после закрытия торгов, поскольку инвесторы оценивали влияние хорошо капитализированной биржи, входящей в ключевой криптосектор. CFTC не комментировала политические факторы, связанные с одобрением. Что известно о рынках прогнозов Gemini Новая лицензия позволяет Gemini Titan – полностью принадлежащей дочерней компании Gemini Space Station – предлагать рынки прогнозов клиентам из США. Изначально компания планирует запустить простые контракты на события типа "да-нет", напрямую конкурируя с флагманскими продуктами Kalshi и Polymarket. Новые торговые контракты будут доступны "скоро" на веб-интерфейсе Gemini, с последующей мобильной торговлей. Клиенты криптовалютной биржи из США смогут торговать ими со своих счетов в USD. Gemini сигнализировала, что рынки прогнозов – это лишь первый шаг в более широкой стратегии деривативов. Фирма обозначила планы по расширению в криптовалютные фьючерсы, опционы и бессрочные контракты. "Рынки прогнозов имеют потенциал быть такими же большими или даже больше, чем традиционные рынки капитала", - сказал Кэмерон Уинклвосс, президент Gemini. Что это значит для рынков прогнозов США Одобрение Gemini немедленно меняет ландшафт рынка прогнозов США со стабильной сцены двух игроков — Kalshi как единственной полностью регулируемой CFTC площадки и Polymarket с сильным ростом в блокчейне — на трехстороннее соревнование. С присутствием на публичном рынке, сильной капитальной базой и массовым распространением, Gemini входит как конкурент, готовый бросить вызов обоим конкурентам. Ожидается, что ее появление усилит гонку за ликвидностью, глубиной продуктов и привлечением пользователей, стимулируя более агрессивную дифференциацию платформ. Генеральный директор Kalshi Тарек Мансур ранее описывал соперничество между Kalshi и Polymarket как "свирепую" дуэль, которая заставляет молодой рынок созревать. Вход Gemini превращает дуополию в конкурентный треугольник, стимулируя более быстрые инновации и более острое соперничество на рынках прогнозов. Эта статья была написана Таней Чепковой на www.financemagnates.com.
Поделиться
Financemagnates2025/12/11 18:00