Skip to content

Instantly share code, notes, and snippets.

@lachezar
Created June 13, 2011 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lachezar/1023445 to your computer and use it in GitHub Desktop.
Save lachezar/1023445 to your computer and use it in GitHub Desktop.
Mandelbrot + Web Workers
<!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>
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