Fixed minor bug.
1 var QUOTES_NUMBER = 39;
2 var SERVER = "http://" + window.location.hostname + ":" + window.location.port;
6 $(document).ready(function() {
7 simulation = new Simulation(document.getElementById("sim"),
8 670, 50, 4, 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() {
14 $(this).css("cursor", "pointer");
16 $(this).css("cursor", "auto");
18 $("#sim").mousemove(function(event) { simulation.mouse_moved(mouse_pos(event, "#sim")); });
20 if (window.webkitRequestAnimationFrame) {
21 onEachFrame = function(cb) {
22 var _cb = function() { cb(); webkitRequestAnimationFrame(_cb); }
25 } else if (window.mozRequestAnimationFrame) {
26 onEachFrame = function(cb) {
27 var _cb = function() { cb(); mozRequestAnimationFrame(_cb); }
31 onEachFrame = function(cb) {
32 setInterval(cb, 1000 / 30);
35 window.onEachFrame = onEachFrame;
36 window.onEachFrame(update);
37 var pos = document.location.href.lastIndexOf("/") + 1;
38 var page = document.location.href.substr(pos);
39 if (page == "experiments.html") {
41 } else if (page == "gameoflife.html") {
46 $(document).keypress(function(event) {
47 if (event.which == 13) {
48 event.preventDefault();
54 var menu_height = 100;
55 var menu_splits = new Array(180, 350, 505);
57 var click_events = new Array();
58 click_events["logo"] = new Array();
59 click_events["logo"][0] = new Object();
60 click_events["logo"][0]["min_x"] = 0;
61 click_events["logo"][0]["max_x"] = menu_splits[0];
62 click_events["logo"][0]["min_y"] = 0;
63 click_events["logo"][0]["max_y"] = menu_height;
64 click_events["logo"][0]["func"] = switch_page;
65 click_events["logo"][0]["args"] = new Array("personalwork.html");
66 click_events["logo"][1] = new Object();
67 click_events["logo"][1]["min_x"] = menu_splits[0] + 1;
68 click_events["logo"][1]["max_x"] = menu_splits[1];
69 click_events["logo"][1]["min_y"] = 0;
70 click_events["logo"][1]["max_y"] = menu_height;
71 click_events["logo"][1]["func"] = switch_page;
72 click_events["logo"][1]["args"] = new Array("howiwork.html");
73 click_events["logo"][2] = new Object();
74 click_events["logo"][2]["min_x"] = menu_splits[1] + 1;
75 click_events["logo"][2]["max_x"] = menu_splits[2];
76 click_events["logo"][2]["min_y"] = 0;
77 click_events["logo"][2]["max_y"] = menu_height;
78 click_events["logo"][2]["func"] = switch_page;
79 click_events["logo"][2]["args"] = new Array("books.html");
80 click_events["logo"][3] = new Object();
81 click_events["logo"][3]["min_x"] = menu_splits[2] + 1;
82 click_events["logo"][3]["max_x"] = menu_width - 1;
83 click_events["logo"][3]["min_y"] = 0;
84 click_events["logo"][3]["max_y"] = menu_height;
85 click_events["logo"][3]["func"] = switch_page;
86 click_events["logo"][3]["args"] = new Array("links.html", "linksend.html");
88 function mouse_pos(event, id) {
89 var offset = $(id).offset();
90 return new Array(event.pageX - offset.left,
91 event.pageY - offset.top);
94 function handle_click(event) {
95 var xy = mouse_pos(event, "#logo");
98 for (var i in click_events[event.target.id]) {
99 var ces = click_events[event.target.id][i];
100 if (ces && x >= ces["min_x"] && x <= ces["max_x"]
101 && y >= ces["min_y"] && y <= ces["max_y"]) {
102 ces["func"](event.target.id, ces);
108 function switch_page(id, params) {
109 var page = params["args"][0];
110 $("body").load(page);
111 document.location.href = page;
114 function colour_area(image, min_x, max_x, min_y, max_y, colour) {
115 var pixels = image.data;
116 for (var y = min_y; y <= max_y; y += 1) {
117 for (var x = min_x; x <= max_x; x += 1) {
118 var pix_colour = getPixel(image, x, y);
119 if (pix_colour.a > 0) {
120 colour.a = pix_colour.a;
121 setPixel(image, x, y, colour);
127 function init_logo(event) {
128 var canvas = document.getElementById("logo");
129 var context = canvas.getContext("2d");
130 canvas.width = menu_width;
131 canvas.height = menu_height;
132 context.drawImage(event.target, 0, 0);
133 var image = context.getImageData(0, 0, menu_width, menu_height);
134 for (var i in click_events["logo"]) {
135 var p = click_events["logo"][i];
136 var min_x = p["min_x"];
137 var max_x = p["max_x"];
138 var min_y = p["min_y"];
139 var max_y = p["max_y"];
140 var pos = document.location.href.lastIndexOf("/") + 1;
141 var page = document.location.href.substr(pos);
142 for (var j in p["args"]) {
143 if (page == p["args"][j]) {
144 colour_area(image, min_x, max_x, 0, 60, black);
145 colour_area(image, min_x, max_x, 60, max_y, white);
149 colour_area(image, min_x, max_x, 0, 60, white);
150 colour_area(image, min_x, max_x, 60, max_y, orange);
154 context.putImageData(image, 0, 0);
155 // context.fillStyle = green.str();
156 // console.log((found["max_x"] - found["min_x"]) / 2 + found["min_x"] - 2);
157 // context.fillRect((found["max_x"]-found["min_x"])/2+found["min_x"]-1, 95, 2, 5);
161 function draw_menu_lines() {
162 var canvas = document.getElementById("logo");
163 var context = canvas.getContext("2d");
164 var image = context.getImageData(0, 0, menu_width, menu_height);
165 var pixels = image.data;
166 context.lineCap = "round";
167 context.lineWidth = 1;
168 var colour1a = new Colour(0, 0, 0, 0.1);
170 context.moveTo(0, menu_height - 1);
171 context.lineTo(menu_width - 1, menu_height - 1);
173 context.strokeStyle = colour1a.str();
175 var colour1e = new Colour(0, 0, 0, 0.05);
177 context.moveTo(70, menu_height - 1);
178 context.lineTo(menu_width - 71, menu_height - 1);
180 context.strokeStyle = colour1e.str();
182 var colour1b = new Colour(0, 0, 0, 0.05);
184 context.moveTo(50, menu_height - 1);
185 context.lineTo(menu_width - 51, menu_height - 1);
187 context.strokeStyle = colour1b.str();
189 var colour1c = new Colour(0, 0, 0, 0.05);
191 context.moveTo(25, menu_height - 1);
192 context.lineTo(menu_width - 26, menu_height - 1);
194 context.strokeStyle = colour1c.str();
196 var colour1d = new Colour(0, 0, 0, 0.05);
198 context.moveTo(10, menu_height - 1);
199 context.lineTo(menu_width - 11, menu_height - 1);
201 context.strokeStyle = colour1d.str();
204 var colour2 = new Colour(0, 0, 0, 0.2);
206 context.moveTo(menu_splits[0], 0);
207 context.lineTo(menu_splits[0], menu_height - 1);
208 context.moveTo(menu_splits[1], 0);
209 context.lineTo(menu_splits[1], menu_height - 1);
210 context.moveTo(menu_splits[2], 0);
211 context.lineTo(menu_splits[2], menu_height - 1);
213 context.strokeStyle = colour2.str();
216 context.clearRect(menu_splits[0] - 1, menu_height - 1, 2, 2);
217 context.clearRect(menu_splits[1] - 1, menu_height - 1, 2, 2);
218 context.clearRect(menu_splits[2] - 1, menu_height - 1, 2, 2);
220 context.clearRect(menu_splits[0] - 1, menu_height - 2, 1, 1);
221 context.clearRect(menu_splits[1] - 1, menu_height - 2, 1, 1);
222 context.clearRect(menu_splits[2] - 1, menu_height - 2, 1, 1);
225 function clearMenuLines() {
226 var canvas = document.getElementById("logo");
227 var context = canvas.getContext("2d");
228 var image = context.getImageData(0, 0, menu_width, menu_height);
229 var pixels = image.data;
230 context.clearRect(0, menu_height - 2, menu_width - 1, 2);
231 context.clearRect(menu_splits[0] - 1, 0, 2, menu_height - 1);
232 context.clearRect(menu_splits[1] - 1, 0, 2, menu_height - 1);
233 context.clearRect(menu_splits[2] - 1, 0, 2, menu_height - 1);
236 function draw_sim_lines() {
239 var canvas = document.getElementById("sim");
240 var context = canvas.getContext("2d");
241 var image = context.getImageData(0, 0, w, h);
242 var pixels = image.data;
243 context.lineCap = "round";
244 context.lineWidth = 1;
245 var colour1a = new Colour(0, 0, 0, 0.1);
247 context.moveTo(0, h - 1);
248 context.lineTo(w - 1, h - 1);
250 context.strokeStyle = colour1a.str();
252 var colour1e = new Colour(0, 0, 0, 0.05);
254 context.moveTo(70, h - 1);
255 context.lineTo(w - 71, h - 1);
257 context.strokeStyle = colour1e.str();
259 var colour1b = new Colour(0, 0, 0, 0.05);
261 context.moveTo(50, h - 1);
262 context.lineTo(w - 51, h - 1);
264 context.strokeStyle = colour1b.str();
266 var colour1c = new Colour(0, 0, 0, 0.05);
268 context.moveTo(25, h - 1);
269 context.lineTo(w - 26, h - 1);
271 context.strokeStyle = colour1c.str();
273 var colour1d = new Colour(0, 0, 0, 0.05);
275 context.moveTo(10, h - 1);
276 context.lineTo(w - 11, h - 1);
278 context.strokeStyle = colour1d.str();
282 function update_logo() {
283 var canvas = document.getElementById("logo");
284 var context = canvas.getContext("2d");
285 var image = context.getImageData(0, 0, menu_width, menu_height);
286 var pixels = image.data;
287 var white = new Colour(255, 255, 255);
288 for (var y = 0; y < menu_height; y += 1) {
289 for (var x = 0; x < menu_width; x += 1) {
290 var pix_colour = getPixel(image, x, y);
291 if (pix_colour.a > 0) {
292 setPixel(image, x, y, new Colour(90, 215, 21, pix_colour.a));
296 context.putImageData(image, 0, 0);
299 function init_gameoflife() {
300 var canvas = document.getElementById("gameoflife");
302 gameoflife = new Simulation(canvas, 670, 670, 8,
304 $("#gameoflife").mousemove(function(event) {
305 gameoflife.mouse_moved(mouse_pos(event, "#gameoflife"));
310 function Colour(r, g, b, a) {
314 this.a = a == undefined ? 255 : a;
316 Colour.prototype.equals = function(rhs) {
318 if (typeof(rhs[p]) == undefined
319 || this[p] != rhs[p]) {
325 Colour.prototype.str = function() {
326 return "rgba(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")";
329 var white = new Colour(255, 255, 255);
330 var black = new Colour(0, 0, 0);
331 var orange = new Colour(201, 87, 35);
332 var green = new Colour(90, 215, 21);
333 var background = new Colour(34, 34, 34);
335 function setPixel(image, x, y, colour) {
336 var index = 4 * (x + y * image.width);
337 image.data[index] = colour.r;
338 image.data[index + 1] = colour.g;
339 image.data[index + 2] = colour.b;
340 image.data[index + 3] = colour.a;
343 function getPixel(image, x, y) {
344 var index = 4 * (x + y * image.width);
345 var r = image.data[index];
346 var g = image.data[index + 1];
347 var b = image.data[index + 2];
348 var a = image.data[index + 3];
349 return new Colour(r, g, b, a);
352 function load_random_quote() {
353 var file = "/quotes/quote" + Math.floor(Math.random() * QUOTES_NUMBER + 1) + ".html";
354 $.ajax({url: SERVER + file,
355 success: write_quote});
358 function write_quote(data, status, xhr) {
359 $("#random_quote").html(data);
362 function load_footer()
364 var file = "/footer.html";
365 var currentFile = self.location.hostname + self.location.pathname;
366 var request = http_request_object();
367 var url = "http://" + self.location.hostname + file;
368 request.open("GET", url, false);
369 request.setRequestHeader("User-Agent", navigator.userAgent);
371 // if (oRequest.status == 200) alert(oRequest.responseText);
372 // else alert("Error executing XMLHttpRequest call!");
373 //document.write(url);
374 //document.write(request.responseText);
375 document.getElementById('footer').innerHTML = request.responseText;
380 // Mandelbrot functions
381 function Complex(real, imag)
387 var MIN_C = new Complex(-2.2, -1.4);
388 var MAX_C = new Complex(1.0, 1.4);
392 var max_iter = MIN_ITER;
397 function Result(z, iter)
403 function complex_quad(c)
405 return new Complex(Math.pow(c.real, 2) - Math.pow(c.imag, 2),
406 2.0 * c.real * c.imag);
409 function complex_quad_value(c)
411 return Math.pow(c.real, 2) + Math.pow(c.imag, 2);
414 function complex_add(c1, c2)
416 return new Complex(c1.real + c2.real, c1.imag + c2.imag);
419 function complex_equal(c1, c2)
421 return (c1.real == c2.real) && (c1.imag == c2.imag);
424 function iterate(z, c)
426 z_quad = complex_quad(z);
427 return new Complex(z_quad.real + c.real, z_quad.imag + c.imag);
430 function test(c, max_iter)
433 var z = new Complex(0.0, 0.0);
434 var last_z = new Complex(-1.0, 0.0);
435 var quad_z = complex_quad_value(z);
437 while (iter < max_iter
438 && !complex_equal(z, last_z)
439 && quad_z <= bailout)
443 quad_z = complex_quad_value(z);
446 return new Result(quad_z, iter);
449 function draw(diter, dx, dy, dz, dres)
451 var canvas = document.getElementById('mandelbrot');
453 if (canvas.getContext)
456 var ctx = canvas.getContext('2d');
460 resolution = Math.max(1, resolution + dres);
465 max_iter = Math.max(MIN_ITER, max_iter + diter);
468 var red = "rgb(255, 0, 0)";
469 var white = "rgb(255, 255, 255)";
470 var width = canvas.width;
471 var height = canvas.height;
472 var dim = Math.max(width, height);
473 var dim_ratio = Math.round(width / height);
474 var diff_c = new Complex(max_c.real - min_c.real,
475 max_c.imag - min_c.imag);
476 dx_min = diff_c.real / 100 * (dx + dz);
477 dx_max = diff_c.real / 100 * (dx - dz);
479 dy_min = diff_c.imag / 100 * (dy + dz);
480 dy_max = diff_c.imag / 100 * (dy - dz);
482 var min_inc = new Complex(dx_min * dim_ratio / 2.0, dy_min);
483 var max_inc = new Complex(dx_max * dim_ratio / 2.0, dy_max);
484 min_c = complex_add(min_c, min_inc);
485 max_c = complex_add(max_c, max_inc);
486 diff_c = new Complex(max_c.real - min_c.real,
487 max_c.imag - min_c.imag);
489 for (var y = 0; y < height; y += resolution)
491 for (var x = 0; x < width; x += resolution)
493 var c = new Complex(min_c.real + diff_c.real / dim * x,
494 min_c.imag + diff_c.imag / dim * y);
495 var result = test(c, max_iter);
496 var r = Math.min(255, Math.pow(Math.max(0,
497 (result.iter - max_iter / 20.0)), 2));
498 var g = Math.min(255, Math.pow(Math.max(0,
499 (result.iter - max_iter / 25.0)), 2));
500 var b = Math.min(255, Math.pow(Math.max(0,
501 (result.iter - max_iter / 20.0)), 2));
502 var colour = "rgb(" + r + "," + g + "," + b + ")";
503 ctx.fillStyle = colour;
504 ctx.fillRect(x, y, resolution, resolution);
510 function getEventOffsetX(evt)
512 if (evt.offsetX != null)
515 var obj = evt.target || evt.srcElement;
517 return (evt.clientX - obj.pageLeft);
520 function getEventOffsetY(evt)
522 if (evt.offsetY != null)
525 var obj = evt.target || evt.srcElement;
527 return (evt.clientY - obj.pageTop);
530 function setPageTopLeft( o )
536 while (o.offsetParent)
538 left += o.offsetLeft ;
547 function draw2(evt) {
550 var x = (getEventOffsetX(evt) - 335) / 167.5;
551 var y = (getEventOffsetY(evt) - 140) / 70;
553 draw(iter, x, y, z, res);
565 function Grid(width, height, cell_size) {
566 this.width = parseInt(width / cell_size + 0.5);
567 this.height = parseInt(height / cell_size + 0.5);
568 this.canvas_width = width;
569 this.canvas_height = height;
570 this.cell_size = cell_size;
571 this.cells = new Array();
572 for (var y = 0; y < this.height; ++y) {
573 this.cells[y] = new Array();
574 for (var x = 0; x < this.width; ++x) {
575 this.cells[y][x] = new Cell(x, y, 0, this);
579 Grid.prototype.cell = function(x, y) {
580 return this.cells[y][x];
582 Grid.prototype.pick_cell = function(x, y) {
583 var lx = parseInt(x / this.cell_size - 0.5);
584 var ly = parseInt(y / this.cell_size - 0.5);
585 return this.cells[ly][lx];
588 function Cell(x, y, value, grid) {
591 this.canvas_x = x * grid.cell_size;
592 this.canvas_y = y * grid.cell_size;
595 this._neighbours = new Array();
598 Cell.prototype.hash = function() {
599 return this.x + ", " + this.y;
601 Cell.prototype.set_value = function(value) {
603 this.last_mod = $.now();
605 Cell.prototype.neighbours = function() {
606 if (this._neighbours.length) {
607 return this._neighbours;
610 this._neighbours.push(this.grid.cell(this.x-1, this.y));
612 this._neighbours.push(this.grid.cell(this.x-1, this.y-1));
613 this._neighbours.push(this.grid.cell(this.x, this.y-1));
615 if (this.y + 1 < this.grid.height) {
616 this._neighbours.push(this.grid.cell(this.x-1, this.y+1));
619 this._neighbours.push(this.grid.cell(this.grid.width-1, this.y));
621 if (this.x + 1 < this.grid.width) {
622 this._neighbours.push(this.grid.cell(this.x+1, this.y));
623 if (this.y + 1 < this.grid.height) {
624 this._neighbours.push(this.grid.cell(this.x+1, this.y+1));
625 this._neighbours.push(this.grid.cell(this.x, this.y+1));
628 this._neighbours.push(this.grid.cell(this.x+1, this.y-1));
631 this._neighbours.push(this.grid.cell(0, this.y));
633 return this._neighbours;
635 Cell.prototype.density = function() {
637 var neighbours = this.neighbours();
638 for (var n in neighbours) {
639 d += neighbours[n].value;
644 function Simulation(canvas, w, h, cell_size, life_colour, dead_colour) {
645 this.last_update = 0;
647 this.last_mouse_moved = 0;
648 this.redraw = new Array();
649 this.canvas = canvas;
650 this.canvas.width = w;
651 this.canvas.height = h;
652 this.context = canvas.getContext("2d");
653 this.pos_queue = new Array();
654 this.cell_queue = new Array();
655 this.cell_size = cell_size;
656 this.life_colour = life_colour;
657 this.dead_colour = dead_colour;
658 this.grid = new Grid(this.canvas.width, this.canvas.height, cell_size);
661 Simulation.prototype.draw = function() {
663 if (this.redraw.length) {
664 var cell = this.redraw.pop();
665 this.context.fillStyle = cell.value == 1 ?
666 this.life_colour.str() : this.dead_colour.str();
667 this.context.fillRect(cell.canvas_x, cell.canvas_y,
668 this.grid.cell_size, this.grid.cell_size);
669 this.last_draw = $.now();
672 Simulation.prototype.update = function() {
674 if (this.pos_queue.length) {
675 var pos = this.pos_queue.pop();
676 if (pos[0] < this.canvas.width
677 && pos[1] < this.canvas.height) {
678 var cell = this.grid.pick_cell(pos[0], pos[1]);
680 this.cell_queue.push(cell);
681 this.cell_queue.concat(cell.neighbours());
682 this.redraw.push(cell);
685 if (this.last_update + 1000 > now) {
688 var changed = new Array();
689 var next_cell_queue = new Array();
690 while (this.cell_queue.length) {
691 var cell = this.cell_queue.pop();
692 if (changed[cell.hash()]) {
695 var d = cell.density();
696 if (d == 3 && cell.value == 0) {
697 changed[cell.hash()] = cell;
698 next_cell_queue = next_cell_queue.concat(cell.neighbours());
699 } else if (cell.value == 1) {
700 if (d < 2 || d > 3) {
701 changed[cell.hash()] = cell;
702 next_cell_queue = next_cell_queue.concat(cell.neighbours());
706 for (var pos in changed) {
707 var cell = changed[pos];
708 cell.set_value(1 - cell.value);
709 this.redraw.push(cell);
711 this.cell_queue = this.cell_queue.concat(next_cell_queue);
712 this.last_update = now;
714 Simulation.prototype.mouse_moved = function(pos) {
716 if (this.last_mouse_moved + 50 < now) {
717 this.pos_queue.push(pos);
718 this.last_mouse_moved = now;