Spaces:
Sleeping
Sleeping
File size: 4,099 Bytes
d7a8925 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
import React, { useEffect, useRef } from 'react';
const WaveCanvas = () => {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
let animationFrameId;
// Set canvas size
const setCanvasSize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
// Initial setup
setCanvasSize();
// Wave parameters
const waves = [
{ amplitude: 120, frequency: 0.001, speed: 0.0005, phase: 0 },
{ amplitude: 80, frequency: 0.002, speed: 0.0004, phase: 2 }
];
// Get theme colors
const getColors = () => {
const isDarkTheme = document.body.getAttribute('data-theme') === 'dark';
return {
firstWave: isDarkTheme
? { r: 147, g: 51, b: 234 } // Purple for dark theme
: { r: 18, g: 163, b: 176 }, // #12A3B0 Bright teal
secondWave: isDarkTheme
? { r: 59, g: 130, b: 246 } // Blue for dark theme
: { r: 1, g: 73, b: 81 } // #014951 Medium teal
};
};
// Draw function
const draw = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Center the waves vertically
const centerY = canvas.height * 0.5;
const colors = getColors();
waves.forEach((wave, index) => {
// Update wave phase
wave.phase += wave.speed;
// Create gradient with theme-aware colors
const gradient = ctx.createLinearGradient(0, centerY - wave.amplitude, 0, centerY + wave.amplitude);
const color = index === 0 ? colors.firstWave : colors.secondWave;
if (document.body.getAttribute('data-theme') === 'dark') {
gradient.addColorStop(0, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`);
gradient.addColorStop(0.5, `rgba(${color.r}, ${color.g}, ${color.b}, 0.8)`);
gradient.addColorStop(1, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`);
} else {
// Light theme gradient with additional color stops
gradient.addColorStop(0, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`);
gradient.addColorStop(0.2, `rgba(1, 49, 53, 0.4)`); // #013135
gradient.addColorStop(0.5, `rgba(${color.r}, ${color.g}, ${color.b}, 0.8)`);
gradient.addColorStop(0.8, `rgba(175, 221, 229, 0.4)`); // #AFDDE5
gradient.addColorStop(1, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`);
}
// Begin drawing wave
ctx.beginPath();
// Start from bottom left
ctx.moveTo(0, canvas.height);
ctx.lineTo(0, centerY);
// Draw wave path
for (let x = 0; x <= canvas.width; x++) {
const y = centerY +
Math.sin(x * wave.frequency + wave.phase) * wave.amplitude;
ctx.lineTo(x, y);
}
// Complete the path to bottom right
ctx.lineTo(canvas.width, centerY);
ctx.lineTo(canvas.width, canvas.height);
ctx.closePath();
// Fill with gradient
ctx.fillStyle = gradient;
ctx.fill();
});
animationFrameId = requestAnimationFrame(draw);
};
// Start animation
draw();
// Handle resize and theme changes
const handleResize = () => {
setCanvasSize();
};
window.addEventListener('resize', handleResize);
// Watch for theme changes
const observer = new MutationObserver(() => {
draw(); // Redraw when theme changes
});
observer.observe(document.body, {
attributes: true,
attributeFilter: ['data-theme']
});
// Cleanup
return () => {
window.removeEventListener('resize', handleResize);
cancelAnimationFrame(animationFrameId);
observer.disconnect();
};
}, []);
return <canvas ref={canvasRef} className="wave-canvas" />;
};
export default WaveCanvas; |