Html 5 Canvas绘制分形图Mandelbrot

为了测试一下js和Canvas的计算能力,做了一个Mandelbrot的分形图,支持鼠标Zoom In。Mandelbrot的定义很简单,虚数平面的每个点(x,y),通过反复计算zn+1 = zn2 + c,z0 = 0。只有结果收敛才属于Mandelbrot,否则根据n的设定一个颜色,越大越深,代表接近属于集合的点,可以把集合中的点理解为n=无穷大。推荐在chrome中打开本页,还支持firefox和ie9。 拖动鼠标可以明显发现chrome是最流畅的。

更为专业的Mandelbrot请check这里 http://www.atopon.org/mandel/

Your browser does not support the canvas element.


<canvas id="canvas" width="600" height="480" style="margin-left:100px">
<p>Your browser does not support the canvas element.</p>
</canvas>
<p><input id="reset" type="button" value="Reset" /></p>

<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var width = canvas.width ,height = canvas.height;
var maxIterations = 100;
var minRe = -2.0;
var maxRe = 1.0;
var minIm = -1;
var maxIm = minIm+(maxRe-minRe)*height/width;

reset();

document.getElementById(
"reset").onclick = reset;

canvas.onmousedown
= function (evt) {
var x0 = evt.pageX - canvas.offsetLeft;
var y0 = evt.pageY - canvas.offsetTop;

var x1, y1, w, h;
var imgd = context.getImageData(0, 0, width, height);

update(evt);

function update(evt) {
x1
= evt.pageX - canvas.offsetLeft;
y1
= evt.pageY - canvas.offsetTop;
w
= Math.abs(x1 - x0), h = Math.abs(y1 - y0);
}

function clear(evt) {
if (w && h) {
context.clearRect(
0, 0, width, height);
context.putImageData(imgd,
0, 0);
}
}

canvas.onmousemove
= function (evt) {
clear(evt);
update(evt);
context.strokeStyle
= "red";
context.strokeRect(x0
< x1 ? x0 : x1, y0 < y1 ? y0 : y1, w, h);
}

canvas.onmouseup
= function (evt) {
clear(evt);
canvas.onmousemove
= canvas.onmouseup = null;

minRe
= minRe + (maxRe - minRe) / width * (x0 < x1 ? x0 : x1);
maxRe
= minRe + (maxRe - minRe) / width * w;
minIm
= minIm + (maxIm - minIm) / height * (y0 < y1 ? y0 : y1);
maxIm
= minIm + (maxIm - minIm) / height * h;

draw();
}
}

function reset() {
minRe
= -2.0;
maxRe
= 1.0;
minIm
= -1;
maxIm
= minIm + (maxRe - minRe) * height / width;
draw();
}

function draw() {
context.fillRect(
0, 0, width, height);
var imgd = context.getImageData(0, 0, width, height)
var pix = imgd.data;

var drawPixel = function (x, y, itr) {
var i = (y * width + x) * 4;

pix[i]
= pix[i + 1] = pix[i + 2] = Math.round(itr * 255 / maxIterations);
}

mandelbrot(width, height, drawPixel);
context.putImageData(imgd,
0, 0);
}

function mandelbrot(imageWidth, imageHeight, drawPixel) {
var re_factor = (maxRe-minRe)/(imageWidth-1);
var im_factor = (maxIm-minIm)/(imageHeight-1);

for(var y=0; y<imageHeight; ++y)
{
var c_im = maxIm - y*im_factor;
for(var x=0; x<imageWidth; ++x)
{
var c_re = minRe + x*re_factor;

var z_re = c_re, z_im = c_im;
var isInside = true;
var n = 0;
for(; n<maxIterations; ++n)
{
var z_re2 = z_re*z_re, z_im2 = z_im*z_im;
if(z_re2 + z_im2 > 4)
{
isInside
= false;
break;
}
z_im
= 2*z_re*z_im + c_im;
z_re
= z_re2 - z_im2 + c_re;
}

if (!isInside) { drawPixel(x, y, n); }
}
}
}
</script>
posted @ 2011-05-26 22:46 dragonpig 阅读(...) 评论(...) 编辑 收藏