JSFiddle - React, Tailwind, and code Playground
HTML
<title>JS fractals</title>
<body>
<div class="container">
<canvas id="drawfrac" width="600px" height="600px"></canvas>
<table class="table">
<tr>
<td class="baseprop">
<div class="title">Baseline</div>
<input id="showbase" name="show" type="checkbox" checked>Show<br>
Normal color: <input id="basenormcolor" name="ncolor" type="text" value="#000080"><br>
Inverse color: <input id="baseinvcolor" name="icolor" type="text" value="#800000"><br>
Line width: <input id="basewidth" name="bwidth" type="text" value="2"><br>
Background: <input id="backcolor" name="bcolor" type="text" value="#D0D0D0"><br>
</td>
<td class="fracprop">
<div class="title">Fractal</div>
<input id="showfrac" name="show" type="checkbox" checked>Show<br>
Fractal iterations:
<select id="fracdepth">
<option value="0">0</option>
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="-1">as needed</option>
</select><br>
Fractal color: <input id="fraccolor" name="fcolor" type="text" value="#40F040"><br>
Line width: <input id="fracwidth" name="fwidth" type="text" value="2"><br>
</td>
</tr>
<tr>
<td class="description" colspan="2">
<div class="title">Description</div>
A simple JS program to draw a simplest type of fractals. Use:<br>
<i>Shift + Left Click on baseline segment</i> to add node to baseline;<br>
<i>Ctrl + Left Click on baseline node</i> to remove node;<br>
<i>Left Click on node</i> to move node;<br>
<i>Left Click on segment</i> to reverse fractal on that segment;<br>
<i>Left Click on...
CSS
.container {
width: 680px;
margin: 20px;
}
#drawfrac {
margin: 40px;
border: 2px solid black;
}
.table {
width: 100%;
border-spacing: 5px;
line-height: 170%;
}
.baseprop, .fracprop {
width: 50%;
background-color: #F0F0C0;
border: 1px solid black;
padding: 0 10px;
vertical-align: top;
}
.description {
background-color: #C0F0C0;
border: 1px solid black;
padding: 0 10px;
}
.title {
text-align: center;
font-weight: bold;
}
JavaScript
// Функция, которая создает объект фрактала. Здесь происходит вычисление фрактала,
// отрисовка и изменения. Странно работать с этими объектами JS без классов.
function fracObject() {
// Здесь будут приватные данные и методы.
var own = {};
// А здесь публичные.
var that = {};
// Базовая линия, на основе которой строится фрактал.
own.baseline = [ { x: 50, y: 450 }, { x: 550, y: 450 } ];
// Нормализованная базовая линия. Первая точка = (0, 0), последняя = (1, 0).
own.normalized = [];
// Глубина фрактала. При значении 0 фрактальная кривая соответствует базовой линии.
// При значении 1 каждый сегмент базовой линии заменяется на копию базовой линии,
// соответствующим образом смасштабированную и повернутую. При значении 2, это
// происходит дважды, и так далее. При значении -1 преобразования происходят до тех
// пор, пока отрезки не станут слишком маленькими.
own.fracDepth = 0;
// Вектор inverse[0] определяет заменяется ли сегмент на копию базовой линии (при
// значении 0), либо на отраженную вдоль оси y копию (при значении 1). Вектор
// inverse[1] = 1 - inverse[0], исключительно для удобства, векторизации не
// хватает. И пожалуй, inverse - не лучшее название.
own.inverse = [ [ 0 ], [ 1 ] ];
// Нормализация. Масштабирование и поворот, ничего сложного.
own.normalize = function() {
own.normalized = [];
var i, x, y, n = own.baseline.length;
var x0 = own.baseline[0].x, y0 = own.baseline[0].y;
var x1 = own.baseline[n-1].x, y1 = own.baseline[n-1].y;
var d = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2));
var a = Math.atan2(y1 - y0, x1 - x0);
for (i = 0; i < n; i++) {
x = (own.baseline[i].x - x0) / d;
y = (own.baseline[i].y - y0) / d;
own.normalized.push({ x: x * Math.cos(a) + y * Math.sin(a),
y: y * Math.cos(a) - x * Math.sin(a) });
}
};
// И сразу же...