factory/v2012/script.js
author Eugen Sawin <sawine@me73.com>
Thu, 05 Jan 2012 17:03:06 +0100
changeset 80 ba69edadfc4c
parent 79 72b5c635d6df
child 81 a76b2fb0f21f
permissions -rw-r--r--
Stuff.
     1 var QUOTES_NUMBER = 39;
     2 var SERVER = "http://" + window.location.hostname + ":" + window.location.port;
     3 var simulation;
     4 var gameoflife;
     5 
     6 $(document).ready(function() {   
     7     simulation = new Simulation(document.getElementById("sim"), 670, 50);  
     8     var image = new Image();
     9     image.onload = init_logo;
    10     image.src = "images/logobase.png";
    11     $("#logo").click(handle_click);   
    12     $("#logo").hover(function() {
    13         $(this).css("cursor", "pointer");        
    14     }, function() {
    15         $(this).css("cursor", "auto");
    16     });
    17     $("#sim").mousemove(function(event) { simulation.mouse_moved(mouse_pos(event, "#sim")); });
    18     var onEachFrame;
    19     if (window.webkitRequestAnimationFrame) {
    20         onEachFrame = function(cb) {
    21             var _cb = function() { cb(); webkitRequestAnimationFrame(_cb); }
    22             _cb();
    23         };
    24     } else if (window.mozRequestAnimationFrame) {
    25         onEachFrame = function(cb) {
    26             var _cb = function() { cb(); mozRequestAnimationFrame(_cb); }
    27             _cb();
    28         };
    29     } else {
    30         onEachFrame = function(cb) {
    31             setInterval(cb, 1000 / 30);
    32         }
    33     }    
    34     window.onEachFrame = onEachFrame;   
    35     window.onEachFrame(update);    
    36 });
    37 
    38 $(document).keypress(function(event) {
    39     if (event.which == 13) {      
    40 	event.preventDefault();
    41         update_logo();	    
    42     }
    43 });
    44 
    45 var menu_width = 670;
    46 var menu_height = 100;
    47 var menu_splits = new Array(180, 350, 505);
    48 
    49 var click_events = new Array();
    50 click_events["logo"] = new Array();
    51 click_events["logo"][0] = new Object();
    52 click_events["logo"][0]["min_x"] = 0;
    53 click_events["logo"][0]["max_x"] = menu_splits[0];
    54 click_events["logo"][0]["min_y"] = 0;
    55 click_events["logo"][0]["max_y"] = menu_height;
    56 click_events["logo"][0]["func"] = switch_page;
    57 click_events["logo"][0]["args"] = new Array("personalwork.html");
    58 click_events["logo"][1] = new Object();
    59 click_events["logo"][1]["min_x"] = menu_splits[0] + 1;
    60 click_events["logo"][1]["max_x"] = menu_splits[1];
    61 click_events["logo"][1]["min_y"] = 0;
    62 click_events["logo"][1]["max_y"] = menu_height;
    63 click_events["logo"][1]["func"] = switch_page;
    64 click_events["logo"][1]["args"] = new Array("howiwork.html");
    65 click_events["logo"][2] = new Object();
    66 click_events["logo"][2]["min_x"] = menu_splits[1] + 1;
    67 click_events["logo"][2]["max_x"] = menu_splits[2];
    68 click_events["logo"][2]["min_y"] = 0;
    69 click_events["logo"][2]["max_y"] = menu_height;
    70 click_events["logo"][2]["func"] = switch_page;
    71 click_events["logo"][2]["args"] = new Array("books.html");
    72 click_events["logo"][3] = new Object();
    73 click_events["logo"][3]["min_x"] = menu_splits[2] + 1;
    74 click_events["logo"][3]["max_x"] = menu_width - 1;
    75 click_events["logo"][3]["min_y"] = 0;
    76 click_events["logo"][3]["max_y"] = menu_height;
    77 click_events["logo"][3]["func"] = switch_page;
    78 click_events["logo"][3]["args"] = new Array("links.html", "linksend.html");
    79 
    80 function mouse_pos(event, id) { 
    81     var offset = $(id).offset();   
    82     return new Array(event.pageX - offset.left, 
    83                      event.pageY - offset.top);
    84 }
    85 
    86 function handle_click(event) {
    87     var xy = mouse_pos(event, "#logo");
    88     var x = xy[0];
    89     var y = xy[1];
    90     for (var i in click_events[event.target.id]) {
    91         var ces = click_events[event.target.id][i];
    92         if (ces && x >= ces["min_x"] && x <= ces["max_x"]
    93             && y >= ces["min_y"] && y <= ces["max_y"]) {    
    94             ces["func"](event.target.id, ces);
    95             break;
    96         }
    97     }
    98 }
    99 
   100 function switch_page(id, params) {
   101     var page = params["args"][0];
   102     $("body").load(page);
   103     document.location.href = page;    
   104 }
   105 
   106 function colour_area(image, min_x, max_x, min_y, max_y, colour) {   
   107     var pixels = image.data;    
   108     for (var y = min_y; y <= max_y; y += 1) {
   109         for (var x = min_x; x <= max_x; x += 1) {
   110             var pix_colour = getPixel(image, x, y);
   111             if (pix_colour.a > 0) {
   112                 colour.a = pix_colour.a;
   113                 setPixel(image, x, y, colour);
   114             }
   115         }
   116     }    
   117 }
   118 
   119 function init_logo(event) {
   120     var canvas = document.getElementById("logo");
   121     var context = canvas.getContext("2d");    
   122     canvas.width = menu_width;
   123     canvas.height = menu_height;
   124     context.drawImage(event.target, 0, 0);
   125     var image = context.getImageData(0, 0, menu_width, menu_height);    
   126     for (var i in click_events["logo"]) {
   127         var p = click_events["logo"][i]; 
   128         var min_x = p["min_x"];
   129         var max_x = p["max_x"];
   130         var min_y = p["min_y"];
   131         var max_y = p["max_y"];
   132         var pos = document.location.href.lastIndexOf("/") + 1; 
   133         var page = document.location.href.substr(pos);        
   134         for (var j in p["args"]) {
   135             if (page == p["args"][j]) {         
   136                 colour_area(image, min_x, max_x, 0, 60, black);
   137                 colour_area(image, min_x, max_x, 60, max_y, white);
   138                 break;
   139             }
   140             else {
   141                 colour_area(image, min_x, max_x, 0, 60, white);
   142                 colour_area(image, min_x, max_x, 60, max_y,  orange);  
   143             }
   144         }       
   145     } 
   146     context.putImageData(image, 0, 0);      
   147     // context.fillStyle = green.str();
   148     // console.log((found["max_x"] - found["min_x"]) / 2 + found["min_x"] - 2);
   149     // context.fillRect((found["max_x"]-found["min_x"])/2+found["min_x"]-1, 95, 2, 5);  
   150     draw_menu_lines();   
   151 }
   152 
   153 function draw_menu_lines() {
   154     var canvas = document.getElementById("logo");
   155     var context = canvas.getContext("2d");  
   156     var image = context.getImageData(0, 0, menu_width, menu_height);
   157     var pixels = image.data;
   158     context.lineCap = "round";
   159     context.lineWidth = 1;
   160     var colour1a = new Colour(0, 0, 0, 0.1);
   161     context.beginPath();   
   162     context.moveTo(0, menu_height - 1);
   163     context.lineTo(menu_width - 1, menu_height - 1);   
   164     context.closePath();  
   165     context.strokeStyle = colour1a.str();
   166     context.stroke(); 
   167     var colour1e = new Colour(0, 0, 0, 0.05);  
   168     context.beginPath();   
   169     context.moveTo(70, menu_height - 1);
   170     context.lineTo(menu_width - 71, menu_height - 1);   
   171     context.closePath();  
   172     context.strokeStyle = colour1e.str();
   173     context.stroke();  
   174     var colour1b = new Colour(0, 0, 0, 0.05);  
   175     context.beginPath();   
   176     context.moveTo(50, menu_height - 1);
   177     context.lineTo(menu_width - 51, menu_height - 1);   
   178     context.closePath();  
   179     context.strokeStyle = colour1b.str();
   180     context.stroke();
   181     var colour1c = new Colour(0, 0, 0, 0.05);  
   182     context.beginPath();   
   183     context.moveTo(25, menu_height - 1);
   184     context.lineTo(menu_width - 26, menu_height - 1);   
   185     context.closePath();  
   186     context.strokeStyle = colour1c.str();
   187     context.stroke();
   188     var colour1d = new Colour(0, 0, 0, 0.05);  
   189     context.beginPath();   
   190     context.moveTo(10, menu_height - 1);
   191     context.lineTo(menu_width - 11, menu_height - 1);   
   192     context.closePath();  
   193     context.strokeStyle = colour1d.str();
   194     context.stroke();  
   195     
   196     var colour2 = new Colour(0, 0, 0, 0.2);
   197     context.beginPath();  
   198     context.moveTo(menu_splits[0], 0); 
   199     context.lineTo(menu_splits[0], menu_height - 1);
   200     context.moveTo(menu_splits[1], 0);
   201     context.lineTo(menu_splits[1], menu_height - 1);
   202     context.moveTo(menu_splits[2], 0);
   203     context.lineTo(menu_splits[2], menu_height - 1);
   204     context.closePath();
   205     context.strokeStyle = colour2.str();
   206     context.stroke();
   207 
   208     context.clearRect(menu_splits[0] - 1, menu_height - 1, 2, 2);
   209     context.clearRect(menu_splits[1] - 1, menu_height - 1, 2, 2);
   210     context.clearRect(menu_splits[2] - 1, menu_height - 1, 2, 2);
   211 
   212     context.clearRect(menu_splits[0] - 1, menu_height - 2, 1, 1);
   213     context.clearRect(menu_splits[1] - 1, menu_height - 2, 1, 1);
   214     context.clearRect(menu_splits[2] - 1, menu_height - 2, 1, 1);
   215 }
   216 
   217 function clearMenuLines() {
   218     var canvas = document.getElementById("logo");
   219     var context = canvas.getContext("2d");  
   220     var image = context.getImageData(0, 0, menu_width, menu_height);
   221     var pixels = image.data;
   222     context.clearRect(0, menu_height - 2, menu_width - 1, 2);
   223     context.clearRect(menu_splits[0] - 1, 0, 2, menu_height - 1);
   224     context.clearRect(menu_splits[1] - 1, 0, 2, menu_height - 1);
   225     context.clearRect(menu_splits[2] - 1, 0, 2, menu_height - 1);
   226 }
   227 
   228 function draw_sim_lines() {
   229     var w = 670;
   230     var h = 50;
   231     var canvas = document.getElementById("sim");
   232     var context = canvas.getContext("2d");  
   233     var image = context.getImageData(0, 0, w, h);
   234     var pixels = image.data;
   235     context.lineCap = "round";
   236     context.lineWidth = 1;
   237     var colour1a = new Colour(0, 0, 0, 0.1);
   238     context.beginPath();   
   239     context.moveTo(0, h - 1);
   240     context.lineTo(w - 1, h - 1);   
   241     context.closePath();  
   242     context.strokeStyle = colour1a.str();
   243     context.stroke(); 
   244    
   245     var colour1b = new Colour(0, 0, 0, 0.05);  
   246     context.beginPath();   
   247     context.moveTo(50, h - 1);
   248     context.lineTo(w - 51, h - 1);   
   249     context.closePath();  
   250     context.strokeStyle = colour1b.str();
   251     context.stroke();
   252    
   253     var colour1d = new Colour(0, 0, 0, 0.05);  
   254     context.beginPath();   
   255     context.moveTo(10, h - 1);
   256     context.lineTo(w - 11, h - 1);   
   257     context.closePath();  
   258     context.strokeStyle = colour1d.str();
   259     context.stroke();   
   260 }
   261 
   262 function update_logo() {
   263     var canvas = document.getElementById("logo");
   264     var context = canvas.getContext("2d");  
   265     var image = context.getImageData(0, 0, menu_width, menu_height);
   266     var pixels = image.data;
   267     var white = new Colour(255, 255, 255);
   268     for (var y = 0; y < menu_height; y += 1) {
   269         for (var x = 0; x < menu_width; x += 1) {
   270             var pix_colour = getPixel(image, x, y);
   271             if (pix_colour.a > 0) {
   272                 setPixel(image, x, y, new Colour(90, 215, 21, pix_colour.a));
   273             }
   274         }
   275     }   
   276     context.putImageData(image, 0, 0);
   277 }
   278 
   279 function init_gameoflife() {
   280     var canvas = document.getElementById("gameoflife"); alert("h");
   281     if (cavans) {
   282         gameoflife = new Simulation(canvas, 670, 670);
   283         $("#gameoflife").mousemove(function(event) { 
   284             gameoflife.mouse_moved(mouse_pos(event, "#gameoflife")); 
   285         });
   286         alert("h");
   287     }
   288 }
   289 
   290 function Colour(r, g, b, a) {
   291     this.r = r;
   292     this.g = g;
   293     this.b = b;
   294     this.a = a == undefined ? 255 : a;
   295 }
   296 Colour.prototype.equals = function(rhs) {
   297     for (p in this) {
   298         if (typeof(rhs[p]) == undefined
   299            || this[p] != rhs[p]) {           
   300             return false;
   301         }
   302     }
   303     return true;
   304 }
   305 Colour.prototype.str = function() {
   306     return "rgba(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")";
   307 }
   308 
   309 var white = new Colour(255, 255, 255);
   310 var black = new Colour(0, 0, 0);
   311 var orange = new Colour(201, 87, 35);
   312 var green = new Colour(90, 215, 21);
   313 var background = new Colour(34, 34, 34);
   314 
   315 function setPixel(image, x, y, colour) {
   316     var index = 4 * (x + y * image.width);
   317     image.data[index] = colour.r;
   318     image.data[index + 1] = colour.g;
   319     image.data[index + 2] = colour.b;
   320     image.data[index + 3] = colour.a;
   321 }
   322 
   323 function getPixel(image, x, y) {   
   324     var index = 4 * (x + y * image.width);
   325     var r = image.data[index];
   326     var g = image.data[index + 1];
   327     var b = image.data[index + 2];
   328     var a = image.data[index + 3];
   329     return new Colour(r, g, b, a);
   330 }
   331 
   332 function load_random_quote() {
   333     var file = "/quotes/quote" + Math.floor(Math.random() * QUOTES_NUMBER + 1) + ".html";
   334     $.ajax({url: SERVER + file,
   335             success: write_quote});
   336 }
   337 
   338 function write_quote(data, status, xhr) {   
   339     $("#random_quote").html(data);
   340 }
   341 
   342 function load_footer()
   343 {
   344 	var file = "/footer.html";
   345 	var currentFile = self.location.hostname + self.location.pathname;		
   346 	var request = http_request_object();
   347 	var url  = "http://" + self.location.hostname + file;	
   348 	request.open("GET", url, false);
   349 	request.setRequestHeader("User-Agent", navigator.userAgent);
   350 	request.send(null)
   351 	// if (oRequest.status == 200) alert(oRequest.responseText);
   352 	// else alert("Error executing XMLHttpRequest call!");	
   353 	//document.write(url);
   354 	//document.write(request.responseText);
   355     document.getElementById('footer').innerHTML = request.responseText;
   356 }
   357 
   358 
   359 
   360 // Mandelbrot functions
   361 function Complex(real, imag) 
   362 {
   363 	this.real = real;
   364 	this.imag = imag;
   365 }
   366 
   367 var MIN_C = new Complex(-2.2, -1.4);
   368 var MAX_C = new Complex(1.0, 1.4);
   369 var min_c = MIN_C;
   370 var max_c = MAX_C;
   371 var MIN_ITER = 100;
   372 var max_iter = MIN_ITER;
   373 var zoom = 1.0;
   374 var resolution = 3;
   375 var bailout = 4.0;
   376 
   377 function Result(z, iter) 
   378 {
   379 	this.z = z;
   380 	this.iter = iter;
   381 }
   382 
   383 function complex_quad(c)
   384 {
   385 	return new Complex(Math.pow(c.real, 2) - Math.pow(c.imag, 2), 
   386 		2.0 * c.real * c.imag);
   387 }
   388 
   389 function complex_quad_value(c)
   390 {
   391 	return Math.pow(c.real, 2) + Math.pow(c.imag, 2);
   392 }
   393 
   394 function complex_add(c1, c2)
   395 {
   396 	return new Complex(c1.real + c2.real, c1.imag + c2.imag);
   397 }
   398 
   399 function complex_equal(c1, c2)
   400 {	
   401 	return (c1.real == c2.real) && (c1.imag == c2.imag);
   402 }
   403 
   404 function iterate(z, c) 
   405 {
   406 	z_quad = complex_quad(z);
   407 	return new Complex(z_quad.real + c.real, z_quad.imag + c.imag);
   408 }
   409 
   410 function test(c, max_iter) 
   411 {
   412 	var iter = 0;
   413 	var z = new Complex(0.0, 0.0);
   414 	var last_z = new Complex(-1.0, 0.0);
   415 	var quad_z = complex_quad_value(z);
   416 	
   417 	while (iter < max_iter
   418 		&& !complex_equal(z, last_z)
   419 		&& quad_z <= bailout)
   420 	{
   421 		last_z = z;
   422 		z = iterate(z, c);
   423 		quad_z = complex_quad_value(z);
   424 		iter++;
   425 	}
   426 	return new Result(quad_z, iter);
   427 }
   428 
   429 function draw(diter, dx, dy, dz, dres)
   430 {  
   431 	var canvas = document.getElementById('mandelbrot'); 
   432 	
   433 	if (canvas.getContext)
   434 	{  
   435 		zoom += dz;
   436 		var ctx = canvas.getContext('2d');
   437 
   438 		if (dres != 0)
   439 		{		
   440 			resolution = Math.max(1, resolution + dres);
   441 		}
   442 
   443 		if (diter != 0)
   444 		{
   445 			max_iter = Math.max(MIN_ITER, max_iter + diter);
   446 		}
   447 		
   448 		var red = "rgb(255, 0, 0)";
   449 		var white = "rgb(255, 255, 255)";
   450 		var width = canvas.width;
   451 		var height = canvas.height;
   452 		var dim = Math.max(width, height);
   453 		var dim_ratio = Math.round(width / height);	
   454 		var diff_c = new Complex(max_c.real - min_c.real,
   455 			max_c.imag - min_c.imag);
   456 		dx_min = diff_c.real / 100 * (dx + dz);
   457 		dx_max = diff_c.real / 100 * (dx - dz);
   458 
   459 		dy_min = diff_c.imag / 100 * (dy + dz);
   460 		dy_max = diff_c.imag / 100 * (dy - dz);
   461 
   462 		var min_inc = new Complex(dx_min * dim_ratio / 2.0, dy_min);
   463 		var max_inc = new Complex(dx_max * dim_ratio / 2.0, dy_max);
   464 		min_c = complex_add(min_c, min_inc);
   465 		max_c = complex_add(max_c, max_inc);
   466 		diff_c = new Complex(max_c.real - min_c.real,
   467 			max_c.imag - min_c.imag);
   468 		
   469 		for (var y = 0; y < height; y += resolution) 
   470 		{
   471 			for (var x = 0; x < width; x += resolution) 
   472 			{    			
   473 				var c = new Complex(min_c.real + diff_c.real / dim * x, 
   474 					min_c.imag + diff_c.imag / dim * y);  	
   475 			 	var result = test(c, max_iter);	
   476 		 		var r = Math.min(255, Math.pow(Math.max(0, 
   477 		 			(result.iter - max_iter / 20.0)), 2));
   478 				var g = Math.min(255, Math.pow(Math.max(0, 
   479 					(result.iter - max_iter / 25.0)), 2));			
   480 		 		var b = Math.min(255, Math.pow(Math.max(0, 
   481 					(result.iter - max_iter / 20.0)), 2));
   482 		 		var colour = "rgb(" + r + "," + g + "," + b + ")";
   483 		 		ctx.fillStyle = colour; 
   484 				ctx.fillRect(x, y, resolution, resolution);			
   485 			}
   486   		}
   487 	}  
   488 } 
   489 
   490 function getEventOffsetX(evt)
   491 {
   492 	if (evt.offsetX != null)
   493 		return evt.offsetX;
   494  
   495     var obj = evt.target || evt.srcElement;
   496    	setPageTopLeft(obj);
   497     return (evt.clientX - obj.pageLeft);
   498 }
   499 
   500 function getEventOffsetY(evt)
   501 {
   502 	if (evt.offsetY != null)
   503 		return evt.offsetY;
   504  
   505     var obj = evt.target || evt.srcElement;
   506    	setPageTopLeft(obj);
   507     return (evt.clientY - obj.pageTop);
   508 }
   509  
   510 function setPageTopLeft( o )
   511 {
   512     var top = 0,
   513     left = 0,
   514     obj = o;
   515  
   516     while (o.offsetParent)
   517      {
   518          left += o.offsetLeft ;
   519          top += o.offsetTop ;
   520          o = o.offsetParent ;
   521     };
   522  
   523     obj.pageTop = top;
   524     obj.pageLeft = left; 
   525 }
   526  
   527 function draw2(evt) {
   528     var iter = 0;
   529     var res = 0;
   530     var x = (getEventOffsetX(evt) - 335) / 167.5;
   531     var y = (getEventOffsetY(evt) - 140) / 70;
   532     var z = 0;
   533     draw(iter, x, y, z, res);
   534 }
   535 
   536 function update() {
   537     simulation.update();
   538     simulation.draw();
   539     if (gameoflife) {
   540         gameoflife.update();
   541         gameoflife.draw();
   542     }
   543 }
   544 
   545 function Grid(width, height, cell_size) {
   546     this.width = parseInt(width / cell_size);
   547     this.height = parseInt(height / cell_size);
   548     this.canvas_width = width;
   549     this.canvas_height = height;
   550     this.cell_size = cell_size;  
   551     this.cells = new Array();
   552     for (var y = 0; y < this.height; ++y) { 
   553         this.cells[y] = new Array();
   554         for (var x = 0; x < this.width; ++x) {
   555             this.cells[y][x] = new Cell(x, y, 0, this);
   556         }
   557     }
   558 }
   559 Grid.prototype.cell = function(x, y) {   
   560     return this.cells[y][x];
   561 }
   562 Grid.prototype.pick_cell = function(x, y) {
   563     var lx = parseInt(x / this.cell_size - 0.5);
   564     var ly = parseInt(y / this.cell_size - 0.5);
   565     return this.cells[ly][lx];
   566 }
   567 
   568 function Cell(x, y, value, grid) {
   569     this.x = x;
   570     this.y = y;  
   571     this.canvas_x = x * grid.cell_size;
   572     this.canvas_y = y * grid.cell_size;
   573     this.value = value;
   574     this.grid = grid;
   575     this._neighbours = new Array();
   576     this.last_mod = 0;
   577 }
   578 Cell.prototype.hash = function() {
   579     return this.x + ", " + this.y;
   580 }
   581 Cell.prototype.set_value = function(value) {
   582     this.value = value;
   583     this.last_mod = $.now();
   584 }
   585 Cell.prototype.neighbours = function() {
   586     if (this._neighbours.length) {
   587         return this._neighbours;
   588     }
   589     if (this.x > 0) {
   590         this._neighbours.push(this.grid.cell(this.x-1, this.y));
   591         if (this.y > 0) {
   592             this._neighbours.push(this.grid.cell(this.x-1, this.y-1));
   593             this._neighbours.push(this.grid.cell(this.x, this.y-1));
   594         }
   595         if (this.y + 1 < this.grid.height) {
   596             this._neighbours.push(this.grid.cell(this.x-1, this.y+1));
   597         }
   598     }
   599     if (this.x + 1 < this.grid.width) {
   600         this._neighbours.push(this.grid.cell(this.x+1, this.y));
   601         if (this.y + 1 < this.grid.height) {
   602             this._neighbours.push(this.grid.cell(this.x+1, this.y+1));
   603             this._neighbours.push(this.grid.cell(this.x, this.y+1));
   604         }
   605         if (this.y > 0) {
   606             this._neighbours.push(this.grid.cell(this.x+1, this.y-1));
   607         }
   608     }
   609     return this._neighbours;
   610 }
   611 Cell.prototype.density = function() {
   612     var d = 0;
   613     var neighbours = this.neighbours();
   614     for (var n in neighbours) {
   615         d += neighbours[n].value;
   616     }
   617     return d;
   618 }
   619 
   620 function Simulation(canvas, w, h) {
   621     this.last_update = 0;
   622     this.last_draw = 0;
   623     this.last_mouse_moved = 0;
   624     this.redraw = new Array();   
   625     this.canvas = canvas;
   626     this.canvas.width = w;
   627     this.canvas.height = h;
   628     this.context = canvas.getContext("2d");    
   629     this.pos_queue = new Array();
   630     this.cell_queue = new Array();  
   631     var cell_size = 3;
   632     this.grid = new Grid(this.canvas.width, this.canvas.height, cell_size);
   633     draw_sim_lines();
   634 }
   635 Simulation.prototype.draw = function() {
   636     var now = $.now();
   637     if (this.redraw.length) {
   638         var cell = this.redraw.pop();
   639         this.context.fillStyle = cell.value == 1 ? green.str() : background.str();
   640         this.context.fillRect(cell.canvas_x, cell.canvas_y, 
   641                               this.grid.cell_size, this.grid.cell_size);
   642         this.last_draw = $.now();
   643     }
   644 }
   645 Simulation.prototype.update = function() {
   646     var now = $.now();
   647     if (this.pos_queue.length) {
   648         var pos = this.pos_queue.pop();
   649         if (pos[0] < this.canvas.width
   650             && pos[1] < this.canvas.height) {
   651             var cell = this.grid.pick_cell(pos[0], pos[1]);
   652             cell.set_value(1);
   653             this.cell_queue.push(cell);
   654             this.cell_queue.concat(cell.neighbours()); 
   655             this.redraw.push(cell);          
   656         }
   657     }
   658     if (this.last_update + 1000 > now) {
   659         return;
   660     }
   661     var changed = new Array();
   662     var next_cell_queue = new Array();
   663     while (this.cell_queue.length) {
   664         var cell = this.cell_queue.pop();
   665         if (changed[cell.hash()]) {           
   666             continue;
   667         }
   668         var d = cell.density();
   669         if (d == 3 && cell.value == 0) {           
   670             changed[cell.hash()] = cell;            
   671             next_cell_queue = next_cell_queue.concat(cell.neighbours());               
   672         } else if (cell.value == 1) {
   673             if (d < 2 || d > 3) {              
   674                 changed[cell.hash()] = cell;                
   675                 next_cell_queue = next_cell_queue.concat(cell.neighbours());               
   676             }
   677         }       
   678     }
   679     for (var pos in changed) {
   680         var cell = changed[pos];      
   681         cell.set_value(1 - cell.value);
   682         this.redraw.push(cell);
   683     }
   684     this.cell_queue = this.cell_queue.concat(next_cell_queue);
   685     this.last_update = now;  
   686 }
   687 Simulation.prototype.mouse_moved = function(pos) {
   688     var now = $.now();    
   689     if (this.last_mouse_moved + 50 < now) {
   690         this.pos_queue.push(pos);
   691         this.last_mouse_moved = now;       
   692     }
   693 }
   694 
   695