mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
Added particles to light bar
This commit is contained in:
parent
2e7b6f3338
commit
88beacde1a
3 changed files with 147 additions and 2 deletions
|
@ -60,7 +60,7 @@ export function SearchBarInput(props: SearchBarProps) {
|
||||||
onFocus={() => setFocused(true)}
|
onFocus={() => setFocused(true)}
|
||||||
onChange={(val) => setSearch(val)}
|
onChange={(val) => setSearch(val)}
|
||||||
value={props.value.searchQuery}
|
value={props.value.searchQuery}
|
||||||
className="text-search-text w-full flex-1 bg-transparent px-4 py-4 pl-12 placeholder-search-placeholder focus:outline-none sm:py-4 sm:pr-2"
|
className="w-full flex-1 bg-transparent px-4 py-4 pl-12 text-search-text placeholder-search-placeholder focus:outline-none sm:py-4 sm:pr-2"
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
/>
|
/>
|
||||||
</Flare.Child>
|
</Flare.Child>
|
||||||
|
|
|
@ -19,4 +19,13 @@
|
||||||
transform: rotate(180deg) translateZ(0px) translateY(400px);
|
transform: rotate(180deg) translateZ(0px) translateY(400px);
|
||||||
transform-origin: center center;
|
transform-origin: center center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbar canvas {
|
||||||
|
width: 40%;
|
||||||
|
height: 300px;
|
||||||
|
transform: translateY(-50%) rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,145 @@
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
import "./Lightbar.css";
|
import "./Lightbar.css";
|
||||||
|
|
||||||
|
class Particle {
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
y = 0;
|
||||||
|
|
||||||
|
radius = 0;
|
||||||
|
|
||||||
|
direction = 0;
|
||||||
|
|
||||||
|
speed = 0;
|
||||||
|
|
||||||
|
lifetime = 0;
|
||||||
|
|
||||||
|
ran = 0;
|
||||||
|
|
||||||
|
constructor(canvas: HTMLCanvasElement) {
|
||||||
|
this.reset(canvas);
|
||||||
|
this.initialize(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(canvas: HTMLCanvasElement) {
|
||||||
|
this.x = Math.round((Math.random() * canvas.width) / 2 + canvas.width / 4);
|
||||||
|
this.y = Math.random() * 100 + 5;
|
||||||
|
|
||||||
|
this.radius = 1 + Math.floor(Math.random() * 0.5);
|
||||||
|
this.direction = -((Math.random() * Math.PI) / 2) + Math.PI / 4;
|
||||||
|
this.speed = 0.02 + Math.random() * 0.08;
|
||||||
|
|
||||||
|
const second = 60;
|
||||||
|
this.lifetime = second * 3 + Math.random() * (second * 30);
|
||||||
|
|
||||||
|
this.ran = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(canvas: HTMLCanvasElement) {
|
||||||
|
this.ran = Math.random() * this.lifetime;
|
||||||
|
const baseSpeed = this.speed;
|
||||||
|
this.speed = Math.random() * this.lifetime * baseSpeed;
|
||||||
|
this.update(canvas);
|
||||||
|
this.speed = baseSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(canvas: HTMLCanvasElement) {
|
||||||
|
this.ran += 1;
|
||||||
|
|
||||||
|
const addX = this.speed * Math.sin(this.direction);
|
||||||
|
const addY = this.speed * Math.cos(this.direction);
|
||||||
|
this.x += addX;
|
||||||
|
this.y += addY;
|
||||||
|
|
||||||
|
if (this.ran > this.lifetime) {
|
||||||
|
this.reset(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(canvas: HTMLCanvasElement) {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
|
||||||
|
const x = this.ran / this.lifetime;
|
||||||
|
const o = (x - x * x) * 4;
|
||||||
|
ctx.globalAlpha = Math.max(0, o * 0.8);
|
||||||
|
|
||||||
|
ctx.ellipse(
|
||||||
|
this.x,
|
||||||
|
this.y,
|
||||||
|
this.radius,
|
||||||
|
this.radius * 1.5,
|
||||||
|
this.direction,
|
||||||
|
0,
|
||||||
|
Math.PI * 2
|
||||||
|
);
|
||||||
|
ctx.fillStyle = "white";
|
||||||
|
ctx.fill();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ParticlesCanvas() {
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!canvasRef.current) return;
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
const particles: Particle[] = [];
|
||||||
|
|
||||||
|
canvas.width = canvas.scrollWidth;
|
||||||
|
canvas.height = canvas.scrollHeight;
|
||||||
|
|
||||||
|
for (let i = 0; i < 20; i += 1) {
|
||||||
|
const particle = new Particle(canvas);
|
||||||
|
particles.push(particle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldTick = true;
|
||||||
|
let handle: ReturnType<typeof requestAnimationFrame> | null = null;
|
||||||
|
function particlesLoop() {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
if (shouldTick) {
|
||||||
|
for (const particle of particles) {
|
||||||
|
particle.update(canvas);
|
||||||
|
}
|
||||||
|
shouldTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.width = canvas.scrollWidth;
|
||||||
|
canvas.height = canvas.scrollHeight;
|
||||||
|
for (const particle of particles) {
|
||||||
|
particle.render(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = requestAnimationFrame(particlesLoop);
|
||||||
|
}
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
shouldTick = true;
|
||||||
|
}, 1e3 / 120); // tick 120 times a sec
|
||||||
|
|
||||||
|
particlesLoop();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (handle) cancelAnimationFrame(handle);
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <canvas className="particles" ref={canvasRef} />;
|
||||||
|
}
|
||||||
|
|
||||||
export function Lightbar(props: { className?: string }) {
|
export function Lightbar(props: { className?: string }) {
|
||||||
return (
|
return (
|
||||||
<div className={props.className}>
|
<div className={props.className}>
|
||||||
<div className="lightbar" />
|
<div className="lightbar">
|
||||||
|
<ParticlesCanvas />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue