<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>颗粒时钟</title></head><style>* {
margin: 0;
padding: 0;
}
html,body{
overflow: hidden;
}
canvas {
background: radial-gradient(#fff, #8c738c);display: block;
}
</style><body><canvas></canvas></body></html><script>constcanvas=document.querySelector('canvas')
constctx=canvas.getContext('2d', {
willReadFrequently: true })
constPARTICLE_NUM=15000lettext=''constFONT_SIZE=140;
constparticles=newArray(PARTICLE_NUM)
constCOLOR='#5445544d';
constSIZES= [2, 7];
letstartMoveTime=0;
functiongetRandom(min, max) {
returnMath.floor(Math.random() * (max+1-min) +min);
}
functioninit() {
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
constcx=canvas.width/2,
cy=canvas.height/2;
for (leti=0; i<particles.length; i++) {
constrad=Math.random() *2*Math.PI;
constsize=getRandom(SIZES[0], SIZES[1]);
constr=canvas.height/2;
particles[i] = {
sx: cx+Math.cos(rad) *r,
sy: cy+Math.sin(rad) *r,
x: cx+Math.cos(rad) *r,
y: cy+Math.sin(rad) *r,
size };
drawParticle(particles[i])
}
}
functionfps() {
requestAnimationFrame((time) => {
constcurText=getText();
if (curText!==text) {
text=curText;for (constpofparticles) {
p.sx=p.x;
p.sy=p.y;
}
startMoveTime=Date.now()
}
constimgData=getBMP();
update(imgData);
fps()
})
}
fps()
functiondrawParticle(p) {
ctx.fillStyle=COLOR;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI*2,true)
ctx.closePath();
ctx.fill()
}
functiongetText() {
varnow=newDate();
varyear=now.getFullYear(); varmonth=now.getMonth() +1; varday=now.getDate(); varhh=now.getHours(); varmm=now.getMinutes(); varss=now.getSeconds(); varclock=year+"-";
if(month<10)
clock+="0";
clock+=month+"-";
if(day<10)
clock+="0";
clock+=day+" ";
if(hh<10)
clock+="0";
clock+=hh+":";
if (mm<10) clock+='0';
if (ss<10) clock+='0';
clock+=mm+":"+ss;
return(clock);
}
functiongetBMP() {
const {width, height} =canvas;
clear()
ctx.fillStyle='#fff';
ctx.textBaseline='middle';
ctx.font=`${FONT_SIZE}px '手札体-简', sans-serif`;
consttextWidth=ctx.measureText(text).width;
ctx.fillText(text, (width-textWidth) /2, height/2);
constimgData=ctx.getImageData(0, 0, width, height)
returnimgData }
functionupdate(imgData) {
clear();
const {width, height, data} =imgDataconstdis=4constpxls= [];
for (letw=0; w<width; w+=dis) {
for (leth=0; h<height; h+=dis) {
consti= (w+h*width) *4;
if (data[i] >10) {
pxls.push([w, h]);
}
}
}
constcount=Math.min(particles.length , pxls.length)
constduration=400;
consttimeSpan=Date.now() -startMoveTimefor (leti=0; i<count; i++) {
constp=particles[i];
constsx=p.sx;
constsy=p.sy;
consttx=pxls[i][0];
constty=pxls[i][1];
constdisX=tx-sx,
disY=ty-sy;
letmoveX= (disX/duration) *timeSpan,
moveY= (disY/duration) *timeSpan;
if (Math.abs(moveX) >Math.abs(disX)){
moveX=disX }
if (Math.abs(moveY) >Math.abs(disY)){
moveY=disY }
p.x=sx+moveX;
p.y=sy+moveY;
drawParticle(p)
}
}
functionclear() {
const {width , height} =canvas;
ctx.clearRect(0,0,width,height);
}
init();
</script>