Mandelbrot

Mandelbrot is a javascript implementation of a simple mandelbrot set calculator.

//
// Set the pixel at location <x,y> in the image data to <r,g,b,a>.  The r, g,
// and b elements are the red, green, and blue color components.  The a element
// is the alpha, or transparency value.  The r, g, b, and a values can range
// from 0 to 255.
//
function set_pixel(image_data, x, y, r, g, b, a)
{
    // Compute the index into the pixel data.  Each pixel is represented by four
    // sequential values in the image_data.data array.
    index = (x + y * image_data.width) * 4;

    image_data.data[index + 0] = r;
    image_data.data[index + 1] = g;
    image_data.data[index + 2] = b;
    image_data.data[index + 3] = a;
}

//
// Compute the number of iterations required for a single orbit of the
// mandelbrot equation to escape from a circle of radius 2 centered at the
// origin of the complex plane.
//
function compute_escape_time(c_r, c_i, maximum_iterations)
{
    z_r = 0.0;
    z_i = 0.0;

    for (i = 0; i < maximum_iterations; i++)
    {
	//
	// Compute a single iteration of Z^2 + C.  Complex numbers are of the
	// form "real + imaginary * i", so to square them you end up computing:
	//
	// (real + imaginary * i) * (real + imaginary * i)
	// =
	// real * real + imaginary * imaginary * i^2 + 2 * real * imaginary * i
	// =
	// real * real - imaginary * imaginary + 2 * real * imaginary * i
	//
	// So the new real value is (real * real - imaginary * imaginary)
	// And the new imaginary value is (2 * real * imaginary)
	//
	// The reason the first + turns into a - is because i^2 is defined to be
	// equal to -1, that's what makes the numbers imaginary.
	//
	temp = (z_r * z_r) - (z_i * z_i) + c_r;
	z_i = (2.0 * z_r * z_i) + c_i;
	z_r = temp;

	// Check to see if the magnitude of the complex number is larger than
	// 2.  We check whether the squared magnitude is greater than 4 here to
	// avoid taking a square root, because square roots are slow.
	if (((z_r * z_r) + (z_i * z_i)) > 4.0)
	    return i;
    }

    // Return the maximum iterations value if we never escaped.
    return maximum_iterations;
}

//
// Draw a Mandelbrot set filling in a canvas specified by element_id.
//
function draw_mandelbrot(element_id)
{
    // Lookup the canvas and get a 2D rendering context from it.
    element = document.getElementById(element_id);
    context = element.getContext("2d");

    //
    // Construct an image data object to hold the pixels before they are
    // drawn to the screen.
    //
    image_data = context.createImageData(element.width,
					 element.height);

    //
    // Iterate over every pixel in the canvas and compute the escape time for
    // the corresponding point in the complex plane.
    //
    for (y = 0; y < image_data.height; y++)
    {
	for (x = 0; x < image_data.width; x++)
	{
	    //
	    // This scales the <x, y> values into a smaller range of the
	    // complex plane.  But it doesn't take into account the size of the
	    // canvas element.  So if the canvas element changes size, this will
	    // need to change as well.  This can be made automatic, but it would
	    // obcure the meaning for this example.  It would be a good
	    // experiment to change these values and try and make the result
	    // general.
	    //
	    iterations = compute_escape_time((x - 350.0) / 200.0,
					     (y - 250.0) / 200.0,
					     100);

	    //
	    // This is a simple use of the iteration count.  We are only looking
	    // at the bottom bit of the resulting escape time iterations.  This
	    // results in the zebra striping look.
	    //
	    if (iterations & 1)
		r = g = b = 255;
	    else
		r = g = b = 0;

	    //
	    // Write the computed color value to the image_data at the current
	    // location.
	    //
	    set_pixel(image_data, x, y, r, g, b, 255);
	}
    }

    // Finally, copy the resulting image to the canvas for display.
    context.putImageData(image_data, 0, 0);
}

Syntax highlighted with Prism.