1. The fractal
We'll use the Julia fractal. If you're not interested in the mathematical details, feel free to skip the gray section below. All you need to know is:
- it's a great Javascript exercise
- Julia fractals are mathematical images generated by iterating the calculation in rows 13-22 as long as the condition in row 24 is fulfilled. Then we plot the color corresponding to the value of i (=number of iterations).
For a fixed point c (its coordinates [c real and c imaginary] are defined in lines 4-5: experiment with different values between -2 and 2) in the complex plane, we'll iterate the formula:
zn+1=zn2+c
(lines 19-21) until the number of iterations reaches 255 or the result is higher than 4 (line 24). We could use a higher limit of iterations to get a more detailed image, but 255 is the highest value that HTML allows to assign to an RGB component. A result of 4 or more means that for complex coordinates that are currently being calculated the orbit escapes to infinity - this is what actually gives Julia its amazing shape.
We'll plot the color corresponding to the number of iterations (lines 26-30). Lines 9-14 convert the the screen coordinates into complex coordinates.
It is very similar to Mandelbrot (click this link to get more details on the math behind both of them), except with Julia the point c is fixed.
Each point in the Mandelbrot set corresponds to a Julia set.
When it comes to animation, you can zoom into the Mandelbrot set, but Julia is more interesting because its shape is different for different c points.
0 |
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 |
<html> |
<body> |
<canvas id="myCanvas" width="800" height="800"></canvas> |
<script> |
var creal = -.8 |
var cimag = .156; |
var canvas = document.getElementById('myCanvas'); |
var context = canvas.getContext('2d'); |
|
for(y=0;y<200;y++) |
{ |
for(x=0;x<200;x++) |
{ |
var cx=-2+x/50; |
var cy=-2+y/50; |
var i = 0; |
|
do |
{ |
xt=cx*cx-cy*cy+creal; |
cy=2*cx*cy+cimag; |
cx=xt; |
i++; |
} |
while ((cx*cx+cy*cy<4)&&i<255); |
|
i=i.toString(16); |
context.beginPath(); |
context.rect(x*4, y*4, 4, 4); |
context.fillStyle ='#'+i+i+i; |
context.fill(); |
} |
} |
</script> |
</body> |
</html> |
2. Animation
With only a couple of additional lines (see the comments in the code), we can bring the fractal to life. All we're doing is changing the c point with each animation frame and redrawing the fractal. By using the sin and cos functions, we're moving it around on the complex plane, so that it ends up where it started. Experiment with the formulas in lines 37 and 38! We'll also reduce the number of maximum iterations to 25 to allow even slower machines enough time for the calculations in each frame.
0 |
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 |
<html> |
<body> |
<canvas id="myCanvas" width="800" height="800"></canvas> |
<script> |
var creal = -.8 |
var cimag = .156; |
var canvas = document.getElementById('myCanvas'); |
var context = canvas.getContext('2d'); |
var frame = 0; // new variable to track the current frame number |
|
function julia() // the program drawing the fractal |
{ // is now a function so that it can be called periodically |
for(y=0;y<200;y++) |
{ |
for(x=0;x<200;x++) |
{ |
var cx=-2+x/50; |
var cy=-2+y/50; |
var i = 0; |
|
do |
{ |
xt=cx*cx-cy*cy+creal; |
cy=2*cx*cy+cimag; |
cx=xt; |
i++; |
} |
while ((cx*cx+cy*cy<4)&&i<25); |
|
i=i.toString(16); |
context.beginPath(); |
context.rect(x*4, y*4, 4, 4); |
context.fillStyle ='#'+i+i+i; |
context.fill(); |
} |
} |
frame++; // increase the number of the frame |
creal=-.8+.6*Math.sin(frame/(3.14*20)); // calculate the new coordinates |
cimag=.156+.4*Math.cos(frame/(3.14*40)); // of the c point |
} |
|
a=setInterval(julia,100); //redraw the fractal every 100ms |
|
</script> |
</body> |
</html> |
3. The colors
In the final step, we can replace the grayscale with a colorful pallette. The modified lines of code are commented below.
So far, we set the number of iterations for a given point as the Red, Green and Blue components of its color. This time we'll create an array of 24 colors in 3 ranges, 8 colors in each. In each of the ranges, one of the RGB components will gradually increase from 0 to 255 (minimum and maximum values allowed by HTML), while the other two components are constant for each of the ranges.
Click here to read about other ways of creating the pallette.
0 |
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 |
<html> |
<body> |
<canvas id="myCanvas" width="800" height="800"></canvas> |
<script> |
var creal = -.8 |
var cimag = .156; |
var canvas = document.getElementById('myCanvas'); |
var context = canvas.getContext('2d'); |
var frame = 0; |
|
var pallette=[]; //an array that stores the RGB combinations |
|
function julia() |
{ |
for(y=0;y<200;y++) |
{ |
for(x=0;x<200;x++) |
{ |
var cx=-2+x/50; |
var cy=-2+y/50; |
var i = 0; |
|
do |
{ |
xt=cx*cx-cy*cy+creal; |
cy=2*cx*cy+cimag; |
cx=xt; |
i++; |
} |
while ((cx*cx+cy*cy<4)&&i<25); |
|
//i=i.toString(16); - commented out since not needed in this version |
context.beginPath(); |
context.rect(x*4, y*4, 4, 4); |
context.fillStyle = pallette[i]; |
context.fill(); |
} |
} |
frame++; |
creal=-.8+.6*Math.sin(frame/(3.14*20)); |
cimag=.156+.4*Math.cos(frame/(3.14*40)); |
|
} |
|
for(x=0;x<9;x++) // this loop populates the color pallette array |
{ |
color=(31*x).toString(16); // convert the number to hex |
if(color.length==1) color='0'+color; // add a zero in front if only one hex digit |
pallette[x]="#"+color+color+'ff'; // colors 0-8: the Red and Green components change, Blue=FF |
pallette[x+8]='#00ff'+color; // colors 8-16: the Blue component changes, Red and Green=FF |
pallette[17+x]="#"+color+'0000'; // colors 17-25: the Red component changes, Green and Blue=0 |
} |
|
a=setInterval(julia,100); |
|
</script> |
</body> |
</html> |
More JavaScript tutorials:
Fire effect in JavaScript: 20 lines of code
Your first program in JavaScript: you need 5 minutes and a notepad
Tutorial - interactive, animated sprites in JavaScript
8-bit style sine scroll (30 lines)
YinYang with a twist - 4 circles and 20 lines of code
Count the dots - optical illusion (18 lines)
Python
Domino effect (10 lines)
Wrecking ball effect (14 lines)
3d fractal in Blender Python
Fractals in Excel