algorytm.org

Implementacja w JavaScript

Baza Wiedzy
wersja offline serwisu przeznaczona na urządzenia z systemem Android
Darowizny
darowiznaWspomóż rozwój serwisu
Nagłówki RSS
Artykuły
Implementacje
Komentarze
Forum
Bookmarki






Sonda
Implementacji w jakim języku programowania poszukujesz?

Zbiór Mandelbrot'a - Implementacja w JavaScript
Ocena użytkownikóww: *****  / 3
SłabyŚwietny
Nadesłany przez Tomasz Lubiński, 05 maja 2011 21:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.
Pobierz pełne rozwiązanie.

Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.

mandelbrot.js:
//Mandelbrot
//(c) 2011 by Tomasz Lubinski
//www.algorytm.org

/* Render area coordinates */
var minX = -2.0;
var maxX =  0.5;
var minY = -1.25;
var maxY =  1.25;

/* Render area size */
var width = 0;
var height = 0;
var ratioX;
var ratioY;

/* Number of fractal levels */
var levelNum = 100;
var colors = new Array(levelNum+1);

/* Fractal image */
var imageData;
var canvas;
var ctx;
	
/* Selection data*/
var selectionStarted = false;
var selectStartX, selectStartY, selectStopX, selectStopY;

/* signum function */
function sgn(x){
  if(x>0)return 1;
  else if(x<0)return -1;
  else return 0;
}

/* store where selection has started */
function startSelect(e)
{
	if (e.button == 0)
	{
		/* left mouse button - select operation */
		selectionStarted = true;
		if (e.offsetX || e.offsetX == 0) 
		{
			selectStartX = e.offsetX;
			selectStopX = e.offsetX;
			selectStartY = e.offsetY;
			selectStopY = e.offsetY;				
		}
		else
		{
			selectStartX = e.layerX;
			selectStopX = e.layerX;
			selectStartY = e.layerY;
			selectStopY = e.layerY;
		}
	}
	else
	{
		/* right mouse button - reset operation */
		selectStartX = 0;
		selectStopX = 0;
		selectStartY = 0;
		selectStopY = 0;
		minX = -2.0;
		maxX =  0.5;
		minY = -1.25;
		maxY =  1.25;		
		ratioX = (maxX - minX) / width;
		ratioY = (maxY - minY) / height;
		renderFractal();
	}
}

/* selection has stopped, render new fractal */
function stopSelect(e)
{
	selectionStarted = false;
	if (selectStartX != selectStopX && selectStartY != selectStopY)
	{
		maxX = Math.max(selectStartX, selectStopX)*ratioX + minX;
		minX = Math.min(selectStartX, selectStopX)*ratioX + minX;
		maxY = Math.max(selectStartY, selectStopY)*ratioY + minY;
		minY = Math.min(selectStartY, selectStopY)*ratioY + minY;
		ratioX = (maxX - minX) / width;
		ratioY = (maxY - minY) / height;
		renderFractal();
	}
}

/* mouse is outside render area, cancel selection */
function clearSelect(e)
{
	if (selectionStarted)
	{
		canvas.width = canvas.width;
		ctx.putImageData(imageData, 0, 0);	
	}
	selectionStarted = false;
}

