Mandelbrot set is a mathematical set of points whose boundary is a distinctive and easily recognizable two-dimensional fractal shape. The Mandelbrot set is defined over the complex number plane. The definition of the Mandelbrot set is simple but the structure of the set is really complex and beautiful.
Mandelbrot Set Overview
Mandelbrot set is defined mathematically as the set of values of c in the complex plane for which the orbit of 0 under iteration of the complex quadratic polynomial zn+1 = zn2 + c remains bounded. That is, a complex number c is part of the Mandelbrot set if, when starting with z0 = 0 and applying the iteration repeatedly, the absolute value of zn remains bounded however large n gets.
Below is the structure of the Mandelbrot set that is generated using our application.
HTML 5 Canvas Overview
HTML5 is the latest version of the standard HTML. It comes with new cool element, Canvas that allows you to draw directly and manipulate every single pixels in the canvas. A canvas is a rectangular area on an HTML page, and it is specified with the [cci]
We’ll not cover all the definition of cool function in the canvas. There are documentation of those over the web. We only give an attention to several functions that will be used in our tutorial.
Every canvas element has a graphics context that will be used to modify the pixel on the canvas. We’ll use [cci]2d[/cci] context. To get the context, use [cci]getContext[/cci] function of the canvas object.
var canvas = document.getElementById('thecanvas'); var ctx = canvas.getContext('2d');
The above code assumes that we have defined a canvas element which id [cci]thecanvas[/cci].
Our requirement is to get all the pixels data of the canvas and modify the color of the pixels. To get all pixels data, use [cci]getImageData[/cci] function of the context. The function has 4 arguments [cci]x[/cci],[cci]y[/cci],[cci]width[/cci] and [cci]height[/cci]. [cci]x[/cci] and [cci]y[/cci] arguments define the square top left position from which the pixels will be taken. [cci]width[/cci] and [cci]height[/cci] define the dimension of the square.
var imageData = ctx.getImageData(0, 0, 100, 100); var pixels = imageData.data;
The variable [cci]pixels[/cci] above contains 100×100=10.000 pixels that is save in 1 dimension array. 1 pixels have 4 elements, red,green,blue and alpha component. So [cci]pixels[/cci] variable has 10.000×4 = 40.000 elements. 1 element pixel is an integer from 0 to 255.
We now can modify the pixels data. After the pixels have been modified, we must put the pixels back to canvas in order to our modification takes effect.
ctx.putImageData(imageData, 0, 0);
Drawing Mandelbrot Set on HTML 5 Canvas
Javascript doesn’t provides built in complex number data type. So, we have to define our complex number data type. For simplicity of the tutorial, we will represent any complex number in javascript object with two properties. The [cci]x[/cci] property represents the real part and [cci]y[/cci] property represents the imaginary part.
//define complex data type var Complex = function(x, y) { this.x = x; // real part this.y = y; // imaginary part }; //define new complex number 1+2i var complex = new Complex(1,2);
We have now a simple complex number data type for our application. Before we start to code, remember from above explanation. The mandelbrot definition requires to use two operation on complex number. We’ll not define all number operations in complex number, but we’ll create only two operations, multiplication and addition that will be used in generating mandelbrot set.
//define two complex number var a = 1, b = 2, c = 3, d = 4; var complex1 = new Complex(a,b); var complex1 = new Complex(c,d); //add complex1 and complex1 will result var addition = new Complex(a+c, b+d); //multiply complex1 and complex 2 will result var multiplication = new Complex(a*c - b*d, b*c + a*d);
The Mandelbrot Set Drawing Algorithm
We’ll use different approach from mandelbrot set definition to visualize the set. Rather than finding all complex numbers [cci]c[/cci] which is bounded, our goal is to colorize all of the pixels in the canvas based on number of iterations. This will result great visualization for mandelbrot set.
Step by Step Mandelbrot Set Drawing
- Define user interface. Our application will has simple user interface. It’ll contains color scheme selection box, a button and the canvas.
Below is HTML tags that defines our simple user interface.
Drawing Mandelbrot set on HTML5 graphics canvas
After the html page is loaded, immediately we call javascript function [cci]setupCanvas[/cci]. This function will checks whether the browser support html5 canvas then get canvas’s drawing context and save it as Dunia variable [cci]ctx[/cci]. We’ll use the context to modify each pixels on the canvas.
- Define [cci]setupCanvas[/cci] function.
var setupCanvas = function() { canvas = document.getElementById('thecanvas'); setupMouseListener(); if (!canvas.getContext) { alert("I'm sorry, seems your browser not support HTML 5, try another browser."); return; } // get drawing context ctx = canvas.getContext('2d'); };
- Define render function.
In this function we get the selected color scheme in the selection box. Save the canvas size as Dunia variables then define the scaling ratio from canvas coordinats to mandelbrot coordinats.
var render = function() { if (!canvas.getContext) return; //get color scheme var a = document.getElementById('scheme'); colorScheme = parseInt((a.value || a.options[a.selectedIndex].value)); //save canvas size into variable cw = canvas.width; ch = canvas.height; //define scaling ratio from canvas coordinat to mandlebort coordinat scaleX = (mx[1] - mx[0])/cw; scaleY = (my[1] - my[0])/ch; drawMandlebrot(); };
- Define the [cci]drawMandelbrot[/cci] function.
In this function, we iterate to each pixels in the canvas and find the iteration for each pixels then color the pixel based on number iterations.var drawMandlebrot = function() { if(isDrawing) return; isDrawing = true; var imageData = ctx.getImageData(0, 0, cw, ch); pixels = imageData.data; for(var x = 0; x = 2*2) { break; } // multiply z and z z = new Complex(z.x*z.x - z.y*z.y, z.y*z.x + z.x*z.y); // add z and c z = new Complex(z.x+c.x, z.y+c.y); // inrease iteration iteration++; } // colorize current pixel setPixelColor(x, y, iteration); } } ctx.putImageData(imageData, 0, 0); isDrawing = false; };
- Define [cci]setPixelColor[/cci]
This function will color the current pixels and get the color from [cci]getColor[/cci] function. [cci]getColor[/cci] function will generate a color based on number of iteration and selected color scheme.var getColor = function(i) { i /= maxIteration; var cr = 0.0; var cg = 0.0; var cb = 0.0; switch(colorScheme) { case 1: if (i >= 0.66) cr = i; else if (i >= 0.33) cg = i; else cb = i; break; case 2: if (i >= 0.66) cr = i; else if (i >= 0.33) cb = i; else cg = i; break; case 3: if (i >= 0.66) cb = i; else if (i >= 0.33) cg = i; else cr = i; break; case 4: if (i >= 0.66) cg = i; else if (i >= 0.33) cr = i; else cb = i; break; case 5: if (i >= 0.66) cg = i; else if (i >= 0.33) cb = i; else cr = i; break; case 6: if (i >= 0.66) cb = i; else if (i >= 0.33) cr = i; else cg = i; break; }; var r = parseInt(cr * 3 * maxColor); var g = parseInt(cg * 3 * maxColor); var b = parseInt(cb * 3 * maxColor); return [r, g, b]; }; var setPixelColor = function(x, y, i) { var c = getColor(i); var off = 4 * (y * cw + x); pixels[off] = c[0]; //red pixels[off + 1] = c[1]; //green pixels[off + 2] = c[2]; //blue pixels[off + 3] = 255; //alpha };
- Finally, add the zoom capability.
var mouseWheelHandler = function(e) { // cross-browser wheel delta var e = window.event || e; // old IE support // get delta scroll var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); //get mouse position var mousePos = getMousePos(e); // scale canvas coordinat to mandlebrot complex coordinat var x0 = scaleX*mousePos.x + mx[0], y0 = scaleY*mousePos.y + my[0]; //scale the mandelbrot coordinat size var scale = 1 - delta*zoomScale; var sizeX = (mx[1]-mx[0])*scale; var sizeY = (my[1]-my[0])*scale; // redefine mandelbrot boundaries mx = [x0-sizeX/2, x0+sizeX/2]; my = [y0-sizeY/2, y0+sizeY/2]; render(); }; var getMousePos = function(evt) { var rect = canvas.getBoundingClientRect(); return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; };
Final Source Code
Drawing Mandelbrot set on HTML5 graphics canvas