前端特效30:使用css与js生成炸裂的火花效果

今天,小编将与大家分享web前端特效荟萃系列第30期,喜欢把玩儿炫酷效果的小伙伴快快看过来^_^ ,希望大家喜欢呦~






第30期,给大家分享一个使用css与js生成的唯美炫酷的图形树效果,相关代码如下:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>cloth</title>
  <style>
    .page-meteor-canvas {
	position: relative;
	width: 100vw;
	height: 100vh;
	overflow: hidden;
	background: -webkit-linear-gradient(top, #000000, #1e004e);
	background: linear-gradient(to bottom, #000000, #1e004e);
}

.page-meteor-canvas:before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	opacity: 0.1;
	background: url("http://static.dar-studio.com/codepen/images/night-sky.jpg")
		center bottom;
	background-size: cover;
}

.page-meteor-canvas canvas {
	position: absolute;
	display: block;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
}

.page-meteor-canvas #canvas {
	mix-blend-mode: multiply;
}

.page-meteor-canvas #buffer {
	-webkit-filter: blur(6px) brightness(10) contrast(1.25);
	filter: blur(6px) brightness(10) contrast(1.25);
	mix-blend-mode: screen;
}


   
  </style>
</head>

  
<body>
  <div class="page page-meteor-canvas">
	<canvas id="buffer"></canvas>
	<canvas id="canvas"></canvas>
</div>
  <script>
    "use strict";

function Meteor(options) {
	options = options || {};
	this.main = options.main || {};
	this.ctx = options.ctx;
	this.vfx = options.vfx;
	this.position = options.position || {
		x: Math.random() * this.main.width + this.main.width * 0.25,
		y: Math.random() * -this.main.height * 0.25
	};
	this.rotation = options.rotation || Math.random() * 2 * Math.PI;
	this.velocity = options.velocity || {
		phi: Math.random() * 0.4 - 0.2 + Math.PI * 0.75,
		length: Math.random() * 5 + 1,
		rotate: Math.random() * 0.1 - 0.05
	};
	this.gravity = options.gravity || { phi: Math.PI * 0.5, length: 0.98 };
	this.edge =
		options.edge ||
		~~(Math.random() * this.velocity.length + this.velocity.length * 2 + 2);
	this.color = options.color || ["#300", "#610", "#fd2", "#f62"];
	this.timescale = options.timescale || 0.5;
	this.ground = options.ground || this.main.height;
	this.accelerate = options.accelerate || {
		phi: {
			change: Math.random() * 0.015 - 0.0075,
			min: Math.PI * 0.6,
			max: Math.PI * 0.9
		},
		friction: 1.005
	};
	this.points = [...new Array(this.edge)].map((e, i) => {
		var phi = i / this.edge * 2 * Math.PI;
		return {
			phi: phi + Math.random() * 0.4 - 0.2,
			length: Math.random() * this.velocity.length * 2 + this.velocity.length * 4
		};
	});

	this.update = function(i) {
		this.rotation += this.velocity.rotate * this.timescale;
		this.position.x +=
			Math.cos(this.velocity.phi) * this.velocity.length * this.timescale;
		this.position.y +=
			Math.sin(this.velocity.phi) * this.velocity.length * this.timescale;
		this.position.x +=
			Math.cos(this.gravity.phi) * this.gravity.length * this.timescale;
		this.position.y +=
			Math.sin(this.gravity.phi) * this.gravity.length * this.timescale;
		this.velocity.phi += this.accelerate.phi.change * this.timescale;
		(this.velocity.phi > this.accelerate.phi.max ||
			this.velocity.phi < this.accelerate.phi.min) &&
			(this.accelerate.phi.change = -this.accelerate.phi.change);
		this.velocity.length *= this.accelerate.friction;
		if (this.position.y > this.ground) {
			var ctx = this.vfx;
			var position = this.position;
			var range = this.edge;
			var main = this.main;
			[...new Array(this.edge)].map(
				() =>
					main.makeRock({
						position: { x: position.x, y: position.y },
						base: range
					}) ||
					LightFlare(
						ctx,
						position.x + Math.random() * 10 * range - 5 * range,
						position.y + Math.random() * 6 * range - 3 * range,
						range * Math.random() * 30 + 30
					)
			);
			this.main.meteors.splice(i, 1);
			this.main.makeMeteor();
		}
	};

	this.render = function() {
		var ctx = this.ctx;
		ctx.strokeStyle = this.color[0];
		ctx.fillStyle = this.color[1];
		ctx.moveTo(this.position.x, this.position.y);
		ctx.beginPath();
		this.points.forEach(p => {
			var x = Math.cos(p.phi + this.rotation) * p.length + this.position.x;
			var y = Math.sin(p.phi + this.rotation) * p.length + this.position.y;
			ctx.lineTo(x, y);
		});
		ctx.closePath();
		ctx.stroke();
		ctx.fill();
		//
		var vfx = this.vfx;
		vfx.globalAlpha = Math.random();
		vfx.fillStyle = this.color[2 + ~~(Math.random() + 0.6)];
		vfx.moveTo(this.position.x, this.position.y);
		vfx.beginPath();
		this.points.forEach(p => {
			var x =
				Math.cos(p.phi + this.rotation * Math.random() * 0.2 - 0.1) * p.length +
				Math.random() +
				this.position.x;
			var y =
				Math.sin(p.phi + this.rotation * Math.random() * 0.2 - 0.1) * p.length +
				Math.random() +
				this.position.y;
			vfx.lineTo(x, y);
		});
		vfx.closePath();
		vfx.fill();
	};
}

