剪藏#前端嘛#剪藏
进入黑洞(可复制源代码)
2025 年 7 月 15 日 约 1 分钟


📦 拖到文章底部,点击 阅读原文,可一键复制完整源码
JAVASCRIPT
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>黑洞视觉化</title>
<style>
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-fJAVASCRIPT
amily: 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;}
</style>
</head>
<body>
<div id="blackhole">
<div class="centerHover"><span>点击进入</span></div>
</div>
<script>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 +JAVASCRIPT
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.querySelectorJAVASCRIPT
(".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");}, 2000);}, 5000);}); 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");}); </script>
</body>
</html>点击下方👇🏻 阅读原文【在线预览/一键复制源代码】