In mathematics, a fixed point is an input x
for a function f
such that
f(x) = x
The Mandelbrot Set is a visualization of which points near 0
in the complex plane are fixed points for the function
, where
. Points that are fixed are rendered in black, while all other points are colour-coded based on how quickly repeated application of the function to a point diverges.
Images of the Mandelbrot set should be familiar to most everyone. It’s an infinitely detailed, self-similar set of rainbows surrounding bubbles.






So here’s my javascript and canvas based Mandlebrot viewer:
var xScale, xOffext, yScale, yOffset, xVal, yVal;
var canvas, h, w;
updateScalesAndOffsets = function() {
xScale = parseFloat(document.getElementById('xScale').value);
xOffset = parseFloat(document.getElementById('xOffset').value);
yScale = parseFloat(document.getElementById('yScale').value);
yOffset = parseFloat(document.getElementById('yOffset').value);
};
updateCanvasAndDimensions = function() {
canvas = document.getElementById('m');
h = canvas.getAttribute('height');
w = canvas.getAttribute('width');
};
doMandelbrot = function() {
var iteration, max_iteration = 1000, l, x, y, x0, y0, xtemp;
updateCanvasAndDimensions();
var ctx = canvas.getContext('2d');
updateScalesAndOffsets();
for (var i=0; i < w; i++) {
for (var j=0;j < h; j++) {
// for each point in the image, generate the color value.
x0 = xScale * (i / w) + xOffset;
y0 = yScale * (j / h) + yOffset;
x = 0;
y = 0;
iteration = 0;
while (x*x + y*y < 4 && iteration < max_iteration) {
// this is parametrically performing the complex function f(z) = z^2 -1.
xtemp = x*x - y*y + x0;
y = 2*x*y + y0;
x = xtemp;
iteration++;
}
if (x*x + y*y < 4) {
ctx.fillStyle='rgb(0,0,0)';
} else {
l = iteration < 50? iteration : 50;
// set colors using hsl so that the number of iterations to diverge maps to the hue.
ctx.fillStyle='hsl('+Math.floor((iteration/max_iteration)*256)+',100%,' + l + '%)';
}
ctx.fillRect(i,j,i+1,j+1);
}
}
};
mouseMove = function(e) {
xVal = xScale * (e.clientX / w) + xOffset;
yVal = yScale * (e.clientY / h) + yOffset;
var xCoordinateElement = document.getElementById('xCoordinate'), yCoordinateElement = document.getElementById('yCoordinate');
xCoordinateElement.innerHTML = xVal;
yCoordinateElement.innerHTML = yVal;
};
zoomIn = function() {
document.getElementById('xScale').value = parseFloat(document.getElementById('xScale').value) / 2;
document.getElementById('xOffset').value = xVal - parseFloat(document.getElementById('xScale').value) / 2;
document.getElementById('yScale').value = parseFloat(document.getElementById('yScale').value) / 2;
document.getElementById('yOffset').value = yVal - parseFloat(document.getElementById('yScale').value) / 2;
doMandelbrot();
}
zoomOut = function() {
document.getElementById('xScale').value = parseFloat(document.getElementById('xScale').value) * 2;
document.getElementById('yScale').value = parseFloat(document.getElementById('yScale').value) * 2;
doMandelbrot();
}
moveDir = function(dir) {
switch (dir) {
case 'up' : document.getElementById('yOffset').value = yOffset - yScale / 10; break;
case 'down' : document.getElementById('yOffset').value = yOffset + yScale / 10; break;
case 'right' : document.getElementById('xOffset').value = xOffset + xScale / 10; break;
case 'left' : document.getElementById('xOffset').value = xOffset - xScale / 10; break;
}
updateScalesAndOffsets();
doMandelbrot();
}