直播平台源码搭建教程之模仿实现一个直播的点赞动画
我看到这个动画效果首先想到的,声明一个包含多个小图标对象的数组,通过在不同的位置绘制这些小图标实现这个点赞动画。那么首先我们实现一个小图标的动画。
要做动画我们首先把整个动画流程分解一下,这个动画包含如下几个:
我们这里首先将问题先简单化处理,制作单个图标的动画。这里为了之后对图标动画的操作,我写了一个Ani类表示图标动画,它包含了图标的位置属性、大小、image
对象和动画轨迹相关的属性,还有一个用来绘制的draw
方法。定义如下:
//图标动画类
class Ani{
constructor(img,x,y,w,h){
this.x=x;
this.y=y;
this.width=w;
this.height=h;
this.image=img;
//随机生成正弦曲线的波动幅度
this.step=getRandom(10,60);
//随机生成y轴的移动速度
this.spite=getRandom(2,6);
//正弦函数的摆动频率
this.frequency=getRandom(50,100);
//小图标透明度
this.op=0;
//随机曲线类型
Math.random()>=0.5?this.type=1:this.type=2;
//y轴偏移量,作为正弦函数的参数
this.dy=0;
}
//这里不用全局的context是为了方便复用
draw(context){
//y轴平移动画
this.y-=this.spite;
//x轴摆动动画
this.dy+=this.spite;
let dx=0;
//不同的波动方向
this.type==1?dx=Math.sin(this.dy/this.frequency):dx=Math.sin(-this.dy/this.frequency);
let x=this.x+dx*this.step;
//放大动画
if(this.width<50){
this.width+=0.5;
this.height+=0.5;
}
context.drawImage(this.image,x,this.y,this.width,this.height);
//消失时的透明度动画
if(this.y<50){
this.op+=0.05
context.fillStyle = `rgba(255,255,255,${this.op})`;
context.fillRect(x,this.y,this.width,this.height);
}
}
}
稍微解释一下上面的代码,构造函数中的frequency
属性是用来控制正弦函数的摆动频率的,大家可以修改它的值来查看效果,getRandom()
方法是用来获得某个区间之间的随机数的一个简单函数,下面的完整源码中给出了代码实现。
这里设置图标的透明度是通过在指定位置添加透明背景色实现的,在网上查了好多也没又找到直接修改image对象透明度的方法,因此使用了这个方法。
Ani
类draw()
方法通过改变Ani对象的y
、x
、width
、height
、op
等属性分别实现各个动画过程。这里着重说一下x
轴的摆动动画的实现,x
轴的运动动画是借助正弦函数实现的,js
有现成Math.sin()
函数供我们使用,正弦函数的0->1->0->-1
的曲线完美符合我们需要的运动曲线。这里我们把y
轴偏移量dy
作为正弦函数的参数,生成0~-1
之间的值dx
,再使用dx*step
获得x
轴的偏移量。
Ani
类完成之后我们还需要一个启动动画的函数:
const canvas = document.getElementById('thumsCanvas');
let context = canvas.getContext('2d');
let image=new Image("./img/star.png");
let ani=new Ani(image,250/2-50/2,500-50,20,20);
//渲染函数
function render(){
//context.clearRect(0,0,250,500); // clear canvas
//添加透明背景色填充,实现拖尾效果
context.fillStyle = 'rgba(255,255,255,0.5)';
context.fillRect(0,0,250,500);
ani.draw(context);
window.requestAnimationFrame(render)
}
render();
复制代码
实现了单个图标的动画,那么多个图标的动画就很容易实现了。我们只需要创建一个数组持有多个图标对象,在每次render函数执行时遍历绘制它们。
因为我们需要多个图像的图标对象,因此我们需要实现一个loadImge函数把要加载的图像先缓存到一个imageList数组中,此方法参考上面的文章H5 直播的疯狂点赞动画是如何实现的?(附完整源码)。 代码如下:
//加载图像
function loadImage(){
const images=[
'../img/red.png',
'../img/dog.png',
'../img/cat.png',
'../img/star.png',
'../img/zan.png',
];
const promiseList=[];
images.forEach(element => {
let p=new Promise((resolve)=>{
const img=new Image();
img.onload=resolve.bind(null,img)
img.src=element;
})
promiseList.push(p)
});
return new Promise(resolve=>{
Promise.all(promiseList).then(imgs=>{
this.imageList=imgs;
resolve();
})
})
}
复制代码
然后我们需要把一个方法添加图标对象:
//添加图标对象到数组
function tapAdd(){
let image=this.imageList[this.getRandom(0,5)];
let ani=new Ani(image,250/2-50/2,500-50,20,20)
aniList.push(ani)
}
复制代码
最后我们同样需要一个渲染函数:
//渲染函数
function render(){
//context.clearRect(0,0,250,500); // clear canvas
context.fillStyle = 'rgba(255,255,255,0.5)';
context.fillRect(0,0,250,500);
aniList.forEach((ani,index)=>{
if(ani.y<-50){
ani=null;
}else{
ani.draw(context);
}
})
window.requestAnimationFrame(render)
}
loadImage().then(()=>{
console.log('图像加载完成')
render();
setInterval(tapAdd,100);
});
复制代码
这里两句context.fillStyle = 'rgba(255,255,255,0.5)';context.fillRect(0,0,250,500);
是通过添加半透明填充色实现拖尾效果,如果不需要可以直接换成context.clearRect(0,0,250,500);
。
cavans点赞动画效果
复制代码