Skip to content

Commit 8f15247

Browse files
author
Ritika Mishra
committed
updated ui of bandpower and candle
1 parent 67ca344 commit 8f15247

File tree

3 files changed

+626
-747
lines changed

3 files changed

+626
-747
lines changed

src/components/BandPowerGraph.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ const Graph: React.FC<GraphProps> = ({
134134

135135
// inside drawGraph:
136136
const topMargin = 30; // space for any in-canvas labels
137-
const leftMargin = width < 500 ? 60 : 80;
138-
const bottomMargin = width < 640 ? 70 : 80;
139-
const rightMargin = 60;
137+
const leftMargin = width < 500 ? 50 : 60;
138+
const bottomMargin = width < 640 ? 40 : 50;
139+
const rightMargin = 20;
140140

141141
// Draw axes
142142
const axisColor = theme === "dark" ? "white" : "black";
@@ -148,7 +148,7 @@ const Graph: React.FC<GraphProps> = ({
148148
ctx.stroke();
149149

150150
const barWidth = (width - leftMargin - rightMargin) / bandNames.length;
151-
const barSpacing = barWidth * 0.2; // Space between bars
151+
const barSpacing = barWidth * 0.3; // Space between bars
152152

153153
let minPower = 0;
154154
let maxPower = 100;

src/components/CandleLit.tsx

Lines changed: 109 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,129 @@
1-
"use client";
2-
31
import React, { useState, useEffect } from 'react';
42

53
type FFTChannel = number[];
64
type FFTData = FFTChannel[];
75

86
interface BrightCandleViewProps {
9-
fftData?: FFTData;
10-
betaPower: number;
11-
fullscreen?: boolean;
7+
fftData?: FFTData;
8+
betaPower: number;
129
}
1310

1411
interface CandleLitProps {
15-
betaPower: number;
12+
betaPower: number;
1613
}
1714

18-
const BrightCandleView: React.FC<BrightCandleViewProps> = ({ fftData = [], betaPower, fullscreen }) => {
19-
const brightness = Math.max(0, betaPower / 100); // Normalize brightness
20-
// Add smoothing and minimum brightness
21-
const [displayBrightness, setDisplayBrightness] = useState(0.1); // Start with small flame
22-
const [screenSize, setScreenSize] = useState('normal'); // 'normal', 'large' (150%), 'xlarge' (175%)
23-
24-
useEffect(() => {
25-
// Detect screen size
26-
const detectScreenSize = () => {
27-
const width = window.innerWidth;
28-
if (width >= 1920) { // Assuming 1920px is 175% of standard size
29-
setScreenSize('xlarge');
30-
} else if (width >= 1680) { // Assuming 1680px is 150% of standard size
31-
setScreenSize('large');
32-
} else {
33-
setScreenSize('normal');
34-
}
35-
};
36-
37-
// Set initial size
38-
detectScreenSize();
39-
40-
// Update on resize
41-
window.addEventListener('resize', detectScreenSize);
42-
return () => window.removeEventListener('resize', detectScreenSize);
43-
}, []);
44-
45-
useEffect(() => {
46-
// Always show at least a small flame (0.1) and cap at 1.0
47-
const target = Math.max(0.1, Math.min(1, betaPower / 100));
48-
49-
// Smooth transition
50-
const timer = setInterval(() => {
51-
setDisplayBrightness(prev => {
52-
const diff = target - prev;
53-
return Math.abs(diff) < 0.01 ? target : prev + diff * 0.1;
54-
});
55-
}, 16); // ~60fps
56-
57-
return () => clearInterval(timer);
58-
}, [betaPower]);
59-
// console.log("beta",betaPower);
60-
61-
// Use displayBrightness instead of raw betaPower for all visual elements
62-
const flameColor = `rgba(255, 165, 0, ${displayBrightness})`;
63-
// Calculate brightness from FFT data
64-
const calculateBrightness = (): number => {
65-
if (!Array.isArray(fftData) || fftData.length === 0) {
66-
return 0.5;
67-
}
68-
const channelData = fftData.find(
69-
(channel): channel is FFTChannel =>
70-
Array.isArray(channel) && channel.length > 0
71-
);
72-
if (!channelData) return 0.5;
73-
const totalEnergy = channelData.reduce((sum: number, value: number) => sum + (value || 0), 0);
74-
return Math.min(Math.max(totalEnergy / 100, 0.3), 1);
75-
};
76-
77-
78-
// Generate a slightly randomized organic flame path
79-
const generateFlamePath = () => {
80-
const basePoints = [
81-
{ x: 100, y: 30 },
82-
{ x: 60, y: 80 },
83-
{ x: 100, y: 200 },
84-
{ x: 140, y: 80 }
85-
];
86-
const controlPoints = basePoints.map(point => ({
87-
x: point.x + (Math.random() - 0.5) * (10 * brightness),
88-
y: point.y + (Math.random() - 0.5) * (10 * brightness)
89-
}));
90-
return `
15+
const BrightCandleView: React.FC<BrightCandleViewProps> = ({ fftData = [], betaPower }) => {
16+
const brightness = Math.max(0, betaPower / 100); // Normalize brightness
17+
// Add smoothing and minimum brightness
18+
const [displayBrightness, setDisplayBrightness] = useState(0.1); // Start with small flame
19+
20+
useEffect(() => {
21+
// Always show at least a small flame (0.1) and cap at 1.0
22+
const target = Math.max(0.1, Math.min(1, betaPower / 100));
23+
24+
// Smooth transition
25+
const timer = setInterval(() => {
26+
setDisplayBrightness(prev => {
27+
const diff = target - prev;
28+
return Math.abs(diff) < 0.01 ? target : prev + diff * 0.1;
29+
});
30+
}, 16); // ~60fps
31+
32+
return () => clearInterval(timer);
33+
}, [betaPower]);
34+
35+
// Generate a slightly randomized organic flame path
36+
const generateFlamePath = () => {
37+
const basePoints = [
38+
{ x: 100, y: 50 },
39+
{ x: 70, y: 100 },
40+
{ x: 100, y: 180 },
41+
{ x: 130, y: 100 }
42+
];
43+
const controlPoints = basePoints.map(point => ({
44+
x: point.x + (Math.random() - 0.5) * (10 * brightness),
45+
y: point.y + (Math.random() - 0.5) * (10 * brightness)
46+
}));
47+
return `
9148
M${controlPoints[0].x} ${controlPoints[0].y}
9249
Q${controlPoints[1].x} ${controlPoints[1].y}, ${controlPoints[2].x} ${controlPoints[2].y}
9350
Q${controlPoints[3].x} ${controlPoints[3].y}, ${controlPoints[0].x} ${controlPoints[0].y}
9451
`;
95-
};
96-
97-
// Calculate candle size based on screen size and fullscreen state
98-
const getCandleWidthClass = () => {
99-
if (fullscreen) {
100-
return screenSize === 'xlarge' ? 'w-40' : screenSize === 'large' ? 'w-36' : 'w-32';
101-
} else {
102-
return screenSize === 'xlarge' ? 'w-28' : screenSize === 'large' ? 'w-24' : 'w-20';
103-
}
104-
};
105-
106-
const getCandleHeightClass = () => {
107-
if (fullscreen) {
108-
return 'h-96';
109-
} else {
110-
return screenSize === 'xlarge' ? 'h-56' : screenSize === 'large' ? 'h-48' : 'h-40';
111-
}
112-
};
113-
114-
const getCandleHolderHeightClass = () => {
115-
if (fullscreen) {
116-
return 'h-48';
117-
} else {
118-
return screenSize === 'xlarge' ? 'h-28' : screenSize === 'large' ? 'h-24' : 'h-20';
119-
}
120-
};
121-
122-
const getFlameHeightClass = () => {
123-
if (fullscreen) {
124-
return 'h-64'; // Increased from h-48
125-
} else {
126-
return screenSize === 'xlarge' ? 'h-56' :
127-
screenSize === 'large' ? 'h-48' :
128-
'h-40';
129-
}
130-
};
131-
return (
132-
<div className={`w-full h-full flex items-end justify-center min-h-0 min-w-0 ${fullscreen ? 'pb-1' : ''}`}>
133-
{/* Candle Container with dynamic width based on screen size and fullscreen mode */}
134-
<div className={`relative ${getCandleWidthClass()} ${getCandleHeightClass()} group`}>
135-
{/* Candle Holder with a glassy, frosted look */}
136-
<div
137-
className={`absolute bottom-0 w-full ${getCandleHolderHeightClass()} bg-gradient-to-b from-gray-100 to-gray-200 dark:from-stone-600 dark:to-stone-700
138-
rounded-t-md border border-gray-900 dark:border-gray-800 border-b-0 backdrop-blur-md transition-transform duration-300 before:absolute before:inset-0 before:bg-white/10 before:opacity-40 before:rounded-b-xl before:rounded-t-md `}
139-
>
140-
<div className="absolute inset-0 overflow-hidden rounded-t-md bg-gradient-to-b from-cyan-300 via-blue-400 to-gray-900">
141-
<div className="absolute top-2 left-1/2 transform -translate-x-1/2 text-center">
142-
<div
143-
className={` ${fullscreen ? 'text-3xl'
144-
: screenSize === 'xlarge' ? 'text-2xl' : 'text-xl'} font-semibold text-[#030c21] px-2 py-1 rounded-md opacity-70 `}
145-
>
146-
{String(
147-
Math.floor(Number.isNaN(betaPower) ? 0 : betaPower)
148-
).padStart(2, '0')}
149-
</div>
150-
</div>
151-
</div>
152-
</div>
153-
154-
155-
{/* Yellow-Themed Animated Flame */}
156-
<svg
157-
xmlns="http://www.w3.org/2000/svg"
158-
viewBox={`0 0 200 ${fullscreen ? 200 : 400}`} // Increased viewBox height
159-
className={`absolute top-0 left-1/2 transform -translate-x-1/2 w-full ${getFlameHeightClass()} z-10 drop-shadow-xl`}
160-
>
161-
<defs>
162-
{/* Outer Flame Gradient: Rich, Realistic Candle Flame Colors */}
163-
<linearGradient id="outerFlameGradient" x1="0%" y1="0%" x2="0%" y2="100%">
164-
<stop offset="0%" stopColor={`rgba(255,140,0, ${brightness * 1})`} />
165-
<stop offset="100%" stopColor={`rgba(255,69,0, ${brightness * 0.6})`} />
166-
</linearGradient>
167-
168-
{/* Inner Flame Gradient: Warm, Luminous Colors */}
169-
<linearGradient id="innerFlameGradient" x1="0%" y1="0%" x2="0%" y2="100%">
170-
<stop offset="0%" stopColor={`rgba(255,165,0, ${brightness * 1.2})`} />
171-
<stop offset="100%" stopColor={`rgba(255,99,71, ${brightness * 0.8})`} />
172-
</linearGradient>
173-
174-
{/* Filters for Enhanced Realism */}
175-
<filter id="flameBlur">
176-
<feGaussianBlur stdDeviation="7" />
177-
</filter>
178-
<filter id="innerGlow">
179-
<feGaussianBlur stdDeviation="4" result="coloredBlur" />
180-
<feMerge>
181-
<feMergeNode in="coloredBlur" />
182-
<feMergeNode in="SourceGraphic" />
183-
</feMerge>
184-
</filter>
185-
</defs>
186-
187-
{/* Outer Flame Layer */}
188-
<path
189-
d={generateFlamePath()}
190-
fill="url(#outerFlameGradient)"
191-
filter="url(#flameBlur)"
192-
className="transition-all duration-300 animate-flicker opacity-70"
193-
/>
194-
195-
{/* Inner Flame Layer */}
196-
<path
197-
d={generateFlamePath()}
198-
fill="url(#innerFlameGradient)"
199-
filter="url(#innerGlow)"
200-
className="transition-all duration-300 animate-flicker"
201-
/>
202-
</svg>
52+
};
53+
54+
return (
55+
<div className="w-full h-full flex items-center justify-center min-h-0 min-w-0">
56+
{/* Candle Container - responsive width for different screen sizes */}
57+
<div className="relative w-24 sm:w-28 md:w-32 lg:w-36 h-64 group">
58+
{/* Candle Holder with a glassy, frosted look */}
59+
<div className="absolute bottom-0 w-full h-24 sm:h-28 md:h-32
60+
bg-gradient-to-b from-gray-100 to-gray-200 dark:from-stone-600 dark:to-stone-700
61+
rounded-b-xl rounded-t-md
62+
border border-gray-300 dark:border-white/20
63+
backdrop-blur-md shadow-xl
64+
transition-transform duration-300
65+
before:absolute before:inset-0 before:bg-white/10 before:opacity-40 before:rounded-b-xl before:rounded-t-md"
66+
>
67+
<div className="absolute inset-0 overflow-hidden rounded-b-xl rounded-t-md bg-gradient-to-b from-cyan-300 via-blue-400 to-blue-400">
68+
<div className="absolute top-2 left-1/2 transform -translate-x-1/2 text-center">
69+
<div className="text-base sm:text-lg font-semibold text-gray-700 px-1 sm:px-2 py-1 rounded-md">
70+
{String(Math.floor(betaPower)).padStart(2, '0')}
71+
</div>
20372
</div>
73+
</div>
20474
</div>
205-
);
75+
76+
{/* Yellow-Themed Animated Flame */}
77+
<svg
78+
xmlns="http://www.w3.org/2000/svg"
79+
viewBox="0 0 200 300"
80+
className="absolute top-0 left-1/2 transform -translate-x-1/2 w-full h-36 sm:h-40 md:h-44 lg:h-48 z-10 drop-shadow-xl"
81+
>
82+
<defs>
83+
{/* Outer Flame Gradient: Rich, Realistic Candle Flame Colors */}
84+
<linearGradient id="outerFlameGradient" x1="0%" y1="0%" x2="0%" y2="100%">
85+
<stop offset="0%" stopColor={`rgba(255,140,0, ${brightness * 0.6})`} />
86+
<stop offset="100%" stopColor={`rgba(255,69,0, ${brightness * 0.3})`} />
87+
</linearGradient>
88+
89+
{/* Inner Flame Gradient: Warm, Luminous Colors */}
90+
<linearGradient id="innerFlameGradient" x1="0%" y1="0%" x2="0%" y2="100%">
91+
<stop offset="0%" stopColor={`rgba(255,165,0, ${brightness * 0.8})`} />
92+
<stop offset="100%" stopColor={`rgba(255,99,71, ${brightness * 0.5})`} />
93+
</linearGradient>
94+
95+
{/* Filters for Enhanced Realism */}
96+
<filter id="flameBlur">
97+
<feGaussianBlur stdDeviation="7" />
98+
</filter>
99+
<filter id="innerGlow">
100+
<feGaussianBlur stdDeviation="4" result="coloredBlur" />
101+
<feMerge>
102+
<feMergeNode in="coloredBlur" />
103+
<feMergeNode in="SourceGraphic" />
104+
</feMerge>
105+
</filter>
106+
</defs>
107+
108+
{/* Outer Flame Layer */}
109+
<path
110+
d={generateFlamePath()}
111+
fill="url(#outerFlameGradient)"
112+
filter="url(#flameBlur)"
113+
className="transition-all duration-300 animate-flicker opacity-70"
114+
/>
115+
116+
{/* Inner Flame Layer */}
117+
<path
118+
d={generateFlamePath()}
119+
fill="url(#innerFlameGradient)"
120+
filter="url(#innerGlow)"
121+
className="transition-all duration-300 animate-flicker"
122+
/>
123+
</svg>
124+
</div>
125+
</div>
126+
);
206127
};
207128

208129
export default BrightCandleView;

0 commit comments

Comments
 (0)