仲夏
<style>#papa { left: -214px; width: 1024px; height: 680px; display: grid; place-items: center; background: #000 url('https://638183.freep.cn/638183/t22/51/7036.jpg') no-repeat center/cover; box-shadow: 3px 3px 30px #000; position: relative; }
#canv { position: absolute; }
#papa { margin: auto; width: 1024px; height: 640px; box-shadow: 3px 3px 20px #000; position: relative; }
#disc { position: absolute; width: 40px; height: 40px; left: 10px; top: 10px; background: conic-gradient(red,orange,yellow,green,teal,blue,purple); mask: radial-gradient(transparent 4px,red 0); -webkit-mask: radial-gradient(transparent 4px,red 0); border-radius: 50%; cursor: pointer; z-index: 10; animation: rot 2s linear infinite; }
#lrcbox { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: lightblue; text-shadow: 2px 2px 4px #222; }
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa">
<span id="disc"></span>
<span id="lrcbox">四季音色 - 仲夏</span>
<canvas id="canv"></canvas>
</div>
<script>
let ctx, w, h, cx, cy, branches, startHue, tick;
let aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=468005471.mp3';
aud.loop = true;
aud.autoplay = true;
disc.style.animationPlayState = aud.paused ? 'paused' : 'running';
disc.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('playing',()=> disc.style.animationPlayState = 'running');
aud.addEventListener('pause',()=> disc.style.animationPlayState = 'paused');
let rNum = ( min, max ) => Math.random() * ( max - min ) + min;
let iNum = ( min, max ) => Math.floor( min + Math.random() * ( max - min + 1 ));
function Branch(hue, x, y, angle, vel) {
let move = 15;
this.x = x + rNum(-move, move);
this.y = y + rNum(-move, move);
this.points = [];
this.angle = angle != undefined ? angle : rNum(0, Math.PI * 1);
this.vel = vel != undefined ? vel : rNum(-4, 4);
this.spread = 0;
this.tick = 0;
this.hue = hue != undefined ? hue : 200;
this.life = 1;
this.decay = 0.0015;
this.dead = false;
this.points.push({
x: this.x,
y: this.y
});
}
Branch.prototype.step = function(i) {
this.life -= this.decay;
if( this.life <= 0 ) {
this.dead = true;
}
if(!this.dead) {
let lastPoint = this.points;
this.points.push({
x: lastPoint.x + Math.cos(this.angle) * this.vel,
y: lastPoint.y + Math.sin(this.angle) * this.vel
});
this.angle += rNum(-this.spread, this.spread);
this.vel *= 0.99;
this.spread = this.vel * 0.04;
this.tick++;
this.hue += 0.3;
} else {
branches.splice(i, 1);
}
};
Branch.prototype.draw = function() {
if(!this.points.length || this.dead) {
return false;
}
let length = this.points.length,
i = length - 1,
point = this.points,
lastPoint = this.points;
if(lastPoint) {
let jitter = 2 + this.life * 6;
ctx.beginPath();
ctx.moveTo(lastPoint.x, lastPoint.y);
ctx.lineTo(point.x + rNum(-jitter, jitter), point.y + rNum(-jitter, jitter));
ctx.lineWidth = 1;
let alpha = this.life * 0.075;
ctx.strokeStyle = 'hsla(' + (this.hue + rNum(-10, 10)) + ', 70%, 40%, ' + alpha + ')';
ctx.stroke();
}
}
function init() {
ctx = canv.getContext('2d');
startHue = 220;
branches = [];
reset();
loop();
}
function reset() {
w = canv.width = papa.offsetWidth;
h = canv.height = papa.offsetHeight;
cx = w / 2;
cy = h / 2;
branches.length = 0;
canv.width = w;
canv.height = h;
tick = 0;
for(let i = 0; i < 500; i++) {
branches.push(new Branch( startHue, cx, cy));
}
}
function step() {
let i = branches.length;
while(i--) { branches[ i ].step( i ) }
tick++;
}
function draw() {
let i = branches.length;
if( tick < 450 ) {
ctx.save();
ctx.globalCompositeOperation = 'lighter';
ctx.globalAlpha = 0.002;
ctx.translate(cx, cy);
let scale = 1 + tick * 0.00025 ;
ctx.scale(scale, scale);
ctx.translate(-cx, -cy);
ctx.drawImage(canv, rNum(-150, 150), rNum(-150, 150));
ctx.restore();
}
ctx.globalCompositeOperation = 'lighter';
while(i--) { branches[ i ].draw() }
}
function loop() {
requestAnimationFrame(loop);
step();
draw();
step();
draw();
}
setInterval(()=> {
startHue += 60;
reset();
},8000);
init();
</script>
代码分享(全码):
<style>
#papa { margin: auto; width: 1024px; height: 680px; display: grid; place-items: center; background: #000 url('https://638183.freep.cn/638183/t22/51/7036.jpg') no-repeat center/cover; box-shadow: 3px 3px 30px #000; position: relative; }
#canv { position: absolute; }
#papa { margin: auto; width: 1024px; height: 640px; box-shadow: 3px 3px 20px #000; position: relative; }
#disc { position: absolute; width: 40px; height: 40px; left: 10px; top: 10px; background: conic-gradient(red,orange,yellow,green,teal,blue,purple); mask: radial-gradient(transparent 4px,red 0); -webkit-mask: radial-gradient(transparent 4px,red 0); border-radius: 50%; cursor: pointer; z-index: 10; animation: rot 2s linear infinite; }
#lrcbox { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: lightblue; text-shadow: 2px 2px 4px #222; }
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa">
<span id="disc"></span>
<span id="lrcbox">四季音色 - 仲夏</span>
<canvas id="canv"></canvas>
</div>
<script>
let ctx, w, h, cx, cy, branches, startHue, tick;
let aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=468005471.mp3';
aud.loop = true;
aud.autoplay = true;
disc.style.animationPlayState = aud.paused ? 'paused' : 'running';
disc.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('playing',()=> disc.style.animationPlayState = 'running');
aud.addEventListener('pause',()=> disc.style.animationPlayState = 'paused');
let rNum = ( min, max ) => Math.random() * ( max - min ) + min;
let iNum = ( min, max ) => Math.floor( min + Math.random() * ( max - min + 1 ));
function Branch(hue, x, y, angle, vel) {
let move = 15;
this.x = x + rNum(-move, move);
this.y = y + rNum(-move, move);
this.points = [];
this.angle = angle != undefined ? angle : rNum(0, Math.PI * 1);
this.vel = vel != undefined ? vel : rNum(-4, 4);
this.spread = 0;
this.tick = 0;
this.hue = hue != undefined ? hue : 200;
this.life = 1;
this.decay = 0.0015;
this.dead = false;
this.points.push({
x: this.x,
y: this.y
});
}
Branch.prototype.step = function(i) {
this.life -= this.decay;
if( this.life <= 0 ) {
this.dead = true;
}
if(!this.dead) {
let lastPoint = this.points;
this.points.push({
x: lastPoint.x + Math.cos(this.angle) * this.vel,
y: lastPoint.y + Math.sin(this.angle) * this.vel
});
this.angle += rNum(-this.spread, this.spread);
this.vel *= 0.99;
this.spread = this.vel * 0.04;
this.tick++;
this.hue += 0.3;
} else {
branches.splice(i, 1);
}
};
Branch.prototype.draw = function() {
if(!this.points.length || this.dead) {
return false;
}
let length = this.points.length,
i = length - 1,
point = this.points,
lastPoint = this.points;
if(lastPoint) {
let jitter = 2 + this.life * 6;
ctx.beginPath();
ctx.moveTo(lastPoint.x, lastPoint.y);
ctx.lineTo(point.x + rNum(-jitter, jitter), point.y + rNum(-jitter, jitter));
ctx.lineWidth = 1;
let alpha = this.life * 0.075;
ctx.strokeStyle = 'hsla(' + (this.hue + rNum(-10, 10)) + ', 70%, 40%, ' + alpha + ')';
ctx.stroke();
}
}
function init() {
ctx = canv.getContext('2d');
startHue = 220;
branches = [];
reset();
loop();
}
function reset() {
w = canv.width = papa.offsetWidth;
h = canv.height = papa.offsetHeight;
cx = w / 2;
cy = h / 2;
branches.length = 0;
canv.width = w;
canv.height = h;
tick = 0;
for(let i = 0; i < 500; i++) {
branches.push(new Branch( startHue, cx, cy));
}
}
function step() {
let i = branches.length;
while(i--) { branches[ i ].step( i ) }
tick++;
}
function draw() {
let i = branches.length;
if( tick < 450 ) {
ctx.save();
ctx.globalCompositeOperation = 'lighter';
ctx.globalAlpha = 0.002;
ctx.translate(cx, cy);
let scale = 1 + tick * 0.00025 ;
ctx.scale(scale, scale);
ctx.translate(-cx, -cy);
ctx.drawImage(canv, rNum(-150, 150), rNum(-150, 150));
ctx.restore();
}
ctx.globalCompositeOperation = 'lighter';
while(i--) { branches[ i ].draw() }
}
function loop() {
requestAnimationFrame(loop);
step();
draw();
step();
draw();
}
setInterval(()=> {
startHue += 60;
reset();
},8000);
init();
</script>
特别说明:
画布特效改装自开源代码。原来的效果是全屏效果,不重复演化,动画运行一次,然后通过对页面的单击或改变浏览器窗口大小来触发动画。
代码中,实现机制和代码构造比较复杂,不解释了,大家从中领略到画布之神奇和JS之强大就好,喜欢的话可以直接或间接套用。 本帖最后由 马黑黑 于 2022-8-16 12:18 编辑
相对于之前我所发布的动画特效,这个效果是个吃内存大户,监视发现,纯净运行时,它消耗10多Mb到50MB不等的内存;而我之前的画布作品,内存消耗一般在 2Mb 上下。
但不用担心内存不够的问题,毕竟,内存就是用了用的。现在的电脑、手机,8Gb内存(指运行内存,简称运存)是起步、标配。
我在 4Gb 的机器上测试,运行此页面并无障碍。 先来看看。等会上电脑瞧瞧。 惊艳。。。小马黑黑老师,辛苦了 变幻无穷的美图,再配上优美的乐曲,真是无与伦比啦! 绚丽灿烂的仲夏夜之梦实现啦 青青子衿 发表于 2022-8-16 08:49
惊艳。。。小马黑黑老师,辛苦了
一起辛苦{:4_190:} 樵歌 发表于 2022-8-16 09:31
绚丽灿烂的仲夏夜之梦实现啦
玉皇大帝亲自迎接了木有 加林森 发表于 2022-8-16 08:19
先来看看。等会上电脑瞧瞧。
手机也可以看清楚看全的,用电脑版,拉到底部有选择 梦油 发表于 2022-8-16 09:08
变幻无穷的美图,再配上优美的乐曲,真是无与伦比啦!
感谢支持。请用好茶{:4_190:} 从帖子中领略“画布之神奇和JS之强大”,还真是如此,太惊艳了{:4_199:} 很炫酷的光线爆炸效果,而且是循环播放,每次颜色不同。这个太漂亮了{:4_199:} 马黑黑 发表于 2022-8-16 12:18
手机也可以看清楚看全的,用电脑版,拉到底部有选择
我刚才就是用手机看的。快得很。 红影 发表于 2022-8-16 12:25
很炫酷的光线爆炸效果,而且是循环播放,每次颜色不同。这个太漂亮了
很惊艳吧 红影 发表于 2022-8-16 12:21
从帖子中领略“画布之神奇和JS之强大”,还真是如此,太惊艳了
是的是的 马黑黑 发表于 2022-8-16 12:19
感谢支持。请用好茶
谢谢你的香茶。 马黑黑 发表于 2022-8-16 12:17
玉皇大帝亲自迎接了木有
这个因沙翁主持的,沒请俺呵{:4_173:} 樵歌 发表于 2022-8-16 19:07
这个因沙翁主持的,沒请俺呵
额,受冷落了