aisf-landing/components/dot-waves.tsx

97 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useEffect, useRef } from 'react'
export default function DotWaves() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
// Устанавливаем размеры canvas равными размерам контейнера
const resizeCanvas = () => {
const container = canvas.parentElement
if (container) {
canvas.width = container.offsetWidth
canvas.height = container.offsetHeight
}
}
resizeCanvas()
window.addEventListener('resize', resizeCanvas)
// Параметры анимации
const dots: { x: number; y: number; z: number }[] = []
const numberOfDots = 200 // Больше точек для лучшего эффекта
const maxDepth = 1000 // Максимальная глубина по Z
const speed = 10 // Скорость движения
// Создаем точки со случайными позициями в 3D пространстве
for (let i = 0; i < numberOfDots; i++) {
dots.push({
x: (Math.random() - 0.5) * canvas.width * 2,
y: (Math.random() - 0.5) * canvas.height * 2,
z: Math.random() * maxDepth,
})
}
// Анимация
let animationFrameId: number
const animate = () => {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'
ctx.fillRect(0, 0, canvas.width, canvas.height)
const centerX = canvas.width / 2
const centerY = canvas.height / 2
// Рисуем точки
dots.forEach((dot) => {
// Движение к наблюдателю (уменьшаем Z)
dot.z = dot.z - speed
// Если точка слишком близко, перемещаем её обратно вдаль
if (dot.z <= 1) {
dot.z = maxDepth
dot.x = (Math.random() - 0.5) * canvas.width * 2
dot.y = (Math.random() - 0.5) * canvas.height * 2
}
// Проецируем 3D координаты на 2D экран
const scale = maxDepth / (maxDepth + dot.z)
const x2d = centerX + dot.x * scale
const y2d = centerY + dot.y * scale
// Размер и яркость зависят от Z-координаты
const size = Math.max(0.5, 2 * scale)
const alpha = Math.min(1, scale * 1.5)
ctx.beginPath()
ctx.arc(x2d, y2d, size, 0, Math.PI * 2)
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`
ctx.fill()
})
animationFrameId = requestAnimationFrame(animate)
}
animate()
// Очистка
return () => {
window.removeEventListener('resize', resizeCanvas)
cancelAnimationFrame(animationFrameId)
}
}, [])
return (
<canvas
ref={canvasRef}
className="absolute inset-0 w-full h-full pointer-events-none"
style={{ opacity: 0.5 }}
/>
)
}