function Rock(options) {
	options = options || {};
	this.main = options.main || {};
	this.base = options.base || 2;
	this.ctx = options.ctx;
	this.vfx = options.vfx;
	this.position = options.position || {
		x: Math.random() * this.main.width,
		y: Math.random() * this.main.height
	};
	this.rotation = options.rotation || Math.random() * 2 * Math.PI;
	this.velocity = options.velocity || {
		phi: Math.random() * Math.PI * 0.5 + Math.PI * 1.25,
		length: Math.random() * 1.5 * this.base + 15,
		rotate: Math.random() * 0.2 - 0.1
	};
	this.gravity = options.gravity || { phi: Math.PI * 0.5, length: 5 };
	this.edge =
		options.edge ||
		~~(Math.random() * this.velocity.length + this.velocity.length * 2 + 5);
	this.color = options.color || ["#300", "#510", "#fd2", "#f62"];
	this.timescale = options.timescale || 1.5;
	this.lifespan = options.lifespan || ~~(Math.random() * 30 + 10);
	this.friction = 0.94;
	this.points = [...new Array(this.edge)].map((e, i) => {
		var phi = i / this.edge * 2 * Math.PI;
		return {
			phi: phi + Math.random() * 0.4 - 0.2,
			length:
				Math.random() * this.velocity.length * 0.1 + this.velocity.length * 0.2
		};
	});

	this.update = function(i) {
		if (this.lifespan-- <= 0) {
			this.main.meteors.splice(i, 1);
			return;
		}
		this.rotation += this.velocity.rotate * this.timescale;
		this.position.x +=
			Math.cos(this.velocity.phi) * this.velocity.length * this.timescale;
		this.position.y +=
			Math.sin(this.velocity.phi) * this.velocity.length * this.timescale;
		this.position.x +=
			Math.cos(this.gravity.phi) * this.gravity.length * this.timescale;
		this.position.y +=
			Math.sin(this.gravity.phi) * this.gravity.length * this.timescale;
		this.velocity.length *= this.friction;
	};

	this.render = function() {
		var ctx = this.ctx;
		ctx.globalAlpha = Math.random();
		ctx.strokeStyle = this.color[0];
		ctx.fillStyle = this.color[1];
		ctx.moveTo(this.position.x, this.position.y);
		ctx.beginPath();
		this.points.forEach(p => {
			var x = Math.cos(p.phi + this.rotation) * p.length + this.position.x;
			var y = Math.sin(p.phi + this.rotation) * p.length + this.position.y;
			ctx.lineTo(x, y);
		});
		ctx.closePath();
		ctx.stroke();
		ctx.fill();
		ctx.globalAlpha = 1;
		//
		var vfx = this.vfx;
		vfx.globalAlpha = Math.random();
		vfx.fillStyle = this.color[2 + ~~(Math.random() + 0.6)];
		vfx.moveTo(this.position.x, this.position.y);
		vfx.beginPath();
		this.points.forEach(p => {
			var x =
				Math.cos(p.phi + this.rotation * Math.random() * 0.2 - 0.1) * p.length +
				Math.random() +
				this.position.x;
			var y =
				Math.sin(p.phi + this.rotation * Math.random() * 0.2 - 0.1) * p.length +
				Math.random() +
				this.position.y;
			vfx.lineTo(x, y);
		});
		vfx.closePath();
		vfx.fill();
	};
}

