风止
<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> 代码分享:
<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 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 渲染函数是普通函数,它负责两个任务,一是是否擦除画布,二是调动所有对象去执行对象专属的两个函数。
本帖设计思路以及代码结构可以解决canvas画布用于帖子时的多数变化形态:
画不同形状的对象,修改 draw 函数;
需要不同形态的运动,修改 move 函数;
修改 render 函数相关内容,可达成其他效果。 两个小教程可以帮助理解更多:
一、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 等会上电脑来看。好漂亮的制作。赞!{:4_199:} 变幻无穷、目不暇接,你设计制作得尽善尽美。 梦油 发表于 2022-8-10 09:53
变幻无穷、目不暇接,你设计制作得尽善尽美。
演示一下效果,没达到完美的 加林森 发表于 2022-8-10 08:15
等会上电脑来看。好漂亮的制作。赞!
不知手机看到的效果如何 马黑黑 发表于 2022-8-10 12:32
不知手机看到的效果如何
手机上看速度很快的。我也跟到制作了一个太极的。没有做好就不发出来。 老黑,我在想如何把你这个转换成太极八封呢。 老黑,我在想如何把你这个转换成太极八封呢。 加林森 发表于 2022-8-10 12:39
手机上看速度很快的。我也跟到制作了一个太极的。没有做好就不发出来。
不急,测试好了再发布 马黑黑 发表于 2022-8-10 12:49
不急,测试好了再发布
嗯嗯,明白的。 加林森 发表于 2022-8-10 12:49
老黑,我在想如何把你这个转换成太极八封呢。
这个对你来说有些难度。你还是用CSS关键帧动画去完成比较容易上手 马黑黑 发表于 2022-8-10 12:57
这个对你来说有些难度。你还是用CSS关键帧动画去完成比较容易上手
嗯嗯。我去换一下试试。 马黑黑 发表于 2022-8-10 12:32
演示一下效果,没达到完美的
我看这已经很好啦 梦油 发表于 2022-8-10 13:13
我看这已经很好啦
还可以的吧 这图案好美,代码真强大,黑黑真厉害{:4_187:} 红影 发表于 2022-8-10 15:22
这图案好美,代码真强大,黑黑真厉害
不擦除就是圆环,每次刷新都擦除就是球球。这没没啥的
页:
[1]
2