在本篇博客文章中,我们将介绍如何使用 HTML 和 JavaScript 创建一个令人惊叹的互动星空动画。这个动画将在网页背景中呈现闪烁的星星,同时允许你以鼠标交互的方式产生漂浮的粒子。
https://pengsirs.gitee.io/51xk/19/
在这个项目中,我们将使用以下技术要点:
这个互动星空动画由两个主要元素组成:星星和粒子。星星是背景中的小点,它们以随机颜色闪烁。粒子是随着鼠标移动而产生的小圆点。
星星由 Star 类表示,每个星星都有唯一的标识、位置、颜色和半径。
星星以随机的颜色在背景上闪烁,使用 rgba 颜色来实现半透明效果。
星星在动画中移动,呈现出星星闪烁的效果。
粒子由 Dot 类表示,每个粒子都有唯一的标识、位置、颜色和半径。
粒子在鼠标移动时产生,其颜色和半透明度逐渐减小,最终消失。
粒子之间可以形成连线,以呈现出互动的效果。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>互动星空</title>
<style>
html,body {
margin:0;
overflow:hidden;
width:100%;
height:100%;
cursor:none;
background:black;
background:linear-gradient(to bottom,#000000 0%,#5788fe 100%);
}
.filter {
width:100%;
height:100%;
position:absolute;
top:0;
left:0;
background:#fe5757;
animation:colorChange 30s ease-in-out infinite;
animation-fill-mode:both;
mix-blend-mode:overlay;
}
@keyframes colorChange {
0%,100% {
opacity:0;
}
50% {
opacity:.9;
}
}.landscape {
position:absolute;
bottom:0px;
left:0;
width:100%;
height:100%;
/*background-image:url(https://openclipart.org/image/2400px/svg_to_png/250847/Trees-Landscape-Silhouette.png);
*/
background-image:url('http://www.jq22.com/css/img/xkbg.png');
background-size:1000px 250px;
background-repeat:repeat-x;
background-position:center bottom;
}
</style>
</head>
<body>
<div class="landscape"></div>
<div class="filter"></div>
<canvas id="canvas"></canvas>
<script>
function Star(id, x, y){
this.id = id;
this.x = x;
this.y = y;
this.r = Math.floor(Math.random()*2)+1;
var alpha = (Math.floor(Math.random()*10)+1)/10/2;
this.color = "rgba(255,255,255,"+alpha+")";
}
Star.prototype.draw = function() {
ctx.fillStyle = this.color;
ctx.shadowBlur = this.r * 2;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
Star.prototype.move = function() {
this.y -= .15;
if (this.y <= -10) this.y = HEIGHT + 10;
this.draw();
}
Star.prototype.die = function() {
stars[this.id] = null;
delete stars[this.id];
}
function Dot(id, x, y, r) {
this.id = id;
this.x = x;
this.y = y;
this.r = Math.floor(Math.random()*5)+1;
this.maxLinks = 2;
this.speed = .5;
this.a = .5;
this.aReduction = .005;
this.color = "rgba(255,255,255,"+this.a+")";
this.linkColor = "rgba(255,255,255,"+this.a/4+")";
this.dir = Math.floor(Math.random()*140)+200;
}
Dot.prototype.draw = function() {
ctx.fillStyle = this.color;
ctx.shadowBlur = this.r * 2;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
Dot.prototype.link = function() {
if (this.id == 0) return;
var previousDot1 = getPreviousDot(this.id, 1);
var previousDot2 = getPreviousDot(this.id, 2);
var previousDot3 = getPreviousDot(this.id, 3);
if (!previousDot1) return;
ctx.strokeStyle = this.linkColor;
ctx.moveTo(previousDot1.x, previousDot1.y);
ctx.beginPath();
ctx.lineTo(this.x, this.y);
if (previousDot2 != false) ctx.lineTo(previousDot2.x, previousDot2.y);
if (previousDot3 != false) ctx.lineTo(previousDot3.x, previousDot3.y);
ctx.stroke();
ctx.closePath();
}
function getPreviousDot(id, stepback) {
if (id == 0 || id - stepback < 0) return false;
if (typeof dots[id - stepback] != "undefined") return dots[id - stepback];
else return false;//getPreviousDot(id - stepback);
}
Dot.prototype.move = function() {
this.a -= this.aReduction;
if (this.a <= 0) {
this.die();
return
}
this.color = "rgba(255,255,255,"+this.a+")";
this.linkColor = "rgba(255,255,255,"+this.a/4+")";
this.x = this.x + Math.cos(degToRad(this.dir))*this.speed,
this.y = this.y + Math.sin(degToRad(this.dir))*this.speed;
this.draw();
this.link();
}
Dot.prototype.die = function() {
dots[this.id] = null;
delete dots[this.id];
}
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
WIDTH,
HEIGHT,
mouseMoving = false,
mouseMoveChecker,
mouseX,
mouseY,
stars = [],
initStarsPopulation = 80,
dots = [],
dotsMinDist = 2,
maxDistFromCursor = 50;
setCanvasSize();
init();
function setCanvasSize() {
WIDTH = document.documentElement.clientWidth,
HEIGHT = document.documentElement.clientHeight;
canvas.setAttribute("width", WIDTH);
canvas.setAttribute("height", HEIGHT);
}
function init() {
ctx.strokeStyle = "white";
ctx.shadowColor = "white";
for (var i = 0; i < initStarsPopulation; i++) {
stars[i] = new Star(i, Math.floor(Math.random()*WIDTH), Math.floor(Math.random()*HEIGHT));
//stars[i].draw();
}
ctx.shadowBlur = 0;
animate();
}
function animate() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i in stars) {
stars[i].move();
}
for (var i in dots) {
dots[i].move();
}
drawIfMouseMoving();
requestAnimationFrame(animate);
}
window.onmousemove = function(e){
mouseMoving = true;
mouseX = e.clientX;
mouseY = e.clientY;
clearInterval(mouseMoveChecker);
mouseMoveChecker = setTimeout(function() {
mouseMoving = false;
}, 100);
}
function drawIfMouseMoving(){
if (!mouseMoving) return;
if (dots.length == 0) {
dots[0] = new Dot(0, mouseX, mouseY);
dots[0].draw();
return;
}
var previousDot = getPreviousDot(dots.length, 1);
var prevX = previousDot.x;
var prevY = previousDot.y;
var diffX = Math.abs(prevX - mouseX);
var diffY = Math.abs(prevY - mouseY);
if (diffX < dotsMinDist || diffY < dotsMinDist) return;
var xVariation = Math.random() > .5 ? -1 : 1;
xVariation = xVariation*Math.floor(Math.random()*maxDistFromCursor)+1;
var yVariation = Math.random() > .5 ? -1 : 1;
yVariation = yVariation*Math.floor(Math.random()*maxDistFromCursor)+1;
dots[dots.length] = new Dot(dots.length, mouseX+xVariation, mouseY+yVariation);
dots[dots.length-1].draw();
dots[dots.length-1].link();
}
//setInterval(drawIfMouseMoving, 17);
function degToRad(deg) {
return deg * (Math.PI / 180);
}
</script>
</body>
</html>