diff --git a/src/components/DataRoom/SeeMore/SlidingWave.tsx b/src/components/DataRoom/SeeMore/SlidingWave.tsx index fce2de39b..fbf04f88c 100644 --- a/src/components/DataRoom/SeeMore/SlidingWave.tsx +++ b/src/components/DataRoom/SeeMore/SlidingWave.tsx @@ -30,13 +30,7 @@ export default function SlidingWave({
- - - - - - - + ) diff --git a/src/components/DataRoom/SeeMore/Wave.tsx b/src/components/DataRoom/SeeMore/Wave.tsx index 3a31f928a..ecad432c4 100644 --- a/src/components/DataRoom/SeeMore/Wave.tsx +++ b/src/components/DataRoom/SeeMore/Wave.tsx @@ -1,66 +1,105 @@ import useContainerSize from '@/hooks/useContainerSize' -import React, { useEffect, useRef } from 'react' +import React, { useEffect, useRef, useMemo, useCallback } from 'react' type WaveProps = { height?: number - color?: string + colors?: string[] amplitude?: number frequency?: number speed?: number } const DEFAULT_HEIGHT = 600 -const DEFAULT_COLOR = '#12FF80' +const DEFAULT_COLORS = ['#12FF80', '#008A40', '#003C1C'] const DEFAULT_AMPLITUDE = 100 const DEFAULT_FREQUENCY = 1 -const DEFAULT_SPEED = 3 +const DEFAULT_SPEED = 0.8 const STROKE_WIDTH = 4 const Wave = ({ height = DEFAULT_HEIGHT, - color = DEFAULT_COLOR, + colors = DEFAULT_COLORS, amplitude = DEFAULT_AMPLITUDE, frequency = DEFAULT_FREQUENCY, speed = DEFAULT_SPEED, }: WaveProps) => { + const canvasRef = useRef(null) const containerRef = useRef(null) const { width } = useContainerSize(containerRef) + const animationRef = useRef() - useEffect(() => { - let startTime: number | null = null - let animationFrameId: number - - const animate = (time: number) => { - if (!startTime) startTime = time - const elapsed = time - startTime - - // Only create the path if width is valid - if (width > 0) { - const path = Array.from({ length: width + 1 }, (_, i) => { - const y = height / 2 + amplitude * Math.sin((i / width) * 2 * Math.PI * frequency + (elapsed * speed) / 1000) - return `${i},${y}` - }).join(' L') - - const pathElement = containerRef.current?.querySelector('path') - if (pathElement) { - pathElement.setAttribute('d', `M${path}`) - } + const dpr = useMemo(() => window.devicePixelRatio || 1, []) + + const paths = useMemo(() => { + if (width === 0) return [[], [], []] + const calculatePath = (amplitudeOffset: number) => + Array.from( + { length: width + 1 }, + (_, i) => (amplitude - amplitudeOffset) * Math.sin((i / width) * 2 * Math.PI * frequency), + ) + return [calculatePath(80), calculatePath(40), calculatePath(0)] + }, [width, amplitude, frequency]) + + const setupCanvas = useCallback(() => { + const canvas = canvasRef.current + const ctx = canvas?.getContext('2d') + if (!ctx || !canvas || width === 0) return + + canvas.width = width * dpr + canvas.height = height * dpr + canvas.style.width = `${width}px` + canvas.style.height = `${height}px` + ctx.scale(dpr, dpr) + }, [width, height, dpr]) + + const drawWave = useCallback( + (ctx: CanvasRenderingContext2D, path: number[], color: string, shift: number) => { + ctx.beginPath() + ctx.lineWidth = STROKE_WIDTH + ctx.strokeStyle = color + + for (let i = 0; i <= width; i++) { + ctx.lineTo(i, height / 2 + path[(i + Math.floor(shift)) % width]) } - animationFrameId = requestAnimationFrame(animate) - } + ctx.stroke() + }, + [width, height], + ) + + const animate = useCallback( + (time: number) => { + const canvas = canvasRef.current + const ctx = canvas?.getContext('2d') + if (!ctx || !canvas) return - animationFrameId = requestAnimationFrame(animate) - return () => cancelAnimationFrame(animationFrameId) - }, [width, height, amplitude, frequency, speed]) + const shift = (time * speed) % width + + ctx.clearRect(0, 0, width, height) + + paths.forEach((path, index) => { + drawWave(ctx, path, colors[index % colors.length], shift) + }) + + animationRef.current = requestAnimationFrame(animate) + }, + [width, height, paths, speed, colors, drawWave], + ) + + useEffect(() => { + setupCanvas() + animationRef.current = requestAnimationFrame(animate) + + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current) + } + } + }, [setupCanvas, animate]) return (
- {width > 0 && ( - - - - )} +
) } diff --git a/src/components/DataRoom/SeeMore/styles.module.css b/src/components/DataRoom/SeeMore/styles.module.css index 98c2dca6e..fba121f9d 100644 --- a/src/components/DataRoom/SeeMore/styles.module.css +++ b/src/components/DataRoom/SeeMore/styles.module.css @@ -38,18 +38,7 @@ width: 100%; transform: translateY(-50%); right: 0; - --wave-index: 30; - z-index: calc(var(--wave-index) - (var(--n) * 10)); -} - -.wave:nth-child(1) { - --n: 0; -} -.wave:nth-child(2) { - --n: 1; -} -.wave:nth-child(3) { - --n: 2; + z-index: 30; } @media (max-width: 900px) {