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/
<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>