Статья по теме:
Демо JavaScript:
<!doctype html> <html lang = "en"> <head> <title> fractal </title> <meta charset = "utf-8"> <script src = "js/script.js" defer></script> </head> <body> <div id = "main" style = "position: absolute; top: 0; left: 0; "> <canvas id = "canvas" width = "500" height = "500" style = "background-color: black; "></canvas> <div id = "menu"> <span>Choose lambda value</span> <label> <input id = "lambda" type = "number" size = "3" min = "1" max = "5000" value = "64"> </label> <span>, choose color</span> <label> <select id = "color"> <option value = "fixed"> Fixed color </option> <option value = "random"> Random color </option> <option value = "allRandom"> All random color </option> <option value = "gradient"> Gradient color </option> </select> </label> <span>, choose iteration counter</span> <label> <input id = "counter" type = "number" size = "4" min = "1" max = "5000" value = "150"> </label> <span>, clockwise</span> <label> <input id = "clockwise" type = "checkbox" checked> </label> <button id = "start"> Select </button> </div> </div> </body> </html>
/***** Canvas *****/ let canvas = document.querySelector("#canvas"); let ctx = canvas.getContext("2d"); let canvasWidth = canvas.width; let canvasHeight = canvas.height; let canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight); /***** Случайный цвет *****/ // из 10-ой сс в 16-ую сс function decToHex(n) { return Number(n).toString(16); } // Случайное число function randomNumber(max) { return Math.floor(Math.random() * max); } // Случайный цвет function randomColor() { let r, g, b, res; r = decToHex(randomNumber(255)); g = decToHex(randomNumber(255)); b = decToHex(randomNumber(255)); res = "#" + r + g + b; return res; } /***** Графическая библиотека *****/ // Описываем точку class Point { constructor(x, y) { this.x = x; this.y = y; } } // Рисуем четырёхугольник function drawQuadrangle(canvasData, p1, p2, p3, p4) { ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.lineTo(p3.x, p3.y); ctx.lineTo(p4.x, p4.y); ctx.lineTo(p1.x, p1.y); switch (choose) { case "fixed": case "random": ctx.strokeStyle = color; ctx.stroke(); break; case "allRandom": ctx.strokeStyle = randomColor(); ctx.stroke(); break; case "gradient": ctx.fillStyle = "rgb(" + colorR + "," + colorG + "," + colorB + ")"; if (2 * t <= cnt) { colorR -= sign * step; colorG -= sign * step; colorB -= sign * step; } else { colorR += sign * step; colorG += sign * step; colorB += sign * step; } ctx.fill(); break; default: console.log("error color", color); } } /***** Анимация *****/ // Таймер для анимации let timerId; // Параметр анимации let t = 0; // Вершины квадрата let p1, p2, p3, p4; // Параметры программы let lambda, choose, color, cnt, clockwise; // Компоненты цвета для градиента и знак, чтобы темнить или осветлять let colorR, colorG, colorB, step, sign; // Считаем площадь квадрата function calculateSquare(points) { let tmp = 0; for (let i = 0; i < 4; i++) { tmp += points[i].x * points[(i + 1) === 4 ? 0 : (i + 1)].y - points[(i + 1) === 4 ? 0 : (i + 1)].x * points[i].y; } return 0.5 * Math.abs(tmp); } // Считаем точку которая деленит отрезок в данном отношении lambda function change(start, finish) { return ((start + lambda * finish) / (1 + lambda)); } // Рисуем изобржение function draw() { let square = calculateSquare([p1, new Point(p2.x, p2.y + 1), new Point(p3.x + 1, p3.y + 1), new Point(p4.x + 1, p4.y)]); if (t < 0 || 2 * square < 1) { console.log(t); clearInterval(timerId); return; } drawQuadrangle(canvasData, p1, p2, p3, p4); let tmp = p1; p1 = new Point(change(p1.x, p2.x), change(p1.y, p2.y)); p2 = new Point(change(p2.x, p3.x), change(p2.y, p3.y)); p3 = new Point(change(p3.x, p4.x), change(p3.y, p4.y)); p4 = new Point(change(p4.x, tmp.x), change(p4.y, tmp.y)); t--; } // Функция с которой программа начинает работу function init() { clearInterval(timerId); ctx.clearRect(0,0, canvasWidth, canvasHeight); lambda = parseFloat(document.getElementById("lambda").value); choose = document.getElementById("color").value; cnt = parseInt(document.getElementById("counter").value); clockwise = document.getElementById("clockwise").checked; t = cnt; switch (choose) { case "fixed": color = "#fff"; break; case "random": color = randomColor(); break; case "gradient": colorR = 69; colorG = 39; colorB = 125; step = (cnt === 0 ? 0 : 2 * (255 - Math.max(colorR, colorG, colorB)) / cnt); sign = (255 - Math.max(colorR, colorG, colorB) > 128 ? 1 : -1); break; default: color = "#000"; } if (!clockwise) { lambda = 1 / lambda; } p1 = new Point(0, 0); p2 = new Point(0, canvasWidth); p3 = new Point(canvasWidth, canvasWidth); p4 = new Point(canvasWidth, 0); timerId = setInterval(draw, 50); } // При нажатии на кнопку select вызывается init() document.querySelector("#start").addEventListener("click", init);