基于canvas点击圆形爱心按钮,喷出爱心气泡动画特效。这是一款点赞喜欢爱心特效。
css代码
html代码
快来点赞吧
javascript代码
<script>
class HeartsFlow {
constructor(data) {
this.el = document.querySelector(data.canvasEl);
this.w = 200;
this.h = 400;
this.ctx = this.el.getContext('2d');
this.colors = [
'255, 137, 164', //'#FF89A4',
'239, 121, 138', //'#EF798A',
'255, 77, 128', //'#FF4D80',
'249, 42, 130' //'#F92A82'
];
this.heartsAmount = data.amount;
this.heartsList = [];
this.isAnimate = false;
this.raf = null;
this.animate = this.animate.bind(this);
this.paintHeart = this.paintHeart.bind(this);
this.stopAnimation = this.stopAnimation.bind(this);
this.init();
}
getRandomColor() {
return this.colors[Math.floor(Math.random() * this.colors.length)];
}
getRandom(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
setHeartsList() {
let arr = [];
for (let i = 0; i < this.heartsAmount; i++) {
let currentSize = this.getRandom(10, 15);
let dt = {
x: this.w / 2,
y: this.h,
bx: this.w / 2,
by: this.h,
pos: this.h,
_osp: this.getRandom(200, 400) / 100,
osp: this.getRandom(11, 12) / 10,
vsp: this.getRandom(currentSize, currentSize + i * 2) / 1000,
size: currentSize,
color: this.getRandomColor(),
alfa: 1 };
arr.push(dt);
}
this.heartsList = [...this.heartsList, ...arr];
}
getCoordinates({ x, y, size, color, bx, by, _osp, osp, vsp, pos, alfa }) {
return {
xst: x,
yst: y + size / 2,
x0: x - size / 1.4,
y0: y + size / 4,
x1: x - size / 1.3,
y1: y - size / 1.3,
_x0: x + size / 1.4,
_y0: y + size / 4,
_x1: x + size / 1.3,
_y1: y - size / 1.3,
xfn: x,
yfn: y - size / 3,
bx: bx,
by: by,
_osp: _osp,
osp: osp,
vsp: vsp,
pos: pos,
alfa: alfa,
size: size,
color: color };
}
paintHeart({ xst, yst, x0, y0, _x0, _y0, x1, y1, _x1, _y1, xfn, yfn, color, alfa }) {
this.ctx.globalCompositeOperation = "lighter";
this.ctx.beginPath();
this.ctx.moveTo(xst, yst);
this.ctx.bezierCurveTo(x0, y0, x1, y1, xfn, yfn);
this.ctx.moveTo(xst, yst);
this.ctx.bezierCurveTo(_x0, _y0, _x1, _y1, xfn, yfn);
this.ctx.fillStyle = `rgba(${color}, ${alfa})`;
this.ctx.strokeStyle = `rgba(${color}, ${alfa})`;
this.ctx.fill();
this.ctx.stroke();
this.ctx.closePath();
}
mutateData() {
this.heartsList = this.heartsList.map(item => {
let pos = item.pos - 0.05;
let x = item.x + Math.sin(pos * item._osp) * ((pos - item.by) / item.osp);
let y = pos + (pos - item.by) / item.vsp * 1.6;
let alfa = this.normalize0between1(0, this.h, y).toFixed(1);
return {
...item, x: x, y: y, pos: pos, alfa: alfa };
});
this.heartsList = this.heartsList.filter(item => item.y > 0);
}
normalize0between1(min, max, value) {
return (value - min) / (max - min);
}
setCanvas() {
this.el.width = this.w;
this.el.height = this.h;
}
startAnimation() {
if (!this.isAnimate) {
this.isAnimate = true;
console.log('start animation');
this.setHeartsList();
this.animate();
} else {
this.setHeartsList();
}
}
stopAnimation() {
this.isAnimate = false;
console.log('stop animation');
cancelAnimationFrame(this.raf);
}
animate() {
this.ctx.clearRect(0, 0, this.w, this.h);
if (this.isAnimate) {
for (let i = 0, len = this.heartsList.length; i < len; i++) {
let hrt = this.getCoordinates(this.heartsList[i]);
this.paintHeart(hrt);
}
this.mutateData();
}
this.raf = requestAnimationFrame(this.animate);
if (this.heartsList.length === 0 && this.isAnimate) {
this.stopAnimation();
}
}
init() {
this.setCanvas();
this.setHeartsList();
this.animate();
}}
let ht = new HeartsFlow({
canvasEl: '.hearts-canvas',
amount: 20 });
let btn = document.querySelector('.btn');
btn.addEventListener('click', function () {
ht.startAnimation();
});
</script>