| |
| |
| (function() { |
| var main_element = document.getElementById("header_main"); |
| var content_element = document.getElementById("overlay"); |
| var canvas = document.querySelector('canvas'); |
| var title_elem = document.getElementsByClassName("title_elem")[0]; |
| var title_text = document.getElementById("title_text"); |
| ctx = canvas.getContext('2d'); |
| if (!ctx) |
| console.warn("Your browser does not support canvas, content may be broken :'("); |
|
|
| var SENSITIVITY, SIBLINGS_LIMIT, DENSITY, TOTAL_NODES, ANCHOR_LENGTH, CURSOR_HEIGHT, CURSOR_WIDTH; |
| css_opts = getComputedStyle(document.documentElement); |
| SENSITIVITY = css_opts.getPropertyValue('--background-sensitivity') || 120; |
| SIBLINGS_LIMIT = css_opts.getPropertyValue('--background-siblings') || 7; |
| NODE_DENSITY = css_opts.getPropertyValue('--background-node-density') || 6; |
| CURSOR_WIDTH = css_opts.getPropertyValue('--background-cursor-width') || 250; |
| CURSOR_HEIGHT = css_opts.getPropertyValue('--background-cursor-height') || 250; |
| CURSOR_VERTICAL_SHRINK = css_opts.getPropertyValue('--background-cursor-vertical-shrink') || 0.1; |
| SPEED_COEF = css_opts.getPropertyValue('--background-speed') || 1; |
| ENERGY_DECAY = css_opts.getPropertyValue('--energy-decay') || 2; |
| SHOW_IF_WIDER_THAN = css_opts.getPropertyValue('--background-show-if-wider-than') || 500; |
| MOVE_ON_CURSOR = css_opts.getPropertyValue('--background-move-on-cursor').includes("true") || false; |
|
|
| var nodes = []; |
| choice = (choices => choices[Math.floor(Math.random() * choices.length)]) |
| sample_color = () => choice([[40, 40, 40], [133, 133, 133]]) |
|
|
| ANCHOR_LENGTH = 20; |
|
|
| var cursor = {x: 0, y: 0}; |
|
|
| function centralize_cursor() { |
| var rect = document.getElementById("bug-logo").getBoundingClientRect() |
| var window_left = window.pageXOffset || document.documentElement.scrollLeft; |
| var window_top = window.pageYOffset || document.documentElement.scrollTop; |
| cursor.x = window_left + rect.left + rect.width / 2; |
| cursor.y = window_top + rect.top + rect.height / 2; |
| } |
|
|
| function Node(x, y) { |
| this.anchorX = x; |
| this.anchorY = y; |
| this.x = Math.random() * (x - (x - ANCHOR_LENGTH)) + (x - ANCHOR_LENGTH); |
| this.y = Math.random() * (y - (y - ANCHOR_LENGTH)) + (y - ANCHOR_LENGTH); |
| this.vx = (Math.random() * 2 - 1) * SPEED_COEF; |
| this.vy = (Math.random() * 2 - 1) * SPEED_COEF; |
| this.energy = Math.random() * 100; |
| this.radius = Math.random(); |
| this.siblings = []; |
| [this.r, this.g, this.b] = sample_color() |
| this.brightness = 0; |
| } |
|
|
| Node.prototype.drawNode = function() { |
| var color = `rgba(${this.r}, ${this.g}, ${this.b}, ${this.brightness})`; |
| ctx.beginPath(); |
| ctx.arc(this.x, this.y, 2 * this.radius + 2 * this.siblings.length / SIBLINGS_LIMIT, 0, 2 * Math.PI); |
| ctx.fillStyle = color; |
| ctx.fill(); |
| }; |
|
|
| Node.prototype.drawConnections = function() { |
| for (var i = 0; i < this.siblings.length; i++) { |
| var color = `rgba(133, 133, 133, ${this.brightness})`; |
| ctx.beginPath(); |
| ctx.moveTo(this.x, this.y); |
| ctx.lineTo(this.siblings[i].x, this.siblings[i].y); |
| ctx.lineWidth = 1 - calcDistance(this, this.siblings[i]) / SENSITIVITY; |
| ctx.strokeStyle = color; |
| ctx.stroke(); |
| } |
| }; |
|
|
|
|
| Node.prototype.moveNode = function() { |
| this.energy -= ENERGY_DECAY; |
| if (this.energy < 1) { |
| this.energy = Math.random() * 100; |
| if (this.x - this.anchorX < -ANCHOR_LENGTH) { |
| this.vx = Math.random() * SPEED_COEF; |
| } else if (this.x - this.anchorX > ANCHOR_LENGTH) { |
| this.vx = Math.random() * -SPEED_COEF; |
| } else { |
| this.vx = Math.random() * SPEED_COEF * 2 - SPEED_COEF; |
| } |
| if (this.y - this.anchorY < -ANCHOR_LENGTH) { |
| this.vy = Math.random() * SPEED_COEF; |
| } else if (this.y - this.anchorY > ANCHOR_LENGTH) { |
| this.vy = Math.random() * -SPEED_COEF; |
| } else { |
| this.vy = Math.random() * SPEED_COEF * 2 - SPEED_COEF; |
| } |
| } |
| relative_speed_rate = Math.min(canvas.height / 100, 10.0) |
| this.x += this.vx * this.energy * relative_speed_rate; |
| this.y += this.vy * this.energy * relative_speed_rate; |
| }; |
|
|
| function initNodes() { |
| centralize_cursor(); |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| if (canvas.width >= SHOW_IF_WIDER_THAN) |
| total_nodes = Math.round(NODE_DENSITY * (canvas.width / 100 * canvas.height / 100)); |
| else |
| total_nodes = 0; |
| nodes = []; |
| for (var i = 0; i < total_nodes; i++) |
| nodes.push(new Node(50 + Math.random() * (canvas.width - 100), |
| 5 + Math.random() * (canvas.height - 10))); |
| } |
|
|
| function calcDistance(node1, node2) { |
| return Math.sqrt(Math.pow(node1.x - node2.x, 2) + (Math.pow(node1.y - node2.y, 2))); |
| } |
|
|
| function findSiblings() { |
| var node1, node2, distance; |
| for (var i = 0; i < nodes.length; i++) { |
| node1 = nodes[i]; |
| node1.siblings = []; |
| for (var j = 0; j < nodes.length; j++) { |
| node2 = nodes[j]; |
| if (node1 !== node2) { |
| distance = calcDistance(node1, node2); |
| if (distance < SENSITIVITY) { |
| if (node1.siblings.length < SIBLINGS_LIMIT) { |
| node1.siblings.push(node2); |
| } else { |
| var node_sibling_distance = 0; |
| var max_distance = 0; |
| var s; |
| for (var k = 0; k < SIBLINGS_LIMIT; k++) { |
| node_sibling_distance = calcDistance(node1, node1.siblings[k]); |
| if (node_sibling_distance > max_distance) { |
| max_distance = node_sibling_distance; |
| s = k; |
| } |
| } |
| if (distance < max_distance) { |
| node1.siblings.splice(s, 1); |
| node1.siblings.push(node2); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
|
|
| function redrawScene() { |
| resizeWindow(); |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| findSiblings(); |
| var i, node, distance; |
| for (i = 0; i < nodes.length; i++) { |
| node = nodes[i]; |
| scaled_distance = calcDistance({x: cursor.x / CURSOR_WIDTH, y: cursor.y / CURSOR_HEIGHT}, |
| {x: node.x / CURSOR_WIDTH, y: node.y / CURSOR_HEIGHT}); |
|
|
| node.brightness = Math.max(1 - scaled_distance, 0); |
| } |
| for (i = 0; i < nodes.length; i++) { |
| node = nodes[i]; |
| if (node.brightness) { |
| node.drawConnections(); |
| node.drawNode(); |
| } |
| node.moveNode(); |
| } |
| requestAnimationFrame(redrawScene); |
| } |
|
|
| function initHandlers() { |
| document.addEventListener('resize', resizeWindow); |
| document.addEventListener('orientationchange', resizeWindow); |
| if (MOVE_ON_CURSOR) { |
| document.addEventListener('mousemove', moveHandler); |
| document.addEventListener('touchmove', moveHandler); |
| } |
| } |
|
|
| function resizeWindow(evt) { |
| var new_width, new_height; |
| new_width = Math.round(Math.max(title_elem.getBoundingClientRect().right, window.innerWidth)) |
| if (screen.width < 640) |
| title_text.style.fontSize = "20px"; |
| else |
| title_text.style.fontSize = "32px"; |
|
|
|
|
| if (!MOVE_ON_CURSOR) |
| new_height = Math.round(title_elem.getBoundingClientRect().top - canvas.getBoundingClientRect().top); |
| else |
| new_height = Math.round(Math.max( |
| content_element.offsetHeight, content_element.scrollHeight, |
| content_element.clientHeight, window.innerHeight)); |
|
|
| if (canvas.width != new_width || canvas.height != new_height) { |
| canvas.width = new_width; |
| canvas.height = new_height; |
| main_element.style.height = (title_elem.offsetHeight + title_elem.offsetTop + 10) + "px"; |
| initNodes(); |
| } |
| if (!MOVE_ON_CURSOR) |
| centralize_cursor(); |
| } |
|
|
| function moveHandler(evt) { |
| if (evt.type == "mousemove") { |
| cursor.x = window.pageXOffset + evt.clientX; |
| cursor.y = window.pageYOffset + evt.clientY; |
| } |
| else { |
| cursor.x = window.pageXOffset + evt.changedTouches[0].clientX; |
| cursor.y = window.pageYOffset + evt.changedTouches[0].clientY; |
| } |
| } |
|
|
| initHandlers(); |
| initNodes(); |
| redrawScene(); |
|
|
| })(); |