马黑黑 发表于 2022-8-10 07:11

风止

<style>
#papa { left: -214px; width: 1024px; height: 640px;background: rgba(0,0,0,.65) url('https://638183.freep.cn/638183/Pic/38/lake5.jpg') no-repeat center/cover; box-shadow: 3px 3px 20px #000; display: grid; place-items: center; position: relative; }
#mama { position: absolute; width: 600px; height: 600px; right: 20px; }
#canv { position: absolute; border-radius: 50%; }
#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; animation: rot 2s linear infinite; }
#tit { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: snow; text-shadow: 2px 2px 4px black; }
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="papa">
        <div id="mama"><canvas id="canv"></canvas></div>
        <span id="disc"></span>
        <span id="tit">风止</span>
</div>

<script>
let ctx = canv.getContext('2d');
let w = canv.width = mama.offsetWidth, h = canv.height = mama.offsetHeight;
let objAr = new Array(50), speed = 1, curve = 0.45, idx = 0, aud = new Audio();
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;

aud.src = 'https://music.163.com/song/media/outer/url?id=1947739273.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');

for(let k = 0; k < objAr.length; k ++) {
        let cc = `rgba(${num(0,255)}, ${num(0,255)}, ${num(0,255)}, .75)`;
        objAr = new Obj(w/2, h/2, 2, k*360/objAr.length, cc);
}

function Obj(x,y,size,angle,color) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.angle = angle;
        this.color = color;
}

Obj.prototype.draw = function() {
        ctx.beginPath();
        ctx.fillStyle = this.color
        ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
        ctx.fill();
}

Obj.prototype.move = function() {
        let rad = this.angle * Math.PI / 180;
        this.x += Math.cos(rad) * speed;
        this.y += Math.sin(rad) * speed;
        this.angle += curve;
}

function render() {
        idx ++;
        if(idx > 800) ctx.clearRect(0,0,w,h);
        if(idx > 1600) idx = 0;
        for(item of objAr) {
                item.draw();
                item.move();
        }
        requestAnimationFrame(render);
}
render();
</script>

马黑黑 发表于 2022-8-10 07:17

代码分享:
<style>
#papa { left: -214px; width: 1024px; height: 640px;background: rgba(0,0,0,.65) url('https://638183.freep.cn/638183/Pic/38/lake5.jpg') no-repeat center/cover; box-shadow: 3px 3px 20px #000; display: grid; place-items: center; position: relative; }
#mama { position: absolute; width: 600px; height: 600px; right: 20px; }
#canv { position: absolute; border-radius: 50%; }
#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; animation: rot 2s linear infinite; }
#tit { position: absolute; left: 60px; top: 10px;font: bold 22px / 40px sans-serif; color: snow; text-shadow: 2px 2px 4px black; }
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="papa">
        <div id="mama"><canvas id="canv"></canvas></div>
        <span id="disc"></span>
        <span id="tit">风止</span>
</div>

<script>
let ctx = canv.getContext('2d');
let w = canv.width = mama.offsetWidth, h = canv.height = mama.offsetHeight;
let objAr = new Array(50), speed = 1, curve = 0.45, idx = 0, aud = new Audio();
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;

aud.src = 'https://music.163.com/song/media/outer/url?id=1947739273.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');

for(let k = 0; k < objAr.length; k ++) {
        let cc = `rgba(${num(0,255)}, ${num(0,255)}, ${num(0,255)}, .75)`;
        objAr = new Obj(w/2, h/2, 2, k*360/objAr.length, cc);
}

function Obj(x,y,size,angle,color) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.angle = angle;
        this.color = color;
}

Obj.prototype.draw = function() {
        ctx.beginPath();
        ctx.fillStyle = this.color
        ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
        ctx.fill();
}

Obj.prototype.move = function() {
        let rad = this.angle * Math.PI / 180;
        this.x += Math.cos(rad) * speed;
        this.y += Math.sin(rad) * speed;
        this.angle += curve;
}

function render() {
        idx ++;
        if(idx > 800) ctx.clearRect(0,0,w,h);
        if(idx > 1600) idx = 0;
        for(item of objAr) {
                item.draw();
                item.move();
        }
        requestAnimationFrame(render);
}
render();
</script>

马黑黑 发表于 2022-8-10 07:45

本帖最后由 马黑黑 于 2022-8-10 18:37 编辑

原理解释:

一、帖子实现思路

将画布视为帖子的组成部分,除播放器外,帖子的动画效果由画布实现,位于帖子右边部分。

二、canvas动画

(一)对象专属动画函数 Obj.prototype.draw 是非常常规的绘图封装,它负责画圆:

Obj.prototype.draw = function() {
      ctx.beginPath(); //开启画笔路径
      ctx.fillStyle = this.color; //填充色
      ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);//画圆
      ctx.fill(); //着色
}


