canvas实现粒子的拖尾效果
/**
* @Author SuZhe
* @DateTime 2019-03-15
* @desc 兼容 requestAnimFrame
* @return {[Function]} requestAnimFrame不兼容的浏览器使用定时器代替
*/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
/**
* @Author SuZhe
* @DateTime 2019-03-15
* @desc 椭圆动画效果 star运动
* @param {[Object]} canvasId [画布布id]
*/
function CanvasAnimation(param){
if(param.ele){
this.canvas = param.ele;
this.cxt = this.canvas.getContext('2d');
this.param = param;
if(param.type){
//star
this.starArr = [[],[],[],[]]; //star数量集合
this.step = [80,-40,40,260]; //步长位置集合
this.color = ['230,116,182','80,238,207','235,149,89','68,192,240']; //颜色集合
}else{
// arc
this.a = 168; //长 半 径
this.b = 53; //短 半 径
this.posi = []; //位置集合
this.posiNext = [];
this.radius = 2;
this.time = 0; //步长
}
this.animation();
}
}
CanvasAnimation.prototype = {
animation: function(){
var that = this;
if(this.param.type){
//star
this.starAni();
}else{
//arc
this.draw();
this.drawNext();
}
window.requestAnimFrame(function(){
that.animation();
});
},
draw: function(){
var y = 56,
posi = this.posi;
this.cxt.clearRect(0,0,340,160);
this.trail(y,posi);
this.time+=0.02;
},
drawNext: function(){
var y = 106,
posi = this.posiNext;
this.trail(y,posi,true);
},
trail: function(y,posi,next){
var context = this.cxt,
x = 170,a,b,
param = {};
if(next){
a = -this.a;
b = -this.b;
}else{
a = this.a;
b = this.b;
}
//圆弧坐标
param.arcX = x + a*Math.cos(this.time),
param.arcY = y + b*Math.sin(this.time);
posi.push(param);
if(posi.length > 25){
posi.shift();
}
for(var i = 0, len = posi.length; i < len; i++){
var alphar = 1;
if(i < len-1){
alphar = i/30;
}
if(next){
context.fillStyle="rgba(255, 204, 0, "+alphar+")";
}else{
context.fillStyle="rgba(0, 246, 255, "+alphar+")";
}
context.beginPath();
context.arc(posi[i].arcX,posi[i].arcY,this.radius,0,2*Math.PI);
context.closePath();
context.fill();
}
},
starAni: function(){
var context = this.cxt,
posi = this.starArr,
starNum = [{},{},{},{}];
context.clearRect(0,0,700,462);
for(var k = 0, lens = starNum.length; k < lens; k++){
starNum[k].x = 90 * k * 2 + 40;
starNum[k].y = 462 - this.step[k];
if(starNum[k].y < 0){
this.step[k] = 0;
}
posi[k].push(starNum[k]);
if(posi[k].length > 45){
posi[k].shift();
}
for(var j = 0, len = posi[k].length; j < len; j++){
var alphar = 1,
redius = 2.5;
if(j < len - 1){
alphar = j/50;
redius = j/48 *2 ;
}
if(j == len-1){
context.shadowOffsetY=-2;
context.shadowOffsetX=0;
context.shadowBlur=10;
context.shadowColor="rgb("+this.color[k]+")";
}
context.fillStyle="rgba("+this.color[k]+", "+alphar+")";
context.beginPath();
context.arc(posi[k][j].x,posi[k][j].y,redius,0,2*Math.PI);
context.closePath();
context.fill();
}
this.step[k] += 2;
}
}
}
<canvas class="canvas" width="340" height="160"></canvas>
var arc = new CanvasAnimation({
ele:document.getElementsByClassName('canvas')[0]
});
<canvas class="canvasStar" width="700" height="462"></canvas>
var star = new CanvasAnimation({
ele: document.getElementsByClassName('canvasStar')[0],
type: 'star'
});