
The purpose of this post is to show how to plot the Mandelbrot Set using javascript and the canvas API. We’ve seen the Mandelbrot fractal image a million times, and there are many examples around of fractal explorers that let you visualise fractals, alter parameters, and zoom infinately far into their complex shapes. The code in this example strips things back to show how the basic map is plotted so that the algorithm is clear. It is based heavily on the excellent tutorial and C++ example found here, and is a reasonably close port to javascript. The code is written for clarity rather than optimization.
I recommend reading the tutorial and getting a general idea of how the algorithm works, having some knowledge of what complex and imaginary numbers are helps too. The javascript version of the code plots the image seen above, but can be easily altered to plot different patterns using a Julia Set. All you need to do is change the cReal and cImaginary variables to be constant values, as described in the tutorial.
Changing the real and imaginary limit variables will change the scaling of the set, and changing the numIterations variable will alter the level of detail (increasing it won’t change much of what you can see but will slow things down).
The Mandelbrot Set consists of the points in black, rather than the coloured points. This example using a similar method to the C++ version to colour the pixels, however it would be easy to change that part of the code to use other colouring methods.
With a fair understanding of how the code works it could be expanded to make Mandelbrot or Julia Set explorers such as this, this, this or this (yes they are popular), or just generate your own interesting fractal images.
Meanwhile I’m looking forward to what the Fractal.io people do next.
window.addEventListener("load",App,false);
function App() {
var theCanvas = document.getElementById("canvas1");
var context = theCanvas.getContext("2d");
drawMandelbrot(context);
}
function drawMandelbrot(context) {
// Create a canvas imagedata object to draw on
var width = 800, height = 600;
var img = context.createImageData(width,height)
//real number limits (represented on the x axis)
var minReal = -2.0;
var maxReal = 1.0;
//imaginary number limits (represented on the y axis)
var minImaginary = -1.2;
var maxImaginary = minImaginary + (maxReal-minReal) * height/width;
// maximum number of iterations influences level of detail
var numIterations = 50;
// used for converting between pixel resolution and the complex number plane limits
var realFactor = (maxReal-minReal)/(width-1);
var imaginaryFactor = (maxImaginary-minImaginary)/(height-1);
// used to calculate whether a point lies within the mandelbrot set
var cImaginary,cReal;
var zReal,zImaginary;
var zReal2,zImaginary2;
// a boolean to indicate whether the point was within the mandelbrot set
var insideSet;
//calculate rows (y/imaginary axis)
for (var y = 0;y < height;y++) {
cImaginary = maxImaginary - y*imaginaryFactor;
//calculate columns (x/real axis);
for (var x = 0;x < width;x++) {
cReal = minReal + x*realFactor;
zReal = cReal;
zImaginary = cImaginary;
//assume the value is within set
inside = true;
//iterate
for (var i=0;i<numIterations;i++) {
zReal2 = zReal*zReal;
zImaginary2 = zImaginary*zImaginary;
//check to see if Z will tend to infinity (not inside set)
if (zReal2 + zImaginary2 > 4) {
inside = false;
break; // if not inside set then exit the for loop
}
zImaginary = 2*zReal*zImaginary + cImaginary;
zReal = zReal2 - zImaginary2 + cReal;
}
if (inside) {
// points inside the set are set to black
setPixel(img,x,y,0,0,0,255);
} else {
// points outside the set are colored black to red and red to white
if (i < numIterations /2 -1) {
setPixel(img,x,y,i*10,0,0,255);
} else {
setPixel(img,x,y,i*10,255,255,255);
}
}
}
}
context.putImageData(img,0,0)
}
// writes rgba values to a pixel in the image data pixel array
function setPixel(imgData, x, y, r, g, b, a) {
offset = (x + y * imgData.width) * 4;
imgData.data[offset+0] = r;
imgData.data[offset+1] = g;
imgData.data[offset+2] = b;
imgData.data[offset+3] = a;
}