<body>
<canvas width="1000" height="500" id="display"></canvas>
<br>
Iterations:
<textarea rows="1", cols="2", id="iterations">5</textarea>
<button onclick="generate('basin')">Generate with Basin Method</button>
<button onclick="generate('angle')">Generate with Angle Method</button>
<button onclick="if (generating) {stop = true;}">Force Stop</button>
</body>
#display {
border: 1px solid black;
}
html {
text-align: center;
}
//Class for numbers a + bi
function complex(real, imag) {
this.real = real;
this.imag = imag;
this.square = function() {
var a = this.real;
var b = this.imag;
return new complex(a*a - b*b, 2*a*b);
}
this.cube = function() {
var a = this.real;
var b = this.imag;
return new complex(a*a*a - 3*a*b*b, 3*a*a*b - b*b*b);
}
this.abs = function() {
var a = this.real;
var b = this.imag;
return (Math.sqrt(a*a + b*b));
}
this.neg = function() {
var a = this.real;
var b = this.imag;
return new complex(-1*a, -1*b);
}
this.angle = function() {
var a = this.real;
var b = this.imag;
if (a >= 0) {
var theta = Math.atan(b/a);
} else {
var theta = Math.atan(b/a) + Math.PI;
}
if (arguments[0] == "deg") {
theta = 180*theta/Math.PI;
}
return theta;
}
}
//Takes complex numbers (from the class "complex") as arguments and adds them
function add() {
var a = 0;
var b = 0;
for (var i = 0; i < arguments.length; i++) {
a = a + arguments[i].real;
b = b + arguments[i].imag;
}
return new complex(a, b);
}
//Takes complex numbers (from the class "complex") as arguments and multiplies them
function multiply() {
var a = arguments[0].real;
var b = arguments[0].imag;
for (var i = 1; i < arguments.length; i++) {
var a2 = arguments[i].real;
var b2 = arguments[i].imag;
var aTemp = a;
a = a*a2 - b*b2;
b = aTemp*b2 + b*a2;
}
return new complex(a, b);
}
//takes two complex numbers (from class "complex") as parameters and divides the first by the second
function divide(comp1, comp2) {
var a = comp1.real;
var b = comp1.imag;
var a2 = comp2.real;
var b2 = comp2.imag;
var aNew = (a*a2 + b*b2)/(a2*a2+b2*b2);
var bNew = (b*a2 - a*b2)/(a2*a2+b2*b2);
return new complex(aNew, bNew);
}
var xMin = -2;
var xMax = 2;
var yMin = -1;
var yMax = 1;
var position = new complex();
var root1 = new complex(1, 0);
var root2 = new complex(-0.5, Math.sqrt(3)/2);
var root3 = new complex(-0.5, -1*Math.sqrt(3)/2);
var display = document.getElementById('display');
var ctx = display.getContext('2d');
function renderBasin(d1, d2, d3, x, y) {
if (d1 < d2 && d1 < d3) {
ctx.fillStyle = "#ff0000";
ctx.fillRect(x,y,1,1);
} else if (d2 < d3) {
ctx.fillStyle = "#00ff00";
ctx.fillRect(x,y,1,1);
} else {
ctx.fillStyle = "#0000ff";
ctx.fillRect(x,y,1,1);
}
}
function renderAngle(point, x, y) {
var angle = point.angle("deg");
ctx.fillStyle = "hsl(" + angle + ", 100%, 50%)";
ctx.fillRect(x,y,1,1);
}
var generating = false;
var stop = true;
function generate(method) {
function loop2() {
setTimeout(function() {
if (generating) {
stop = true;
loop2();
} else {
stop = false;
generating = true;
var iterations = document.getElementById('iterations').value;
var y = 0;
loop1();
function loop1() {
setTimeout(function() {
for (var x = 0; x < display.width; x++) {
if (stop) {break;}
position.real = xMin + x*(xMax - xMin)/display.width;
position.imag = yMin + y*(yMax - yMin)/display.height;
for (var i = 0; i < iterations; i++) {
if (stop) {break;}
position = add(
position,
divide(
add(
new complex(-1,0),
position.cube()
),
multiply(
new complex(3,0),
position.square()
)
).neg()
)
}
var dist1 = add(position, root1.neg()).abs();
var dist2 = add(position, root2.neg()).abs();
var dist3 = add(position, root3.neg()).abs();
if (method == "basin") {
renderBasin(dist1, dist2, dist3, x, y);
} else if (method == "angle") {
renderAngle(position, x, y);
}
}
y++;
if (y < display.height && !stop) {
loop1();
} else {
generating = false;
}
}, 0);
}
}
}, 0);
}
loop2();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.