(二)对象专属动画函数 Obj.prototype.move处理圆心位置、变换角度的变更:

Obj.prototype.move = function() {
      let rad = this.angle * Math.PI / 180; //角度系数 :对象所在坐标系角度乘以PI除以180
      this.x += Math.cos(rad) * speed; //圆心X坐标 :余弦乘以预设速度
      this.y += Math.sin(rad) * speed; //圆心Y坐标 :正弦乘以预设速度
      this.angle += curve; //对象改变角度从而改变位置 :自身当前角度加上预设角度
}


预设的速度 speed 和 变化角度 curve 共同影响对象环绕运行的半径,故此,speed 和 curve 的设定很重要。

(三)渲染函数 render

function render() {
      idx ++; //idx是预设变量,初始值0,每次刷新加1,其值用以决定运动对象的形态
      if(idx > 800) ctx.clearRect(0,0,w,h); //当 idx 大于800,清除画布 :对象为圆球(此前不擦除,圆球连接成环绕线)
      if(idx > 1600) idx = 0; //当 idx 大于1600,idx 重置为初始值
      for(item of objAr) { //遍历对象数组 objAr 的每一个元素,并令其
                item.draw(); //绘制
                item.move(); //变更数据
      }
      requestAnimationFrame(render); //请求动画帧 :利用屏幕刷新运行本函数 → 动画永动
}


render 渲染函数是普通函数,它负责两个任务,一是是否擦除画布,二是调动所有对象去执行对象专属的两个函数。


马黑黑 发表于 2022-8-10 07:49

本帖设计思路以及代码结构可以解决canvas画布用于帖子时的多数变化形态:

画不同形状的对象,修改 draw 函数;
需要不同形态的运动,修改 move 函数;
修改 render 函数相关内容,可达成其他效果。

马黑黑 发表于 2022-8-10 07:52

两个小教程可以帮助理解更多:

一、https://www.huachaowang.com/forum.php?mod=viewthread&tid=61993&extra=page%3D1

二、https://www.huachaowang.com/forum.php?mod=viewthread&tid=62016&extra=page%3D1

加林森 发表于 2022-8-10 08:15

等会上电脑来看。好漂亮的制作。赞!{:4_199:}

梦油 发表于 2022-8-10 09:53

变幻无穷、目不暇接,你设计制作得尽善尽美。

马黑黑 发表于 2022-8-10 12:32

梦油 发表于 2022-8-10 09:53
变幻无穷、目不暇接,你设计制作得尽善尽美。

演示一下效果,没达到完美的

马黑黑 发表于 2022-8-10 12:32

加林森 发表于 2022-8-10 08:15
等会上电脑来看。好漂亮的制作。赞!

不知手机看到的效果如何

加林森 发表于 2022-8-10 12:39

马黑黑 发表于 2022-8-10 12:32
不知手机看到的效果如何

手机上看速度很快的。我也跟到制作了一个太极的。没有做好就不发出来。

加林森 发表于 2022-8-10 12:49

老黑,我在想如何把你这个转换成太极八封呢。

加林森 发表于 2022-8-10 12:49

老黑,我在想如何把你这个转换成太极八封呢。

马黑黑 发表于 2022-8-10 12:49

加林森 发表于 2022-8-10 12:39
手机上看速度很快的。我也跟到制作了一个太极的。没有做好就不发出来。

不急,测试好了再发布

加林森 发表于 2022-8-10 12:51

马黑黑 发表于 2022-8-10 12:49
不急,测试好了再发布

嗯嗯,明白的。

马黑黑 发表于 2022-8-10 12:57

加林森 发表于 2022-8-10 12:49
老黑,我在想如何把你这个转换成太极八封呢。
这个对你来说有些难度。你还是用CSS关键帧动画去完成比较容易上手

加林森 发表于 2022-8-10 13:04

马黑黑 发表于 2022-8-10 12:57
这个对你来说有些难度。你还是用CSS关键帧动画去完成比较容易上手

嗯嗯。我去换一下试试。

梦油 发表于 2022-8-10 13:13

马黑黑 发表于 2022-8-10 12:32
演示一下效果,没达到完美的

我看这已经很好啦

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

梦油 发表于 2022-8-10 13:13
我看这已经很好啦

还可以的吧

红影 发表于 2022-8-10 15:22

这图案好美,代码真强大,黑黑真厉害{:4_187:}

马黑黑 发表于 2022-8-10 18:30

红影 发表于 2022-8-10 15:22
这图案好美,代码真强大,黑黑真厉害

不擦除就是圆环,每次刷新都擦除就是球球。这没没啥的
页: [1] 2
查看完整版本: 风止