artivate/components/hero-data-stream-effect.tsx

88 lines
3.1 KiB
TypeScript
Raw Permalink Normal View History

2025-02-24 15:52:36 +07:00
"use client";
import { useEffect, useRef } from "react";
export function HeroDataStreamEffect() {
const svgRef = useRef<SVGSVGElement>(null);
useEffect(() => {
const svg = svgRef.current;
if (!svg) return;
const resizeSVG = () => {
const headerElement = document.querySelector(".hero-header");
if (headerElement) {
const rect = headerElement.getBoundingClientRect();
const width = Math.max(rect.width + 200, window.innerWidth);
const height = Math.max(rect.height + 200, window.innerHeight);
svg.setAttribute("width", `${width}px`);
svg.setAttribute("height", `${height}px`);
svg.style.top = `${Math.min(rect.top - 100, 0)}px`;
svg.style.left = `${(window.innerWidth - width) / 2}px`;
}
};
resizeSVG();
window.addEventListener("resize", resizeSVG);
const createStream = () => {
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
const startX = Math.random() * svg.clientWidth;
const startY = -50;
const endX = Math.random() * svg.clientWidth;
const endY = svg.clientHeight + 50;
const midX1 = startX + (Math.random() - 0.5) * 200;
const midY1 = startY + (endY - startY) * 0.33;
const midX2 = endX + (Math.random() - 0.5) * 200;
const midY2 = startY + (endY - startY) * 0.66;
const d = `M ${startX} ${startY} C ${midX1} ${midY1}, ${midX2} ${midY2}, ${endX} ${endY}`;
path.setAttribute("d", d);
path.setAttribute("stroke", "rgba(94, 81, 236, 0.4)");
path.setAttribute("stroke-width", "1.5");
path.setAttribute("fill", "none");
path.setAttribute("opacity", "0");
const length = path.getTotalLength();
path.setAttribute("stroke-dasharray", length.toString());
path.setAttribute("stroke-dashoffset", length.toString());
svg.appendChild(path);
return { path, length };
};
const streams: { path: SVGPathElement; length: number }[] = [];
for (let i = 0; i < 15; i++) {
streams.push(createStream());
}
let progress = 0;
const animate = () => {
progress += 0.003;
streams.forEach(({ path, length }, index) => {
const offset = (progress + index * 0.1) % 1;
const opacity = Math.sin(offset * Math.PI) * 0.7;
path.setAttribute("stroke-dashoffset", ((1 - offset) * length).toString());
path.setAttribute("opacity", opacity.toString());
});
requestAnimationFrame(animate);
};
animate();
return () => {
window.removeEventListener("resize", resizeSVG);
};
}, []);
return (
<svg
ref={svgRef}
className="absolute pointer-events-none -z-50 scale-y-150"
style={{ filter: "drop-shadow(0 0 10px rgba(94, 81, 236, 0.3))" }}
/>
);
}