新增第105个小实例:喜庆绚烂的新年烟花特效
This commit is contained in:
parent
db82484f73
commit
7719c9cd0b
|
@ -108,4 +108,5 @@
|
|||
101. HTML5+CSS3小实例:浮雕效果的彩色loading动画
|
||||
102. HTML5+CSS3+JS小实例:切片式轮播图
|
||||
103. HTML5+CSS3小实例:纯CSS实现百叶窗图片切换效果
|
||||
104. HTML5+CSS3小实例:单选按钮的创意动画
|
||||
104. HTML5+CSS3小实例:单选按钮的创意动画
|
||||
105. HTML5+CSS3+JS小实例:喜庆绚烂的新年烟花特效
|
|
@ -0,0 +1,48 @@
|
|||
/* 引入网络字体(Montserrat) */
|
||||
@import url("http://fonts.googleapis.com/css?family=Montserrat:200,300,400,500,600,700,800,900&display=swap");
|
||||
|
||||
*{
|
||||
/* 初始化 */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body{
|
||||
/* 100%窗口高度 */
|
||||
height: 100vh;
|
||||
background: url("../images/yj.jpg") no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
/* 溢出隐藏 */
|
||||
overflow: hidden;
|
||||
/* 禁止文本被选取 */
|
||||
user-select: none;
|
||||
}
|
||||
canvas{
|
||||
/* 设置混合模式:变亮 */
|
||||
mix-blend-mode: lighten;
|
||||
}
|
||||
.container{
|
||||
/* 绝对定位 居中 */
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
/* 设置混合模式:颜色减淡 */
|
||||
mix-blend-mode: color-dodge;
|
||||
}
|
||||
.year{
|
||||
font-size: 30vw;
|
||||
color: #aaa;
|
||||
/* 字体设置为上面引入的字体 */
|
||||
font-family: Montserrat;
|
||||
font-weight: 700;
|
||||
/* 字间距 */
|
||||
letter-spacing: 15px;
|
||||
}
|
||||
.greetings{
|
||||
color: #eee;
|
||||
font-size: 3.5vw;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
letter-spacing: 10px;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
|
||||
<title>新年到了,怎能少了烟花表演!祝大家新年快乐!!</title>
|
||||
<link rel="stylesheet" href="../css/105.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="year">2022</div>
|
||||
<div class="greetings">新年快乐!</div>
|
||||
</div>
|
||||
<!-- 接下来重头戏,烟花来了 -->
|
||||
<!-- 这两个js文件我提前准备好了,太多了,就不带着大家手敲了,大家可以找我拿 -->
|
||||
<script src="../js/105_vector.js"></script>
|
||||
<script src="../js/105_fireworks.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
|
@ -0,0 +1,188 @@
|
|||
const canvas = document.createElement('canvas'),
|
||||
context = canvas.getContext('2d'),
|
||||
width = canvas.width = window.innerWidth,
|
||||
height = canvas.height = window.innerHeight,
|
||||
HalfPI = Math.PI / 2,
|
||||
gravity = vector.create(0, 0.35)
|
||||
|
||||
let objects = [];
|
||||
let startFireworks = true;
|
||||
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
function random255() {
|
||||
return Math.floor(Math.random() * 100 + 155);
|
||||
}
|
||||
|
||||
function randomColor() {
|
||||
let r = random255(),
|
||||
g = random255(),
|
||||
b = random255();
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
}
|
||||
|
||||
class PhysicsBody {
|
||||
constructor() {
|
||||
objects.push(this);
|
||||
}
|
||||
PhysicsUpdate() {
|
||||
this.lastPosition = this.position.duplicate();
|
||||
this.position.addTo(this.velocity);
|
||||
this.velocity.addTo(gravity);
|
||||
}
|
||||
deleteObject() {
|
||||
objects[objects.indexOf(this)] = undefined;
|
||||
}}
|
||||
|
||||
|
||||
class firework extends PhysicsBody {
|
||||
constructor() {
|
||||
super();
|
||||
this.position = vector.create(Math.random() * width, height);
|
||||
|
||||
let Velocity = vector.create(0, 0);
|
||||
Velocity.setLength(Math.random() * 10 + 15);
|
||||
Velocity.setAngle(Math.PI * 1.35 + Math.random() * Math.PI * 0.30);
|
||||
this.velocity = Velocity;
|
||||
|
||||
this.trail = Math.floor(Math.random() * 4) != 1;
|
||||
this.trailColor = this.trail ? randomColor() : undefined;
|
||||
this.trailWidth = 2;
|
||||
|
||||
this.TimeCreated = new Date().getTime();
|
||||
this.TimeExpired = this.TimeCreated + (Math.random() * 5 + 7) * 100;
|
||||
|
||||
this.BlastParticleCount = Math.floor(Math.random() * 50) + 25;
|
||||
this.funky = Math.floor(Math.random() * 5) == 1;
|
||||
|
||||
this.exposionColor = randomColor();
|
||||
}
|
||||
|
||||
draw() {
|
||||
context.strokeStyle = this.trailColor;
|
||||
context.lineWidth = this.trailWidth;
|
||||
|
||||
let p = this.position,
|
||||
lp = this.lastPosition;
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(lp.getX(), lp.getY());
|
||||
context.lineTo(p.getX(), p.getY());
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
funkyfire() {
|
||||
var funky = this.funky;
|
||||
for (var i = 0; i < Math.floor(Math.random() * 10); i++) {
|
||||
new BlastParticle({ firework: this, funky });
|
||||
}
|
||||
}
|
||||
|
||||
explode() {
|
||||
var funky = this.funky;
|
||||
for (var i = 0; i < this.BlastParticleCount; i++) {
|
||||
new BlastParticle({ firework: this, funky });
|
||||
}
|
||||
this.deleteObject();
|
||||
}
|
||||
|
||||
checkExpire() {
|
||||
let now = new Date().getTime();
|
||||
if (now >= this.TimeExpired) this.explode();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.trail) this.draw();
|
||||
if (this.funky) this.funkyfire();
|
||||
this.checkExpire();
|
||||
}}
|
||||
|
||||
|
||||
class BlastParticle extends PhysicsBody {
|
||||
constructor({ firework, funky }) {
|
||||
super();
|
||||
this.position = firework.position.duplicate();
|
||||
|
||||
let Velocity = vector.create(0, 0);
|
||||
if (!this.funky) {
|
||||
Velocity.setLength(Math.random() * 6 + 2);
|
||||
Velocity.setAngle(Math.random() * Math.PI * 2);
|
||||
} else {
|
||||
Velocity.setLength(Math.random() * 3 + 1);
|
||||
Velocity.setAngle(firework.getAngle + Math.PI / 2 - Math.PI * 0.25 + Math.PI * .5);
|
||||
}
|
||||
|
||||
this.velocity = Velocity;
|
||||
|
||||
this.color = firework.exposionColor;
|
||||
|
||||
this.particleSize = Math.random() * 4;
|
||||
|
||||
this.TimeCreated = new Date().getTime();
|
||||
this.TimeExpired = this.TimeCreated + (Math.random() * 4 + 3.5) * 100;
|
||||
}
|
||||
|
||||
draw() {
|
||||
context.strokeStyle = this.color;
|
||||
context.lineWidth = this.particleSize;
|
||||
let p = this.position,
|
||||
lp = this.lastPosition;
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(lp.getX(), lp.getY());
|
||||
context.lineTo(p.getX(), p.getY());
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
checkExpire() {
|
||||
let now = new Date().getTime();
|
||||
if (now >= this.TimeExpired) this.deleteObject();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.draw();
|
||||
this.checkExpire();
|
||||
}}
|
||||
|
||||
|
||||
document.body.addEventListener('mousedown', function (e) {
|
||||
let color = randomColor();
|
||||
for (var i = 0; i < Math.floor(Math.random() * 20) + 25; i++) {
|
||||
new BlastParticle({
|
||||
firework: {
|
||||
position: vector.create(e.pageX, e.pageY),
|
||||
velocity: vector.create(0, 0),
|
||||
exposionColor: color },
|
||||
|
||||
funky: false });
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(function () {
|
||||
if (!startFireworks) return;
|
||||
for (var i = 0; i < Math.floor(Math.random() * 4); i++) {
|
||||
new firework();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
function cleanupObjects() {
|
||||
objects = objects.filter(o => o != undefined);
|
||||
}
|
||||
|
||||
function loop() {
|
||||
context.fillStyle = 'rgba(0,0,0,0.085)';
|
||||
context.fillRect(0, 0, width, height);
|
||||
|
||||
let unusedObjectCount = 0;
|
||||
objects.map(o => {
|
||||
if (!o) {unusedObjectCount++;return;}
|
||||
o.PhysicsUpdate();
|
||||
o.render();
|
||||
});
|
||||
if (unusedObjectCount > 100) cleanupObjects();
|
||||
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
|
||||
loop();
|
|
@ -0,0 +1,151 @@
|
|||
var vector = {
|
||||
_x: 1,
|
||||
_y: 0,
|
||||
|
||||
create: function(x, y) {
|
||||
var obj = Object.create(this);
|
||||
obj.setX(x);
|
||||
obj.setY(y);
|
||||
return obj;
|
||||
},
|
||||
|
||||
duplicate: function() {
|
||||
return vector.create(this._x, this._y);
|
||||
},
|
||||
|
||||
random: function(maxX, maxY, minX, minY){
|
||||
var x = Math.random() * (maxX-minX) + minX;
|
||||
var y = Math.random() * (maxY-minY) + minY;
|
||||
return vector.create(x,y);
|
||||
},
|
||||
|
||||
setX: function(value) {
|
||||
this._x = value;
|
||||
},
|
||||
|
||||
getX: function() {
|
||||
return this._x;
|
||||
},
|
||||
|
||||
setY: function(value) {
|
||||
this._y = value;
|
||||
},
|
||||
|
||||
getY: function() {
|
||||
return this._y;
|
||||
},
|
||||
|
||||
bounds: function(size, mX, mY){
|
||||
var mapsize = size;
|
||||
if(this._x > mX + mapsize){ this._x = -size; }
|
||||
if(this._x < -mapsize){ this._x = mX + size; }
|
||||
|
||||
if(this._y > mY + mapsize){ this._y = -size; }
|
||||
if(this._y < -mapsize){ this._y = mY + size; }
|
||||
},
|
||||
|
||||
outOfBounds: function(sx, sy, ex, ey){
|
||||
if(this._x < sx){ return true; }
|
||||
if(this._x > ex){ return true; }
|
||||
|
||||
if(this._y < sy){ return true; }
|
||||
if(this._y > ey){ return true; }
|
||||
},
|
||||
|
||||
setAngle: function(angle) {
|
||||
var length = this.getLength();
|
||||
this._x = Math.cos(angle) * length;
|
||||
this._y = Math.sin(angle) * length;
|
||||
},
|
||||
|
||||
getAngle: function() {
|
||||
return Math.atan2(this._y, this._x);
|
||||
},
|
||||
|
||||
angleTo: function(p2) {
|
||||
return Math.atan2(p2.getY() - this._y, p2.getX() - this._x);
|
||||
},
|
||||
|
||||
distanceTo: function(p2) {
|
||||
var dx = p2.getX() - this._x,
|
||||
dy = p2.getY() - this._y;
|
||||
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
},
|
||||
|
||||
setLength: function(length) {
|
||||
var angle = this.getAngle();
|
||||
this._x = Math.cos(angle) * length;
|
||||
this._y = Math.sin(angle) * length;
|
||||
},
|
||||
|
||||
gravitateTo: function(p2, mass, mymass) {
|
||||
var grav = Vector.create(0, 0),
|
||||
dist = mypos.distanceTo(p2);
|
||||
|
||||
//grav.setLength(mass / (dist * dist));
|
||||
grav.setLength((G*mass*mymass) / (dist * dist));
|
||||
grav.setAngle(this.angleTo(p2));
|
||||
this.addTo(grav);
|
||||
},
|
||||
|
||||
getLength: function() {
|
||||
return Math.sqrt(this._x * this._x + this._y * this._y);
|
||||
},
|
||||
|
||||
maxSpeed: function(s){
|
||||
if(this.getLength() > s){
|
||||
this.setLength(s);
|
||||
}
|
||||
},
|
||||
|
||||
add: function(v2) {
|
||||
return vector.create(this._x + v2.getX(), this._y + v2.getY());
|
||||
},
|
||||
|
||||
subtract: function(v2) {
|
||||
return vector.create(this._x - v2.getX(), this._y - v2.getY());
|
||||
},
|
||||
|
||||
multiply: function(val) {
|
||||
return vector.create(this._x * val, this._y * val);
|
||||
},
|
||||
|
||||
divide: function(val) {
|
||||
return vector.create(this._x / val, this._y / val);
|
||||
},
|
||||
|
||||
addTo: function(v2) {
|
||||
this._x += v2.getX();
|
||||
this._y += v2.getY();
|
||||
},
|
||||
|
||||
subtractFrom: function(v2) {
|
||||
this._x -= v2.getX();
|
||||
this._y -= v2.getY();
|
||||
},
|
||||
|
||||
multiplyBy: function(val) {
|
||||
this._x *= val;
|
||||
this._y *= val;
|
||||
},
|
||||
|
||||
divideBy: function(val) {
|
||||
this._x /= val;
|
||||
this._y /= val;
|
||||
},
|
||||
|
||||
normalize: function(scale){
|
||||
var norm = Math.sqrt(this._x * this._x + this._y * this._y);
|
||||
if (norm != 0) {
|
||||
return vector.create(
|
||||
scale * this._x / norm,
|
||||
scale * this._y / norm
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
dot: function(v2){
|
||||
return this._x * v2._x + this._y * v2._y;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue