Interactive Blackhole
Home
Snippets
Interactive Blackhole
HTML
CSS
JS
<div id="blackhole"> <div class="centerHover"><span>ENTER</span></div> </div>
body, html { height: 100%; margin: 0; padding: 0; } body { height: 100%; background-color: rgba(25,25,25,1); overflow: hidden; } #blackhole { height: 100%; width: 100%; position: relative; display: flex; } .centerHover { width: 255px; height: 255px; background-color: transparent; border-radius: 50%; position: absolute; left: 50%; top: 50%; margin-top: -128px; margin-left: -128px; z-index: 2; cursor: pointer; line-height: 255px; text-align: center; transition: all 500ms; } .centerHover.open { opacity: 0; pointer-events: none; } .centerHover:hover span { color: #DDD; } .centerHover:hover span:before { background-color: #DDD; } .centerHover:hover span:after { background-color: #DDD; } .centerHover span { color: #666; font-family: serif; font-size: 18px; position: relative; transition: all 500ms; } .centerHover span:before { content: ''; display: inline-block; height: 1px; width: 16px; margin-right: 12px; margin-bottom: 4px; background-color: #666; transition: all 500ms; } .centerHover span:after { content: ''; display: inline-block; height: 1px; width: 16px; margin-left: 12px; margin-bottom: 4px; background-color: #666; transition: all 500ms; } canvas { position: relative; z-index: 1; width: 100%; height: 100%; margin: auto; } #blackhole { height: 100%; width: 100%; position: relative; display: flex; } .centerHover { width: 255px; height: 255px; background-color: transparent; border-radius: 50%; position: absolute; left: 50%; top: 50%; margin-top: -128px; margin-left: -128px; z-index: 2; cursor: pointer; line-height: 255px; text-align: center; transition: all 500ms; } .centerHover.open { opacity: 0; pointer-events: none; } .centerHover:hover span { color: #DDD; } .centerHover:hover span:before { background-color: #DDD; } .centerHover:hover span:after { background-color: #DDD; } .centerHover span { color: #666; font-family: serif; font-size: 18px; position: relative; transition: all 500ms; } .centerHover span:before { content: ''; display: inline-block; height: 1px; width: 16px; margin-right: 12px; margin-bottom: 4px; background-color: #666; transition: all 500ms; } .centerHover span:after { content: ''; display: inline-block; height: 1px; width: 16px; margin-left: 12px; margin-bottom: 4px; background-color: #666; transition: all 500ms; } canvas { position: relative; z-index: 1; width: 100%; height: 100%; margin: auto; }
function blackhole(element) { const container = document.querySelector(element); const h = container.offsetHeight; const w = container.offsetWidth; const cw = w; const ch = h; const maxorbit = 255; const centery = ch / 2; const centerx = cw / 2; const startTime = new Date().getTime(); let currentTime = 0; const stars = []; let collapse = false; let expanse = false; let returning = false; const canvas = document.createElement('canvas'); canvas.width = cw; canvas.height = ch; container.appendChild(canvas); const context = canvas.getContext("2d"); context.globalCompositeOperation = "multiply"; function setDPI(canvas, dpi) { if (!canvas.style.width) canvas.style.width = canvas.width + 'px'; if (!canvas.style.height) canvas.style.height = canvas.height + 'px'; const scaleFactor = dpi / 96; canvas.width = Math.ceil(canvas.width * scaleFactor); canvas.height = Math.ceil(canvas.height * scaleFactor); const ctx = canvas.getContext('2d'); ctx.scale(scaleFactor, scaleFactor); } function rotate(cx, cy, x, y, angle) { const radians = angle; const cos = Math.cos(radians); const sin = Math.sin(radians); const nx = (cos * (x - cx)) + (sin * (y - cy)) + cx; const ny = (cos * (y - cy)) - (sin * (x - cx)) + cy; return [nx, ny]; } setDPI(canvas, 192); class Star { constructor() { const rands = []; rands.push(Math.random() * (maxorbit / 2) + 1); rands.push(Math.random() * (maxorbit / 2) + maxorbit); this.orbital = (rands.reduce((p, c) => p + c, 0) / rands.length); this.x = centerx; this.y = centery + this.orbital; this.yOrigin = centery + this.orbital; this.speed = (Math.floor(Math.random() * 2.5) + 1.5) * Math.PI / 180; this.rotation = 0; this.startRotation = (Math.floor(Math.random() * 360) + 1) * Math.PI / 180; this.id = stars.length; this.collapseBonus = this.orbital - (maxorbit * 0.7); if (this.collapseBonus < 0) { this.collapseBonus = 0; } this.color = 'rgba(255,255,255,' + (1 - ((this.orbital) / 255)) + ')'; this.hoverPos = centery + (maxorbit / 2) + this.collapseBonus; this.expansePos = centery + (this.id % 100) * -10 + (Math.floor(Math.random() * 20) + 1); this.prevR = this.startRotation; this.prevX = this.x; this.prevY = this.y; this.originalY = this.yOrigin; stars.push(this); } draw() { if (!expanse && !returning) { this.rotation = this.startRotation + (currentTime * this.speed); if (!collapse) { if (this.y > this.yOrigin) { this.y -= 2.5; } if (this.y < this.yOrigin - 4) { this.y += (this.yOrigin - this.y) / 10; } } else { this.trail = 1; if (this.y > this.hoverPos) { this.y -= (this.hoverPos - this.y) / -5; } if (this.y < this.hoverPos - 4) { this.y += 2.5; } } } else if (expanse && !returning) { this.rotation = this.startRotation + (currentTime * (this.speed / 2)); if (this.y > this.expansePos) { this.y -= Math.floor(this.expansePos - this.y) / -80; } } else if (returning) { this.rotation = this.startRotation + (currentTime * this.speed); if (Math.abs(this.y - this.originalY) > 2) { this.y += (this.originalY - this.y) / 50; } else { this.y = this.originalY; this.yOrigin = this.originalY; } } context.save(); context.fillStyle = this.color; context.strokeStyle = this.color; context.beginPath(); const oldPos = rotate(centerx, centery, this.prevX, this.prevY, -this.prevR); context.moveTo(oldPos[0], oldPos[1]); context.translate(centerx, centery); context.rotate(this.rotation); context.translate(-centerx, -centery); context.lineTo(this.x, this.y); context.stroke(); context.restore(); this.prevR = this.rotation; this.prevX = this.x; this.prevY = this.y; } } const centerHover = document.querySelector('.centerHover'); centerHover.addEventListener('click', function() { collapse = false; expanse = true; returning = false; this.classList.add('open'); setTimeout(() => { expanse = false; returning = true; setTimeout(() => { returning = false; this.classList.remove('open'); }, 8000); }, 25000); }); centerHover.addEventListener('mouseover', function() { if (expanse === false) { collapse = true; } }); centerHover.addEventListener('mouseout', function() { if (expanse === false) { collapse = false; } }); function loop() { const now = new Date().getTime(); currentTime = (now - startTime) / 50; context.fillStyle = 'rgba(25,25,25,0.2)'; context.fillRect(0, 0, cw, ch); for (let i = 0; i < stars.length; i++) { if (stars[i] !== undefined) { stars[i].draw(); } } requestAnimationFrame(loop); } function init() { context.fillStyle = 'rgba(25,25,25,1)'; context.fillRect(0, 0, cw, ch); for (let i = 0; i < 2500; i++) { new Star(); } loop(); } init(); } document.addEventListener('DOMContentLoaded', () => { blackhole('#blackhole'); })
Ad #1
Ad #2
Scroll to Top