Created
June 13, 2011 19:01
-
-
Save lachezar/1023445 to your computer and use it in GitHub Desktop.
Mandelbrot + Web Workers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Mandelbrot + Web Workers!</title> | |
</head> | |
<body> | |
<canvas id="canvas" width="800" height="600" style="float: left">There should be a canvas here?!</canvas> | |
<script type="text/javascript"> | |
var workers = []; | |
const poolCount = 8*6; | |
var busyWorkers = 0; | |
for (var i = 0; i < poolCount; i++) { | |
var worker = new Worker('worker.js'); | |
worker.id = i; | |
worker.onmessage = function(e) { | |
var pixels = e.data; | |
putPixels(this.id, pixels); | |
busyWorkers--; | |
updateWorkersCount(); | |
} | |
workers.push(worker); | |
} | |
var canvas = document.getElementById('canvas'); | |
var context = canvas.getContext('2d'); | |
context.fillStyle = "rgb(0,0,0)"; | |
context.fillRect(0, 0, canvas.width, canvas.height); | |
const maxWidth = 100; | |
const maxHeight = 100; | |
const columns = canvas.width / maxWidth; | |
const rows = canvas.height / maxHeight; | |
var zoomLevel = 1.0; | |
var lastZoom = 1.0; | |
var cx = 0; | |
var cy = 0; | |
var cxz = 0; | |
var cyz = 0; | |
draw(zoomLevel, 0, 0); | |
function putPixels(id, pixels) { | |
context.putImageData(pixels, (id%columns)*maxWidth, parseInt(id/columns)*maxHeight); | |
} | |
function draw(zoomLevel, cx, cy) { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < columns; j++) { | |
var pixels = context.getImageData(j*maxWidth, i*maxHeight, maxWidth, maxHeight); | |
workers[i*columns+j].postMessage({pixels: pixels, sx: j*maxWidth+cx, sy: i*maxHeight+cy, w: maxWidth, h: maxHeight, canvasWidth: canvas.width, canvasHeight: canvas.height, zoom: zoomLevel}); | |
busyWorkers++; | |
} | |
} | |
} | |
canvas.onmousedown = function(e) { | |
if (cxz != 0 && cyz != 0) { | |
cx = cy = 0; | |
lastZoom = 1; | |
} | |
cx += cxz+(e.pageX-canvas.width/2); | |
cy += cyz+(e.pageY-canvas.height/2); | |
draw(zoomLevel, cx, cy); | |
cxz = cyz = 0; | |
} | |
canvas.addEventListener('DOMMouseScroll', zoom, false); | |
function zoom(e) { | |
var k = e.detail < 0 ? 2 : 0.5; | |
zoomLevel *= k; | |
lastZoom *= k; | |
cxz = (cx+canvas.width/2)*lastZoom-canvas.width/2; | |
cyz = (cy+canvas.height/2)*lastZoom-canvas.height/2; | |
context.save(); | |
if (e.detail < 0) { | |
context.scale(k, k); | |
context.drawImage(canvas, -canvas.width/4, -canvas.height/4); | |
} | |
draw(zoomLevel, cxz, cyz); | |
context.restore(); | |
updateZoomLevel(); | |
} | |
function updateWorkersCount() { | |
document.getElementById('workers_count').innerHTML = busyWorkers; | |
} | |
function updateZoomLevel() { | |
document.getElementById('zoom_level').innerHTML = zoomLevel; | |
} | |
</script> | |
<div style="float: left; margin-left: 10px;"> | |
<div> | |
Workers: <span id="workers_count">0</span> | |
</div> | |
<div> | |
Zoom: <span id="zoom_level">1</span> | |
</div> | |
<div> | |
Click on the image to navigate through it. Scroll with the mouse for zoom. | |
</div> | |
<div> | |
<a href="http://en.wikipedia.org/wiki/Mandelbrot_set" target="_blank">About Mandelbrot set</a> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onmessage(e) { | |
var newPixels = calc(e.data); | |
postMessage(newPixels); | |
} | |
function calc(data) { | |
var pixels = data.pixels; | |
var sx = data.sx; | |
var sy = data.sy; | |
var w = data.w; | |
var h = data.h; | |
var canvasWidth = data.canvasWidth; | |
var canvasHeight = data.canvasHeight; | |
var zoom = data.zoom; | |
var minRe = -2.0; | |
var maxRe = 1.0; | |
var minIm = -1.2; | |
var maxIm = minIm + (maxRe - minRe) * canvasHeight / canvasWidth; | |
var reFactor = (maxRe - minRe) / (canvasWidth - 1); | |
var imFactor = (maxIm - minIm) / (canvasHeight - 1); | |
var maxIterations = 4096; | |
for (var y = sy; y < sy+h; y++) { | |
var cim = maxIm - ((y) * imFactor)/zoom; | |
for (var x = sx; x < sx+w; x++) { | |
var cre = minRe + ((x) * reFactor)/zoom; | |
var zre = cre; | |
var zim = cim; | |
var k = 0; | |
for(k = 0; k < maxIterations; k++) { | |
if (zre*zre + zim*zim > 4) { | |
break; | |
} | |
var tempZre = zre*zre - zim*zim + cre; | |
zim = 2 * zre * zim + cim; | |
zre = tempZre; | |
} | |
plot(pixels, x-sx, y-sy, 4096 - Math.min(k, maxIterations)); | |
} | |
} | |
return pixels; | |
} | |
function plot(pixels, x, y, color) { | |
var offset = 4 * pixels.width * y + 4 * x; | |
pixels.data[offset+0] = (color & 16)*16; | |
pixels.data[offset+1] = ((color >> 4) & 16)*16; | |
pixels.data[offset+2] = ((color >> 8) & 16)*16; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment