-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtreefractal.html
248 lines (203 loc) · 10.3 KB
/
treefractal.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
<!DOCTYPE html>
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<style>
#form1 {
padding: 10px 10px 10px 10px;
}
#form1 input {
margin: 10px 10px 10px 10px;
display: inline-block;
}
body {
width: 100%;
}
#tutorial {
padding: 20px 20px 40px 40px;
font-size: 16px;
font-family: serif;
h1 {
font-family: 'Helvetica Neue';
}
}
</style>
</head>
<body>
<div class="container-fluid">
<div class="row" id="tutorial">
<h1>Make Your Own Fractal Tree!</h1>
<p>Using the parameters below you can grow your own trees using fractals (well, approximately a fractal). The tree is generated by starting with a trunk of a certain length and then adding two branches that split off at a specified angle and length that is a ratio of the trunk. We continue adding these split branches for every branch that is drawn, up to a certain depth. If you were to repeat this process, as the limit approached inifity, you would have a set of numbers that were of a fractional dimension and had a self-repeating structure. Namely, a fractal set.</p>
<p>Below, I provide access to some parameters so that you can draw one of your own trees by: (1) controlling the number of layers you compute, (2) changing the length ratio of the branches to their parent branch, and (3) shifting the angles where the branches emerge. You can also set the width and length of the trunk, which will change the look of your whole tree (making it thicker and taller). You also have a color choice. The branches get filled in on a color spectrum where the starting color is your trunk's hue and the ending color is your leave's hue. Lastly, I made some little flower buds that you can add. The code is all done in JavaScript's D3 library, and can be found on <a href="https://www.github.com/wannabeCitizen/FractalTree">my GitHub</a>.</p>
<h2>Suggesions on Parameters</h2>
<p>I advise keeping tree depth under 20. The computations grow O(2^n) so your browser can crash if you push it. By about 15 you'll notice a serious slowdown. The length ratios are really nice in the .6-.8 range, and quickly become impossible to render for values greater than 1 (if you do want to go big, I'd take my code and re-render it with a bigger canvas). Width of trunk looks pretty natural between 10-20 (pixels) and the height 100-300. The colors need to be specified in hex (e.g., "#FF0000" = red). If you need help finding colors you can try <a href="https://color.adobe.com">this</a> or <a href="http://www.w3schools.com/tags/ref_colorpicker.asp">this</a>.</p>
<p>Start off by hitting submit to see the basic tree then start playing around and see what you find. <b>You may need to scroll down</b> to see the tree because I had to use a pretty large canvas to support the range of tree sizes. While the suggestions above are starters, you'll find some beautiful behavior in other ranges. Have fun!</p>
<br>
</div>
<div class="row">
<form id="form1">
<div class="col-md-4">
<div class="user_params" id="init1">
Tree Depth:<br>
<input type="text" id="depth" value="8">
<br>Line Ratio 1:<br>
<input type="text" id="ratio1" value=".67">
<br>Line Ratio 2:<br>
<input type="text" id="ratio2" value=".67">
<br>Angle 1:<br>
<input type="text" id="angle1" value="60">
<br>Angle 2:<br>
<input type="text" id="angle2" value="60">
<br>
</div>
</div>
<div class="col-md-4">
<div class="user_params" id="init2">
Width of Trunk:<br>
<input type="text" id="width" value="12">
<br>Length of Trunk:<br>
<input type="text" id="length" value="200">
<br>Trunk Color<br>
<input type="text" id="color1" value="#663300">
<br>Leaf Color<br>
<input type="text" id="color2" value="#006600">
<br>Add random flowers?<br>
<input type="radio" name="flower" id="flowers" value="yes" checked="checked"> yes
<input type="radio" name="flower" id="flowers" value="no"> no
<br>Add randomness to angles?<br>
<input type="radio" name="angleRand" id="angleRand" value="yes"> yes
<input type="radio" name="angleRand" id="angleRand" value="no" checked="checked"> no
<br>
<input type="submit" value="submit" id="sub_button">
</div>
</div>
</form>
</div>
</div>
<script>
$("#form1").submit(function ( event ){
myDepth = parseInt($("#depth").val());
ratio1 = parseFloat($("#ratio1").val());
ratio2 = parseFloat($("#ratio2").val());
angle1 = parseFloat($("#angle1").val());
angle2 = parseFloat($("#angle2").val());
myLength = parseInt($("#length").val());
myWidth = parseInt($("#width").val());
colorStart = $("#color1").val();
colorEnd = $("#color2").val();
flowers = $("#flowers:checked").val();
angleRand = $("#angleRand:checked").val();
console.log(flowers);
console.log(angleRand);
if (!myDepth) { myDepth = 8;}
if (!ratio1) { ratio1 = .67;}
if (!ratio2) { ratio2 = .67;}
if (!angle1) { angle1 = 60;}
if (!angle2) { angle2 = 60;}
if (!myLength || myLength > 350) { myLength = 150;}
if (!myWidth) { myWidth = 10;}
if (!colorStart) { colorStart = "#663300";}
if (!colorEnd) { colorEnd = "#006600";}
if (flowers == "yes") {
flowers = true;
} else if (flowers == "no") {
flowers = false;
}
if (angleRand == "yes") {
angleRand = true;
} else if (angleRand == "no") {
angleRand = false;
}
$("svg").empty();
lines = buildTree(myDepth, ratio1, ratio2, angle1, angle2, myWidth, myLength, flowers, colorStart, colorEnd, angleRand);
return false;
});
var treeLine = function (x0, y0, x, y, l, angle) {
this.x0 = x0;
this.y0 = y0;
this.x = x;
this.y = y;
this.len = l;
this.angle = angle
};
var toRadians = function (angle) {
return angle * (Math.PI/180);
}
var nextLines = function (starting, ratio1, ratio2, angle1, angle2) {
x1 = starting.x;
y1 = starting.y;
theta = starting.angle;
draw_len = starting.len;
x21 = x1 + ratio1*draw_len*Math.cos(toRadians(theta - angle1));
y21 = y1 + ratio1*draw_len*Math.sin(toRadians(theta - angle1));
line1 = new treeLine(x1, y1, x21, y21, ratio1*draw_len, theta - angle1)
x22 = x1 + ratio2*draw_len*Math.cos(toRadians(theta + angle2));
y22 = y1 + ratio2*draw_len*Math.sin(toRadians(theta + angle2));
line2 = new treeLine(x1, y1, x22, y22, ratio2*draw_len, theta + angle2)
return [line1, line2];
};
var margins = {top: 20, left: 30, bottom: 20, right: 20},
width = 1200 - margins.left - margins.right,
height = 1000 - margins.top - margins.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line()
var buildTree = function (depth, ratio1, ratio2, angle1, angle2, widthT, lengthT, flowers, colorStart, colorEnd, angleRand) {
var root = new treeLine(width/2, height-200, width/2, height-200-lengthT, lengthT, -90);
var lines = [root];
var leaves = [root];
console.log(angleRand);
for (var i = 0; i<=depth; i++){
var newLeaves = [];
for (var seed in leaves) {
if (angleRand) {
angleTest = Math.random();
if (angleTest > .5) {
angle1 += Math.random()*10;
angle2 -= Math.random()*10;
} else {
angle1 -= Math.random()*10;
angle2 += Math.random()*10;
}
}
var newLines = nextLines(leaves[seed], ratio1, ratio2, angle1, angle2);
for (var addons in newLines) {
lines.push(newLines[addons]);
newLeaves.push(newLines[addons]);
}
}
leaves = newLeaves.slice();
}
var flowerScale = d3.scale.linear()
.domain([10,0])
.interpolate(d3.interpolateHcl)
.range(["#CC0066", "#FF33CC"]);
var colorScale = d3.scale.linear()
.domain([200, 0])
.interpolate(d3.interpolateHcl)
.range([colorStart, colorEnd]);
var colorPick = function (branchL) {
test = Math.random();
if (flowers && branchL <= 5 && test > .9) {
return flowerScale(branchL)
} else {
return colorScale(branchL)
}
};
var widthScale = d3.scale.linear()
.domain([lengthT, 0])
.range([widthT, 2]);
svg.selectAll('.line')
.data(lines)
.enter().append("svg:line")
.attr("x1", function (d) { return d.x0; })
.attr("y1", function (d) { return d.y0; })
.attr("x2", function (d) { return d.x; })
.attr("y2", function (d) { return d.y; })
.attr("stroke-width", function (d) { return widthScale(d.len); })
.attr("stroke", function (d) { return colorPick(d.len); });
// if (flowers && d.len < 10) { return flowerScale(d.len); } else { return colorScale(d.len); } );
};
</script>