马黑黑 发表于 2022-8-16 07:12

仲夏

<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>

马黑黑 发表于 2022-8-16 07:12

代码分享(全码):
<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>

马黑黑 发表于 2022-8-16 07:16

特别说明:

画布特效改装自开源代码。原来的效果是全屏效果,不重复演化,动画运行一次,然后通过对页面的单击或改变浏览器窗口大小来触发动画。

代码中,实现机制和代码构造比较复杂,不解释了,大家从中领略到画布之神奇和JS之强大就好,喜欢的话可以直接或间接套用。

马黑黑 发表于 2022-8-16 07:22

本帖最后由 马黑黑 于 2022-8-16 12:18 编辑

相对于之前我所发布的动画特效,这个效果是个吃内存大户,监视发现,纯净运行时,它消耗10多Mb到50MB不等的内存;而我之前的画布作品,内存消耗一般在 2Mb 上下。

但不用担心内存不够的问题,毕竟,内存就是用了用的。现在的电脑、手机,8Gb内存(指运行内存,简称运存)是起步、标配。

我在 4Gb 的机器上测试,运行此页面并无障碍。

加林森 发表于 2022-8-16 08:19

先来看看。等会上电脑瞧瞧。

青青子衿 发表于 2022-8-16 08:49

惊艳。。。小马黑黑老师,辛苦了

梦油 发表于 2022-8-16 09:08

变幻无穷的美图,再配上优美的乐曲,真是无与伦比啦!

樵歌 发表于 2022-8-16 09:31

绚丽灿烂的仲夏夜之梦实现啦

马黑黑 发表于 2022-8-16 12:17

青青子衿 发表于 2022-8-16 08:49
惊艳。。。小马黑黑老师,辛苦了

一起辛苦{:4_190:}

马黑黑 发表于 2022-8-16 12:17

樵歌 发表于 2022-8-16 09:31
绚丽灿烂的仲夏夜之梦实现啦

玉皇大帝亲自迎接了木有

马黑黑 发表于 2022-8-16 12:18

加林森 发表于 2022-8-16 08:19
先来看看。等会上电脑瞧瞧。

手机也可以看清楚看全的,用电脑版,拉到底部有选择

马黑黑 发表于 2022-8-16 12:19

梦油 发表于 2022-8-16 09:08
变幻无穷的美图,再配上优美的乐曲,真是无与伦比啦!

感谢支持。请用好茶{:4_190:}

红影 发表于 2022-8-16 12:21

从帖子中领略“画布之神奇和JS之强大”,还真是如此,太惊艳了{:4_199:}

红影 发表于 2022-8-16 12:25

很炫酷的光线爆炸效果,而且是循环播放,每次颜色不同。这个太漂亮了{:4_199:}

加林森 发表于 2022-8-16 12:38

马黑黑 发表于 2022-8-16 12:18
手机也可以看清楚看全的,用电脑版,拉到底部有选择

我刚才就是用手机看的。快得很。

马黑黑 发表于 2022-8-16 13:05

红影 发表于 2022-8-16 12:25
很炫酷的光线爆炸效果,而且是循环播放,每次颜色不同。这个太漂亮了

很惊艳吧

马黑黑 发表于 2022-8-16 13:06

红影 发表于 2022-8-16 12:21
从帖子中领略“画布之神奇和JS之强大”,还真是如此,太惊艳了

是的是的

梦油 发表于 2022-8-16 14:32

马黑黑 发表于 2022-8-16 12:19
感谢支持。请用好茶

谢谢你的香茶。

樵歌 发表于 2022-8-16 19:07

马黑黑 发表于 2022-8-16 12:17
玉皇大帝亲自迎接了木有

这个因沙翁主持的,沒请俺呵{:4_173:}

马黑黑 发表于 2022-8-16 19:07

樵歌 发表于 2022-8-16 19:07
这个因沙翁主持的,沒请俺呵

额,受冷落了
页: [1] 2 3 4
查看完整版本: 仲夏