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