factory/v2012/script.js
author Eugen Sawin <sawine@me73.com>
Sat, 07 Jan 2012 01:33:27 +0100
changeset 90 49897f71f067
parent 89 728dc42f2eb3
child 92 290ad5d7652b
permissions -rw-r--r--
Removed baked html files. Added menu highlighting.
     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"), 
     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 var last_highlight;
   137 var last_colours = new Array();
   138 function highlight_menu(id, p) {
   139     if (last_highlight == p) {
   140         return;
   141     }
   142     var canvas = document.getElementById("logo");
   143     var context = canvas.getContext("2d");    
   144     var image = context.getImageData(0, 0, menu_width, menu_height);
   145     if (last_highlight && last_colours && last_colours[0] && last_colours[1]) {        
   146         page = last_highlight["args"][0]; 
   147         min_x = last_highlight["min_x"];
   148         max_x = last_highlight["max_x"];
   149         min_y = last_highlight["min_y"];
   150         max_y = last_highlight["max_y"];
   151         colour_area(image, min_x + 10, max_x - 10, 0, 60, 
   152                     last_colours[0]);
   153         colour_area(image, min_x + 10, max_x - 10, 60, max_y - 10, 
   154                     last_colours[1]);
   155     }
   156     if (p) {    
   157         var page = p["args"][0]; 
   158         var min_x = p["min_x"];
   159         var max_x = p["max_x"];
   160         var min_y = p["min_y"];
   161         var max_y = p["max_y"];       
   162         last_colours[0] = colour_area(image, min_x + 10, max_x - 10, 0, 60, 
   163                                       orange);
   164         last_colours[1] = colour_area(image, min_x + 10, max_x - 10, 60, max_y - 10, 
   165                                       white);        
   166     }
   167     
   168     context.putImageData(image, 0, 0);
   169     last_highlight = p;
   170 }
   171 
   172 function colour_area(image, min_x, max_x, min_y, max_y, colour) {   
   173     var pixels = image.data;
   174     var old_colour;
   175     for (var y = min_y; y <= max_y; y += 1) {
   176         for (var x = min_x; x <= max_x; x += 1) {
   177             var pix_colour = getPixel(image, x, y);
   178             if (pix_colour.a > 0) {
   179                 colour.a = pix_colour.a;               
   180                 setPixel(image, x, y, colour); 
   181                 if (pix_colour.a == 255) {
   182                     old_colour = new Colour(pix_colour.r,
   183                                             pix_colour.g,
   184                                             pix_colour.b,
   185                                             pix_colour.a);
   186                 }
   187             }
   188         }
   189     }
   190     return old_colour;
   191 }
   192 
   193 function init_logo(event) {
   194     var canvas = document.getElementById("logo");
   195     var context = canvas.getContext("2d");    
   196     canvas.width = menu_width;
   197     canvas.height = menu_height;
   198     context.drawImage(event.target, 0, 0);
   199     var image = context.getImageData(0, 0, menu_width, menu_height);    
   200     for (var i in click_events["logo"]) {
   201         var p = click_events["logo"][i]; 
   202         var min_x = p["min_x"];
   203         var max_x = p["max_x"];
   204         var min_y = p["min_y"];
   205         var max_y = p["max_y"];
   206         var pos = document.location.href.lastIndexOf("/") + 1; 
   207         var page = document.location.href.substr(pos);        
   208         for (var j in p["args"]) {
   209             if (page == p["args"][j]) {         
   210                 colour_area(image, min_x, max_x, 0, 60, black);
   211                 colour_area(image, min_x, max_x, 60, max_y, white);
   212                 break;
   213             }
   214             else {
   215                 colour_area(image, min_x, max_x, 0, 60, white);
   216                 colour_area(image, min_x, max_x, 60, max_y,  orange);  
   217             }
   218         }       
   219     } 
   220     context.putImageData(image, 0, 0);      
   221     // context.fillStyle = green.str();
   222     // console.log((found["max_x"] - found["min_x"]) / 2 + found["min_x"] - 2);
   223     // context.fillRect((found["max_x"]-found["min_x"])/2+found["min_x"]-1, 95, 2, 5);  
   224     draw_menu_lines();   
   225 }
   226 
   227 function draw_menu_lines() {
   228     var canvas = document.getElementById("logo");
   229     var context = canvas.getContext("2d");  
   230     var image = context.getImageData(0, 0, menu_width, menu_height);
   231     var pixels = image.data;
   232     context.lineCap = "round";
   233     context.lineWidth = 1;
   234     var colour1a = new Colour(0, 0, 0, 0.1);
   235     context.beginPath();   
   236     context.moveTo(0, menu_height - 1);
   237     context.lineTo(menu_width - 1, menu_height - 1);   
   238     context.closePath();  
   239     context.strokeStyle = colour1a.str();
   240     context.stroke(); 
   241     var colour1e = new Colour(0, 0, 0, 0.05);  
   242     context.beginPath();   
   243     context.moveTo(70, menu_height - 1);
   244     context.lineTo(menu_width - 71, menu_height - 1);   
   245     context.closePath();  
   246     context.strokeStyle = colour1e.str();
   247     context.stroke();  
   248     var colour1b = new Colour(0, 0, 0, 0.05);  
   249     context.beginPath();   
   250     context.moveTo(50, menu_height - 1);
   251     context.lineTo(menu_width - 51, menu_height - 1);   
   252     context.closePath();  
   253     context.strokeStyle = colour1b.str();
   254     context.stroke();
   255     var colour1c = new Colour(0, 0, 0, 0.05);  
   256     context.beginPath();   
   257     context.moveTo(25, menu_height - 1);
   258     context.lineTo(menu_width - 26, menu_height - 1);   
   259     context.closePath();  
   260     context.strokeStyle = colour1c.str();
   261     context.stroke();
   262     var colour1d = new Colour(0, 0, 0, 0.05);  
   263     context.beginPath();   
   264     context.moveTo(10, menu_height - 1);
   265     context.lineTo(menu_width - 11, menu_height - 1);   
   266     context.closePath();  
   267     context.strokeStyle = colour1d.str();
   268     context.stroke();  
   269     
   270     var colour2 = new Colour(0, 0, 0, 0.2);
   271     context.beginPath();  
   272     context.moveTo(menu_splits[0], 0); 
   273     context.lineTo(menu_splits[0], menu_height - 1);
   274     context.moveTo(menu_splits[1], 0);
   275     context.lineTo(menu_splits[1], menu_height - 1);
   276     context.moveTo(menu_splits[2], 0);
   277     context.lineTo(menu_splits[2], menu_height - 1);
   278     context.closePath();
   279     context.strokeStyle = colour2.str();
   280     context.stroke();
   281 
   282     context.clearRect(menu_splits[0] - 1, menu_height - 1, 2, 2);
   283     context.clearRect(menu_splits[1] - 1, menu_height - 1, 2, 2);
   284     context.clearRect(menu_splits[2] - 1, menu_height - 1, 2, 2);
   285 
   286     context.clearRect(menu_splits[0] - 1, menu_height - 2, 1, 1);
   287     context.clearRect(menu_splits[1] - 1, menu_height - 2, 1, 1);
   288     context.clearRect(menu_splits[2] - 1, menu_height - 2, 1, 1);
   289 }
   290 
   291 function clearMenuLines() {
   292     var canvas = document.getElementById("logo");
   293     var context = canvas.getContext("2d");  
   294     var image = context.getImageData(0, 0, menu_width, menu_height);
   295     var pixels = image.data;
   296     context.clearRect(0, menu_height - 2, menu_width - 1, 2);
   297     context.clearRect(menu_splits[0] - 1, 0, 2, menu_height - 1);
   298     context.clearRect(menu_splits[1] - 1, 0, 2, menu_height - 1);
   299     context.clearRect(menu_splits[2] - 1, 0, 2, menu_height - 1);
   300 }
   301 
   302 function draw_sim_lines() {
   303     var w = 670;
   304     var h = 50;
   305     var canvas = document.getElementById("sim");
   306     var context = canvas.getContext("2d");  
   307     var image = context.getImageData(0, 0, w, h);
   308     var pixels = image.data;
   309     context.lineCap = "round";
   310     context.lineWidth = 1;
   311     var colour1a = new Colour(0, 0, 0, 0.1);
   312     context.beginPath();   
   313     context.moveTo(0, h - 1);
   314     context.lineTo(w - 1, h - 1);   
   315     context.closePath();  
   316     context.strokeStyle = colour1a.str();
   317     context.stroke(); 
   318     var colour1e = new Colour(0, 0, 0, 0.05);  
   319     context.beginPath();   
   320     context.moveTo(70, h - 1);
   321     context.lineTo(w - 71, h - 1);   
   322     context.closePath();  
   323     context.strokeStyle = colour1e.str();
   324     context.stroke();  
   325     var colour1b = new Colour(0, 0, 0, 0.05);  
   326     context.beginPath();   
   327     context.moveTo(50, h - 1);
   328     context.lineTo(w - 51, h - 1);   
   329     context.closePath();  
   330     context.strokeStyle = colour1b.str();
   331     context.stroke();
   332     var colour1c = new Colour(0, 0, 0, 0.05);  
   333     context.beginPath();   
   334     context.moveTo(25, h - 1);
   335     context.lineTo(w - 26, h - 1);   
   336     context.closePath();  
   337     context.strokeStyle = colour1c.str();
   338     context.stroke();
   339     var colour1d = new Colour(0, 0, 0, 0.05);  
   340     context.beginPath();   
   341     context.moveTo(10, h - 1);
   342     context.lineTo(w - 11, h - 1);   
   343     context.closePath();  
   344     context.strokeStyle = colour1d.str();
   345     context.stroke();   
   346 }
   347 
   348 function update_logo() {
   349     var canvas = document.getElementById("logo");
   350     var context = canvas.getContext("2d");  
   351     var image = context.getImageData(0, 0, menu_width, menu_height);
   352     var pixels = image.data;
   353     var white = new Colour(255, 255, 255);
   354     for (var y = 0; y < menu_height; y += 1) {
   355         for (var x = 0; x < menu_width; x += 1) {
   356             var pix_colour = getPixel(image, x, y);
   357             if (pix_colour.a > 0) {
   358                 setPixel(image, x, y, new Colour(90, 215, 21, pix_colour.a));
   359             }
   360         }
   361     }   
   362     context.putImageData(image, 0, 0);
   363 }
   364 
   365 var char_map = new Array();
   366 char_map["A"] = new Array(new Array(0, 4), new Array(1, 3),
   367                           new Array(2, 2), new Array(3, 1),
   368                           new Array(4, 0), new Array(5, 1),
   369                           new Array(6, 2), new Array(7, 3),
   370                           new Array(8, 4), new Array(2, 3),
   371                           new Array(3, 3), new Array(4, 3),
   372                           new Array(5, 3), new Array(6, 3));
   373 char_map["M"] = new Array(new Array(0, 4), new Array(0, 3),
   374                           new Array(0, 2), new Array(0, 1),
   375                           new Array(0, 0), new Array(0, 5),
   376                           new Array(5, 4), new Array(5, 3),
   377                           new Array(5, 2), new Array(5, 1),
   378                           new Array(5, 0), new Array(5, 5),
   379                           new Array(1, 1), new Array(2, 2), 
   380                           new Array(4, 2), new Array(5, 1),
   381                           new Array(3, 3));
   382 char_map["E"] = new Array(new Array(0, 4), new Array(0, 3),
   383                           new Array(0, 2), new Array(0, 1),
   384                           new Array(0, 0), new Array(0, 5),
   385                           new Array(1, 0), new Array(2, 0),
   386                           new Array(3, 0),
   387                           new Array(1, 3), new Array(2, 3),                       
   388                           new Array(1, 5), new Array(2, 5),
   389                           new Array(3, 5))
   390 char_map["7"] = new Array(new Array(0, 0), new Array(1, 0),
   391                           new Array(2, 0),
   392                           new Array(0, 5), new Array(0, 4),
   393                           new Array(1, 3), new Array(2, 2));
   394 char_map["3"] = new Array(new Array(2, 4), new Array(2, 3),
   395                           new Array(2, 2), new Array(2, 1),
   396                           new Array(0, 0), new Array(0, 5),
   397                           new Array(1, 0), new Array(2, 0),                         
   398                           new Array(1, 3), new Array(2, 3),                          
   399                           new Array(1, 5), new Array(2, 5))
   400 
   401 function init_gameoflife(text) {
   402     var canvas = document.getElementById("gameoflife");
   403     var cell_size = 16;
   404     if (canvas) {
   405         gameoflife = new Simulation(canvas, 670, 670, cell_size,
   406                                     green, black);
   407         $("#gameoflife").mousemove(function(event) { 
   408             gameoflife.mouse_moved(mouse_pos(event, "#gameoflife")); 
   409         });       
   410         var offset = new Array(13, 16);
   411         for (var c in text) {            
   412             var w = 0;
   413             for (p in char_map[text[c]]) {
   414                 var x = char_map[text[c]][p][0];
   415                 var y = char_map[text[c]][p][1];
   416                 w = Math.max(w, x);
   417                 var pos = new Array((x + offset[0]) * cell_size, 
   418                                     (y + offset[1]) * cell_size);
   419                 gameoflife.activate_cell(pos);
   420             }            
   421             offset[0] += w + 2;
   422         }       
   423     }    
   424 }
   425 
   426 function Colour(r, g, b, a) {
   427     this.r = r;
   428     this.g = g;
   429     this.b = b;
   430     this.a = a == undefined ? 255 : a;
   431 }
   432 Colour.prototype.equals = function(rhs) {
   433     for (p in this) {
   434         if (typeof(rhs[p]) == undefined
   435            || this[p] != rhs[p]) {           
   436             return false;
   437         }
   438     }
   439     return true;
   440 }
   441 Colour.prototype.str = function() {
   442     return "rgba(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")";
   443 }
   444 
   445 var white = new Colour(255, 255, 255);
   446 var black = new Colour(0, 0, 0, 255);
   447 var orange = new Colour(201, 87, 35, 255);
   448 var green = new Colour(90, 215, 21, 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