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(); }