Forráskód Böngészése

SceneCSV readability fix

Adam Jafarov 3 hete
szülő
commit
c7ecfac2d7
1 módosított fájl, 79 hozzáadás és 61 törlés
  1. 79 61
      src/components/CsvGraph.jsx

+ 79 - 61
src/components/CsvGraph.jsx

@@ -16,12 +16,10 @@ import {
 import Papa from 'papaparse';
 import { API_BASE } from '../config';
 
-const PerformanceCard = ({ title, height = 300, children }) => (
-    <div className="mb-8 last:mb-0">
-        <div className="flex items-center justify-between mb-4">
-            <h3 className="text-sm font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">{title}</h3>
-        </div>
-        <div className="theme-surface border theme-border rounded-xl p-4 shadow-sm h-[300px]">
+const PerformanceCard = ({ title, children }) => (
+    <div className="mb-6 last:mb-0">
+        <h3 className="text-[10px] md:text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2 px-1">{title}</h3>
+        <div className="theme-surface border theme-border rounded-xl p-2 md:p-5 shadow-sm h-[280px] md:h-[380px]">
             <ResponsiveContainer width="100%" height="100%">
                 {children}
             </ResponsiveContainer>
@@ -32,14 +30,16 @@ const PerformanceCard = ({ title, height = 300, children }) => (
 const CustomTooltip = ({ active, payload, label }) => {
     if (active && payload && payload.length) {
         return (
-            <div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 p-3 rounded-lg shadow-xl text-xs">
-                <p className="font-bold mb-2 border-b border-gray-100 dark:border-gray-800 pb-1">Sample {label}</p>
-                {payload.map((entry, index) => (
-                    <div key={index} className="flex items-center justify-between gap-4 my-1">
-                        <span style={{ color: entry.color }} className="font-medium">{entry.name}:</span>
-                        <span className="font-mono text-gray-600 dark:text-gray-300">{entry.value.toLocaleString()}</span>
-                    </div>
-                ))}
+            <div className="bg-white/95 dark:bg-gray-900/95 backdrop-blur-sm border border-gray-200 dark:border-gray-700 p-2 md:p-3 rounded-lg shadow-xl text-[10px] md:text-[12px]">
+                <p className="font-bold mb-1 border-b border-gray-100 dark:border-gray-800 pb-1">Sample {label}</p>
+                <div className="max-h-64 md:max-h-[600px] overflow-y-auto pr-1">
+                    {payload.map((entry, index) => (
+                        <div key={index} className="flex items-center justify-between gap-4 my-0.5">
+                            <span style={{ color: entry.color }} className="font-medium truncate max-w-[100px] md:max-w-none">{entry.name}:</span>
+                            <span className="font-mono text-gray-600 dark:text-gray-300">{entry.value.toLocaleString()}</span>
+                        </div>
+                    ))}
+                </div>
             </div>
         );
     }
@@ -51,6 +51,14 @@ const CsvGraph = ({ rawData }) => {
     const [columns, setColumns] = useState([]);
     const [loading, setLoading] = useState(true);
     const [error, setError] = useState(null);
+    const [isMobile, setIsMobile] = useState(false);
+
+    useEffect(() => {
+        const checkMobile = () => setIsMobile(window.innerWidth < 768);
+        checkMobile();
+        window.addEventListener('resize', checkMobile);
+        return () => window.removeEventListener('resize', checkMobile);
+    }, []);
 
     useEffect(() => {
         const parseData = async () => {
@@ -165,7 +173,7 @@ const CsvGraph = ({ rawData }) => {
             minFps,
             fps5PercentLows,
             above45Percent,
-            avgPower: avg(groups.power.power),
+            avgPower: avg(groups.power.power) ? avg(groups.power.power) / 1000 : null,
             maxTemp: max(groups.power.temp)
         };
     }, [data, groups]);
@@ -180,10 +188,10 @@ const CsvGraph = ({ rawData }) => {
                 const seconds = totalSeconds % 60;
                 return `${minutes}:${seconds.toString().padStart(2, '0')}`;
             }}
-            tick={{ fontSize: 9 }}
+            tick={{ fontSize: isMobile ? 8 : 10 }}
             stroke="#9ca3af"
             interval="preserveStartEnd"
-            minTickGap={40}
+            minTickGap={isMobile ? 30 : 60}
         />
     );
 
@@ -206,33 +214,33 @@ const CsvGraph = ({ rawData }) => {
     const isGeneric = !groups.fps.fps && !groups.cpu.total && !groups.power.power;
 
     return (
-        <div className="w-full space-y-6">
+        <div className="w-full space-y-4 md:space-y-6">
             {/* Summary Stats */}
             {stats && (
-                <div className="grid grid-cols-3 md:grid-cols-6 bg-gray-100 dark:bg-gray-800/40 rounded-lg divide-x divide-y md:divide-y-0 divide-gray-200 dark:divide-gray-700 border theme-border overflow-hidden">
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Avg FPS</p>
-                        <p className="text-lg font-black theme-text leading-none mt-1">{stats.avgFps !== null ? stats.avgFps.toFixed(1) : '-'}</p>
+                <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-6 bg-gray-100 dark:bg-gray-800/40 rounded-lg divide-x divide-y divide-gray-200 dark:divide-gray-700 border theme-border overflow-hidden">
+                    <div className="text-center py-2 md:py-4 px-1 border-t-0 border-l-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Avg FPS</p>
+                        <p className="text-base md:text-2xl font-black theme-text leading-none mt-1">{stats.avgFps !== null ? stats.avgFps.toFixed(1) : '-'}</p>
                     </div>
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Min FPS</p>
-                        <p className="text-lg font-black theme-text leading-none mt-1">{stats.minFps !== null ? stats.minFps.toFixed(1) : '-'}</p>
+                    <div className="text-center py-2 md:py-4 px-1 border-t-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Min FPS</p>
+                        <p className="text-base md:text-2xl font-black theme-text leading-none mt-1">{stats.minFps !== null ? stats.minFps.toFixed(1) : '-'}</p>
                     </div>
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">5% Lows</p>
-                        <p className="text-lg font-black theme-text leading-none mt-1">{stats.fps5PercentLows !== null ? stats.fps5PercentLows.toFixed(1) : '-'}</p>
+                    <div className="text-center py-2 md:py-4 px-1 sm:border-t-0 md:border-t-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">5% Lows</p>
+                        <p className="text-base md:text-2xl font-black theme-text leading-none mt-1">{stats.fps5PercentLows !== null ? stats.fps5PercentLows.toFixed(1) : '-'}</p>
                     </div>
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">≥45 FPS %</p>
-                        <p className="text-lg font-black theme-text leading-none mt-1">{stats.above45Percent !== null ? `${stats.above45Percent.toFixed(0)}%` : '-'}</p>
+                    <div className="text-center py-2 md:py-4 px-1 md:border-t-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">≥45 FPS %</p>
+                        <p className="text-base md:text-2xl font-black theme-text leading-none mt-1">{stats.above45Percent !== null ? `${stats.above45Percent.toFixed(0)}%` : '-'}</p>
                     </div>
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Avg Power</p>
-                        <p className="text-lg font-black theme-text leading-none mt-1">{stats.avgPower !== null ? `${stats.avgPower.toFixed(0)} mW` : '-'}</p>
+                    <div className="text-center py-2 md:py-4 px-1 md:border-t-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Avg Power</p>
+                        <p className="text-base md:text-2xl font-black theme-text leading-none mt-1">{stats.avgPower !== null ? `${stats.avgPower.toFixed(2)} W` : '-'}</p>
                     </div>
-                    <div className="text-center py-2 px-1">
-                        <p className="text-[9px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Max Temp</p>
-                        <p className="text-lg font-black text-red-500 leading-none mt-1">{stats.maxTemp !== null ? `${stats.maxTemp.toFixed(1)}°` : '-'}</p>
+                    <div className="text-center py-2 md:py-4 px-1 md:border-t-0">
+                        <p className="text-[8px] md:text-[10px] font-bold text-gray-500 uppercase tracking-tighter opacity-70">Max Temp</p>
+                        <p className="text-base md:text-2xl font-black text-red-500 leading-none mt-1">{stats.maxTemp !== null ? `${stats.maxTemp.toFixed(1)}°` : '-'}</p>
                     </div>
                 </div>
             )}
@@ -240,21 +248,21 @@ const CsvGraph = ({ rawData }) => {
             {/* 1. FPS & Stutter */}
             {(groups.fps.fps || groups.fps.jank) && (
                 <PerformanceCard title="FPS and Stutter (Jank)">
-                    <ComposedChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 0 }}>
-                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" />
+                    <ComposedChart data={data} margin={{ top: 5, right: 5, left: isMobile ? -20 : 0, bottom: 5 }}>
+                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" opacity={0.3} />
                         {renderXAxis()}
-                        <YAxis domain={[0, 'auto']} tick={{ fontSize: 10 }} stroke="#9ca3af" />
+                        <YAxis domain={[0, 'auto']} tick={{ fontSize: isMobile ? 8 : 11 }} stroke="#9ca3af" width={isMobile ? 40 : 50} />
                         <Tooltip content={<CustomTooltip />} />
-                        <Legend verticalAlign="top" height={36} />
+                        <Legend verticalAlign="top" height={isMobile ? 24 : 40} iconSize={isMobile ? 8 : 12} wrapperStyle={{ fontSize: isMobile ? '9px' : '12px', paddingBottom: '5px' }} />
 
                         {groups.fps.fps && (
                             <Line type="monotone" dataKey={groups.fps.fps} stroke="#3b82f6" strokeWidth={1.5} dot={false} name="FPS" isAnimationActive={false} />
                         )}
                         {groups.fps.jank && (
-                            <Line type="monotone" dataKey={groups.fps.jank} stroke="#f59e0b" strokeWidth={0} dot={{ r: 3, fill: '#f59e0b' }} name="Jank" isAnimationActive={false} />
+                            <Line type="monotone" dataKey={groups.fps.jank} stroke="#f59e0b" strokeWidth={0} dot={{ r: 2.5, fill: '#f59e0b' }} name="Jank" isAnimationActive={false} />
                         )}
                         {groups.fps.bigJank && (
-                            <Line type="monotone" dataKey={groups.fps.bigJank} stroke="#ef4444" strokeWidth={0} dot={{ r: 4, fill: '#ef4444', strokeWidth: 2, stroke: '#fff' }} name="BigJank" isAnimationActive={false} />
+                            <Line type="monotone" dataKey={groups.fps.bigJank} stroke="#ef4444" strokeWidth={0} dot={{ r: isMobile ? 3 : 4, fill: '#ef4444', strokeWidth: 1.5, stroke: '#fff' }} name="BigJank" isAnimationActive={false} />
                         )}
                     </ComposedChart>
                 </PerformanceCard>
@@ -263,16 +271,26 @@ const CsvGraph = ({ rawData }) => {
             {/* 2. CPU Usage & Clocks */}
             {(groups.cpu.total || groups.cpu.clocks.length > 0) && (
                 <PerformanceCard title="CPU Usage and Clock Speeds">
-                    <ComposedChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 0 }}>
-                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" />
+                    <ComposedChart data={data} margin={{ top: 5, right: 5, left: isMobile ? -20 : 0, bottom: 5 }}>
+                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" opacity={0.3} />
                         {renderXAxis()}
-                        <YAxis yAxisId="left" domain={[0, 100]} tick={{ fontSize: 10 }} stroke="#10b981" name="Usage %" />
-                        <YAxis yAxisId="right" orientation="right" tick={{ fontSize: 10 }} stroke="#9ca3af" name="Clock (MHz)" />
+                        <YAxis yAxisId="left" domain={[0, 100]} tick={{ fontSize: isMobile ? 8 : 11 }} stroke="#10b981" width={isMobile ? 30 : 45} />
+                        <YAxis yAxisId="right" orientation="right" tick={{ fontSize: isMobile ? 8 : 11 }} stroke="#9ca3af" width={isMobile ? 30 : 45} />
                         <Tooltip content={<CustomTooltip />} />
-                        <Legend verticalAlign="top" height={36} wrapperStyle={{ fontSize: '10px' }} />
+                        <Legend
+                            verticalAlign="top"
+                            height={isMobile ? 30 : 60}
+                            iconSize={isMobile ? 6 : 10}
+                            wrapperStyle={{
+                                fontSize: isMobile ? '8px' : '11px',
+                                paddingBottom: '5px',
+                                overflowY: 'auto',
+                                maxHeight: isMobile ? '40px' : '150px'
+                            }}
+                        />
 
                         {groups.cpu.total && (
-                            <Line yAxisId="left" type="monotone" dataKey={groups.cpu.total} stroke="#10b981" strokeWidth={2.5} dot={false} name="Total CPU %" isAnimationActive={false} />
+                            <Line yAxisId="left" type="monotone" dataKey={groups.cpu.total} stroke="#10b981" strokeWidth={2.5} dot={false} name="Total%" isAnimationActive={false} />
                         )}
 
                         {groups.cpu.clocks.map((clock, idx) => (
@@ -282,9 +300,9 @@ const CsvGraph = ({ rawData }) => {
                                 type="monotone"
                                 dataKey={clock}
                                 stroke={`hsl(${idx * 40}, 60%, 50%)`}
-                                strokeWidth={0.8}
+                                strokeWidth={isMobile ? 0.6 : 1.2}
                                 dot={false}
-                                name={clock}
+                                name={clock.replace('(MHz)', '')}
                                 opacity={0.25}
                                 isAnimationActive={false}
                             />
@@ -294,24 +312,24 @@ const CsvGraph = ({ rawData }) => {
             )}
 
             {/* 3. Power & Temp & Battery */}
-            {(groups.power.power || groups.power.temp || groups.power.level) && (
+            {(groups.power.power || groups.power.level || groups.power.temp) && (
                 <PerformanceCard title="Power, Thermal and Battery Level">
-                    <ComposedChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 0 }}>
-                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" />
+                    <ComposedChart data={data} margin={{ top: 5, right: 5, left: isMobile ? -20 : 0, bottom: 5 }}>
+                        <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e5e7eb" opacity={0.3} />
                         {renderXAxis()}
-                        <YAxis yAxisId="left" tick={{ fontSize: 10 }} stroke="#8b5cf6" name="Power (mW)" />
-                        <YAxis yAxisId="right" orientation="right" tick={{ fontSize: 10 }} stroke="#ef4444" name="Temp/Level" domain={['auto', 'auto']} />
+                        <YAxis yAxisId="left" tick={{ fontSize: isMobile ? 8 : 11 }} stroke="#8b5cf6" width={isMobile ? 40 : 55} />
+                        <YAxis yAxisId="right" orientation="right" tick={{ fontSize: isMobile ? 8 : 11 }} stroke="#ef4444" domain={['auto', 'auto']} width={isMobile ? 30 : 45} />
                         <Tooltip content={<CustomTooltip />} />
-                        <Legend verticalAlign="top" height={36} />
+                        <Legend verticalAlign="top" height={isMobile ? 24 : 40} iconSize={isMobile ? 8 : 12} wrapperStyle={{ fontSize: isMobile ? '9px' : '12px', paddingBottom: '5px' }} />
 
                         {groups.power.power && (
                             <Line yAxisId="left" type="monotone" dataKey={groups.power.power} stroke="#8b5cf6" strokeWidth={1.5} dot={false} name="Power (mW)" isAnimationActive={false} />
                         )}
                         {groups.power.temp && (
-                            <Line yAxisId="right" type="monotone" dataKey={groups.power.temp} stroke="#ef4444" strokeWidth={2} strokeDasharray="4 4" dot={false} name="Battery Temp (°C)" isAnimationActive={false} />
+                            <Line yAxisId="right" type="monotone" dataKey={groups.power.temp} stroke="#ef4444" strokeWidth={1.5} strokeDasharray="3 3" dot={false} name="Temp" isAnimationActive={false} />
                         )}
                         {groups.power.level && (
-                            <Line yAxisId="right" type="stepAfter" dataKey={groups.power.level} stroke="#3b82f6" strokeWidth={2} dot={false} name="Battery Level (%)" isAnimationActive={false} />
+                            <Line yAxisId="right" type="stepAfter" dataKey={groups.power.level} stroke="#3b82f6" strokeWidth={2} dot={false} name="Batt%" isAnimationActive={false} />
                         )}
                     </ComposedChart>
                 </PerformanceCard>
@@ -335,10 +353,10 @@ const CsvGraph = ({ rawData }) => {
 
             {/* Shared Brush for scrolling */}
             {data.length > 0 && (
-                <div className="h-12 w-full mt-4 bg-gray-50 dark:bg-gray-800/50 rounded-lg p-2">
+                <div className="h-10 w-full mt-2 bg-gray-50/50 dark:bg-gray-800/20 rounded-lg p-1">
                     <ResponsiveContainer width="100%" height="100%">
                         <LineChart data={data}>
-                            <Brush height={20} stroke="#3b82f6" fill="transparent" />
+                            <Brush height={16} stroke="#3b82f6" fill="transparent" tickFormatter={() => ''} />
                         </LineChart>
                     </ResponsiveContainer>
                 </div>