function LightFlare(ctx, x, y, range) {
	range = range || 100;
	const strength = Math.random() * range + range;
	const light = ctx.createRadialGradient(x, y, 0, x, y, strength);
	light.addColorStop(0, "rgba(250, 200, 50, 0.4)");
	light.addColorStop(0.1, "rgba(250, 200, 50, 0.3)");
	light.addColorStop(0.4, "rgba(250, 200, 50, 0.2)");
	light.addColorStop(0.65, "rgba(250, 200, 50, 0.1)");
	light.addColorStop(0.8, "rgba(250, 200, 50, 0.05)");
	light.addColorStop(1, "rgba(250, 200, 50, 0)");
	ctx.globalAlpha = 1;
	ctx.beginPath();
	ctx.fillStyle = light;
	ctx.arc(x, y, strength, 0, Math.PI * 2);
	ctx.fill();
	ctx.closePath();
}

function Ground(options) {
	options = options || {};
	this.main = options.main || {};
	this.ctx = options.ctx;
	this.edge = options.edge || ~~(Math.random() * 10 + 40);
	this.color = options.color || ["#222", "#1e004e"];
	this.height = options.height || this.main.height * 0.16;
	this.points = [...new Array(this.edge)].map((e, i) => {
		var rand = 1 / this.edge * this.main.width;
		return {
			x: i / this.edge * this.main.width + Math.random() * rand - rand * 0.5,
			y: this.main.height - this.height + Math.random() * this.height * 0.1
		};
	});

	this.update = function() {
		return;
	};

	this.render = function() {
		var ctx = this.ctx;
		ctx.strokeStyle = this.color[0];
		ctx.fillStyle = this.color[1];
		ctx.beginPath();
		ctx.moveTo(-this.height, this.main.height);
		this.points.forEach(p => ctx.lineTo(p.x, p.y));
		ctx.lineTo(this.main.width + this.height, this.main.height);
		ctx.closePath();
		ctx.stroke();
		ctx.fill();
	};
}

let main = {
	canvas: document.getElementById("canvas"),
	buffer: document.getElementById("buffer"),
	ctx: null,
	vfx: null,
	ground: null,
	meteors: [],
	count: 8,
	width: window.innerWidth,
	height: window.innerHeight,
	init: function() {
		this.registerEvents();
		this.ctx = this.canvas.getContext("2d");
		this.vfx = this.buffer.getContext("2d");
		this.vfx.globalCompositeOperation = "screen";
		//
		this.resize();
		//
		this.ground = new Ground({
			ctx: this.ctx,
			main: this
		});
		[...new Array(this.count)].map(() => this.makeMeteor());
	},

	makeMeteor() {
		this.meteors.push(
			new Meteor({
				ctx: this.ctx,
				vfx: this.vfx,
				ground: this.height - this.ground.height * 0.8,
				main: this
			})
		);
	},

	makeRock(options) {
		options = options || {};
		this.meteors.push(
			new Rock({
				ctx: this.ctx,
				vfx: this.vfx,
				position: options.position,
				base: options.base,
				main: this
			})
		);
	},

	update: function() {
		this.meteors.forEach((m, i) => m.update(i));
		this.ground.update();
	},

	render: function() {
		this.ctx.clearRect(0, 0, this.width, this.height);
		this.meteors.forEach(m => m.render());
		this.ground.render();
		//
		this.vfx.fillStyle = "#000000";
		this.vfx.globalAlpha = Math.random() * 0.12;
		this.vfx.fillRect(0, 0, this.width, this.height);
	},

	resize: function() {
		this.width = window.innerWidth * 1.5;
		this.height = window.innerHeight * 1.5;
		this.canvas.width = this.width;
		this.canvas.height = this.height;
		this.buffer.width = this.width;
		this.buffer.height = this.height;
	},

	registerEvents: function() {
		window.addEventListener(
			"resize",
			() => {
				this.resize();
			},
			false
		);
	}
};

main.init();
(function loop() {
	main.update();
	main.render();
	window.requestAnimationFrame(loop);
})();
  </script>
</body>
</html>


在线演示:Here~ 



今天的分享就是这些啦,这里是igeekbar,希望可以给各位geek小伙伴们带来帮助呦~~~如果你制作出了或收藏了哪些炫酷的前端特效,赶快留言分享给我们呦~~~


Geek豪哥   iGeekBar社区大管家

iGeekBar创始人之一,热爱科技与设计,正在探索研究数据科学的女猿,最爱勾搭极客帅哥美女的逗比疯姑娘~~
     扫一扫立刻加入iGeekBar会员QQ群(545980198)
    和更多iG客会员交流分享吧~