为了测试一下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>