特效描述:html5 canvas下雨 雨滴动画特效。html5 canvas绘制下雨雨滴打在地面动画特效。
代码结构
1. 引入JS
2. HTML代码
var two = new Two({
type: Two.Types.canvas,
fullscreen: true,
autostart: true
}).appendTo(document.body);
two.renderer.domElement.style.background = '#aaa';
var ground = two.makeGroup();
var angle = 0;
var rain = new Array(150);
rain.next = function() {
var drop = rain[rain.index];
rain.index = (rain.index + 1) % rain.length;
return drop;
};
rain.index = 0;
var ripples = new Array(250);
ripples.next = function() {
var ripple = ripples[ripples.index];
ripples.index = (ripples.index + 1) % ripples.length;
return ripple;
};
ripples.index = 0;
for (var i = 0; i < ripples.length; i++) {
var ripple = makeRipple();
ripples[i] = ripple;
if (ripple.child) {
ground.add(ripple.child);
}
if (i < rain.length) {
var drop = makeDrop();
rain[i] = drop;
}
}
var pouring = false;
ground.add(ripples);
two.add(rain);
window.addEventListener('mousedown', function(e) {
pouring = true;
}, false);
window.addEventListener('mousemove', function(e) {
ground.scale.y = 0.33 * e.clientY / two.height + 0.33;
angle = Math.PI * (e.clientX / two.width) / 2 - Math.PI / 4;
}, false);
window.addEventListener('mouseup', function(e) {
pouring = false;
}, false);
window.addEventListener('touchstart', function(e) {
e.preventDefault();
e.stopPropagation();
pouring = true;
return false;
}, false);
window.addEventListener('touchend', function(e) {
e.preventDefault();
e.stopPropagation();
pouring = false;
return false;
}, false);
window.addEventListener('click', function(e) {
var ripple = ripples.next();
ripple.start(e.clientX, e.clientY);
}, false);
ground.scale = new Two.Vector(1, 0.4);
two.bind('update', function(frameCount) {
TWEEN.update();
if (pouring && !(frameCount % 1)) {
rain.next().start();
ripples.next().start();
} else if (!(frameCount % 5)) {
rain.next().start();
}
});
function makeDrop(i) {
var seed = Math.random();
var drop = two.makeLine(0, 0, 0, 0);
drop.visible = false;
drop.cap = 'round';
drop.noFill().stroke = 'white';
drop.tweens = {
i: new TWEEN.Tween(drop.vertices[0])
.easing(TWEEN.Easing.Sinusoidal.In)
.onComplete(function() {
ripples.next().start(drop.vertices[0].x, drop.vertices[0].y);
}),
o: new TWEEN.Tween(drop.vertices[1])
.delay(seed * 100)
.easing(TWEEN.Easing.Sinusoidal.In)
.onComplete(function() {
drop.visible = false;
})
};
drop.start = function() {
var dx = Math.random() * two.width;
var dy = Math.random() * two.height;
var ox = 1000 * Math.cos(angle - Math.PI / 2) + dx;
var oy = 1000 * Math.sin(angle - Math.PI / 2) + dy;
var dest = {
x: dx,
y: dy
};
drop.visible = true;
drop.linewidth = Math.random() * 3;
drop.vertices[0].set(ox, oy);
drop.vertices[1].set(ox, oy);
drop.tweens.i.to(dest, seed * 250 + 50).start();
drop.tweens.o.to(dest, seed * 250 + 50).start();
};
return drop
}
function makeRipple(i) {
var seed = Math.random();
var ripple = two.makeCircle(0, 0, 0);
ripple.visible = false;
ripple.noFill().stroke = 'white';
ripple.tween = new TWEEN.Tween(ripple)
.to({ radius: seed * 50 + 100, linewidth: 0 }, seed * 250 + 350)
.easing(TWEEN.Easing.Sinusoidal.Out)
.onComplete(function() {
ripple.visible = false;
});
if (Math.random() > 0.5) {
ripple.child = two.makeCircle(0, 0, 0);
ripple.child.noFill().stroke = ripple.stroke;
ripple.child.tween = new TWEEN.Tween(ripple.child)
.to({ radius: seed * 50 + 100, linewidth: 0 }, seed * 250 + 350)
.delay(Math.random() * 100)
.onComplete(function() {
ripple.child.visible = false;
});
}
ripple.start = function(x, y) {
if (x && y) {
ripple.translation.set(x, y / ground.scale.y);
} else {
ripple.translation.set(
Math.random() * two.width / ground.scale.x,
Math.random() * two.height / ground.scale.y
);
}
ripple.radius = 0;
ripple.linewidth = Math.random() * 3 + 1;
ripple.visible = true;
ripple.tween.start();
if (ripple.child) {
ripple.child.translation.copy(ripple.translation);
ripple.child.radius = 0;
ripple.child.linewidth = ripple.linewidth;
ripple.child.visible = true;
ripple.child.tween.start();
}
};
return ripple;
}