/* mouse is moving inside render area, show selection rectangle */
function moveSelect(e)
{
	if (selectionStarted)
	{
		if (e.offsetX || e.offsetX == 0) 
		{
			selectStopX = e.offsetX;
			selectStopY = e.offsetY;			
		}
		else
		{
			selectStopX = e.layerX;
			selectStopY = e.layerY;
		}
		canvas.width = canvas.width; /* clear canvas */
		ctx.putImageData(imageData, 0, 0); /* put fractal on the canvas */
		if (selectStartX != selectStopX && selectStartY != selectStopY)
		{
			/* make sure that selection area has the same ratio as original area */
			if (width/height < Math.abs(selectStartX-selectStopX)/Math.abs(selectStartY-selectStopY))
			{
				selectStopY = selectStartY+sgn(selectStopY-selectStartY)*height*Math.abs(selectStartX-selectStopX)/width;
			}
			else
			{
				selectStopX = selectStartX+sgn(selectStopX-selectStartX)*width*Math.abs(selectStartY-selectStopY)/height;
			}
			/* put select rectangle on the canvas */
			ctx.fillStyle = 'rgba(100,200,300,0.5)';
			ctx.fillRect(Math.min(selectStartX, selectStopX), Math.min(selectStartY, selectStopY), Math.abs(selectStartX-selectStopX), Math.abs(selectStartY-selectStopY));
		}
	}
}

/* initialize color table */
function initializeColors()
{
	for (var level=0; level<=levelNum; level++)
	{
		colors[level] = new Object();
		colors[level].r = 255.0*level/levelNum;
		colors[level].g = 255.0*level/levelNum;
		colors[level].b = 255.0*Math.log(level)/Math.log(levelNum);
	}
}

/* value is inside set in the returned level */
function levelSet(p_re, p_im)
{
	var z_re = 0;
	var z_im = 0;
	var iteration = 0;
	var tmp_re, tmp_im;

	do
	{
		tmp_re = z_re*z_re - z_im*z_im + p_re;
		tmp_im = 2*z_re*z_im + p_im;
		z_re = tmp_re;
		z_im = tmp_im;
		iteration++;		
	} while ((z_re*z_re+z_im*z_im) < 4 && iteration < levelNum);

	return iteration;
}

/* render Fractal */
function renderFractal()
{
	for (var i=0; i<height; i++)
	{
		p_im = i*ratioY + minY;
		for (var j=0; j<width; j++)
		{
			p_re = j*ratioX + minX;
			index = (i*width+j)*4;
			imageData.data[index+3] = 0xff;
			level = levelSet(p_re, p_im);
			imageData.data[index+0] = colors[level].r;
			imageData.data[index+1] = colors[level].g;
			imageData.data[index+2] = colors[level].b;
		}
	}
	
	// copy the image data back onto the canvas
	ctx.putImageData(imageData, 0, 0);
}

/* touch handler for devices with touch screen */
function touchHandler(event)
{
	var touches = event.changedTouches,
	first = touches[0],
	type = "";
	switch(event.type)
	{
		case "touchstart": type = "mousedown"; break;
		case "touchmove":  type = "mousemove"; break;        
		case "touchend":   type = "mouseup"; break;
		default: return;
	}    
	if (touches.length > 1)
	{
		type = "mousedown";
	}
	var simulatedEvent = document.createEvent("MouseEvent");
	simulatedEvent.initMouseEvent(type, true, true, window, 1, 
		first.screenX, first.screenY, 
		first.clientX, first.clientY, false, 
		false, false, false, touches.length-1, null);
	first.target.dispatchEvent(simulatedEvent);
	event.preventDefault();
}

/* initialize environment and render Fractal */
function initializeFractal()
{
	canvas = document.getElementById("canvas");
	ctx = canvas.getContext("2d");
	
	canvas.onmousemove = moveSelect;
	canvas.onmousedown = startSelect;
	canvas.onmouseup = stopSelect;
	canvas.onmouseout = clearSelect;

	//support for mobile devices with touch screen
	if ("ontouchstart" in document.documentElement)
	{
		canvas.ontouchstart = touchHandler;
		canvas.ontouchmove = touchHandler;
		canvas.ontouchend = touchHandler;
	}

	// read the width and height of the canvas
	width = canvas.width;
	height = canvas.height;

	// create a new pixel array
	imageData = ctx.createImageData(width, height);
	
	ratioX = (maxX - minX) / width;
	ratioY = (maxY - minY) / height;
	
	initializeColors();
	renderFractal();
}
Dodaj komentarz