Skip to content

Commit 520e656

Browse files
committed
Replace percentage mode with Line and Gain visual modes for metrics charts
1 parent 372db2b commit 520e656

1 file changed

Lines changed: 37 additions & 32 deletions

File tree

src/components/Content/History/Charts/StackedAreaChart.js

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import ChartContainer from '../Components/ChartContainer';
99
const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0 }) => {
1010
const theme = useTheme();
1111
const [activeSeries, setActiveSeries] = useState(null);
12-
const [stackOffset, setStackOffset] = useState('none');
12+
const [viewMode, setViewMode] = useState('volume'); // 'volume', 'lines', 'gains'
1313
const { timeRange, customRange, hiddenSeries, toggleSeries, isolateSeries } = useHistoryContext();
1414
const { filteredData, rawHistory } = useHistoryData(timeRange, customRange);
1515

@@ -35,32 +35,37 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
3535
}, [rawHistory, names, prefix]);
3636

3737
const chartData = useMemo(() => {
38+
if (!filteredData || filteredData.length === 0) return [];
39+
40+
// For 'gains' mode, capture the baseline values (first timestamp)
41+
const baseValues = {};
42+
if (viewMode === 'gains') {
43+
const firstEntry = filteredData[0];
44+
visibleSeries.forEach(({ i }) => {
45+
const key = `${prefix}_${i}`;
46+
baseValues[key] = Number(firstEntry[key]) || 0;
47+
});
48+
}
49+
3850
return filteredData.map(d => {
3951
const safeData = { ...d };
40-
let visibleSum = 0;
41-
let firstVisibleKey = null;
4252

4353
visibleSeries.forEach(({ i }) => {
4454
const key = `${prefix}_${i}`;
4555
let val = Number(safeData[key]);
46-
if (isNaN(val) || val < 0) val = 0; // Prevent negative or invalid values
47-
48-
safeData[key] = val;
56+
if (isNaN(val) || val < 0) val = 0;
4957

50-
if (!hiddenSeries.has(key)) {
51-
visibleSum += val;
52-
if (!firstVisibleKey) firstVisibleKey = key;
58+
if (viewMode === 'gains') {
59+
// Show only growth since the start
60+
safeData[key] = Math.max(0, val - baseValues[key]);
61+
} else {
62+
safeData[key] = val;
5363
}
5464
});
5565

56-
// Prevent React/Recharts from crashing in Expand mode when total sum is exactly 0
57-
if (stackOffset === 'expand' && visibleSum === 0 && firstVisibleKey) {
58-
safeData[firstVisibleKey] = 0.000001;
59-
}
60-
6166
return safeData;
6267
});
63-
}, [filteredData, stackOffset, visibleSeries, hiddenSeries, prefix]);
68+
}, [filteredData, viewMode, visibleSeries, hiddenSeries, prefix]);
6469

6570
const getClosestSeries = (e) => {
6671
if (!e || !e.activePayload || e.activePayload.length === 0) return null;
@@ -114,11 +119,7 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
114119
gap: useGrid ? 1.5 : 0.5
115120
}}>
116121
{sorted.map((entry, index) => {
117-
// In 'expand' mode, Recharts converts values to percentages implicitly,
118-
// but payload.value usually holds the original value, unless it's transformed.
119-
// However, we want to show original values and possibly percentage.
120-
// Let's just show original values as shorten() for now, maybe with % if expand mode.
121-
const originalValue = entry.value;
122+
const displayValue = entry.value;
122123
return (
123124
<Box key={index} sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1 }}>
124125
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, minWidth: 0 }}>
@@ -129,7 +130,7 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
129130
</Box>
130131
<Box sx={{ display: 'flex', gap: 1 }}>
131132
<Typography variant="caption" sx={{ fontWeight: 800, fontFamily: 'monospace', color: entry.color, fontSize: '0.75rem' }}>
132-
{shorten(originalValue)}
133+
{viewMode === 'gains' && displayValue > 0 ? '+' : ''}{shorten(displayValue)}
133134
</Typography>
134135
</Box>
135136
</Box>
@@ -144,14 +145,15 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
144145

145146
const controls = (
146147
<ToggleButtonGroup
147-
value={stackOffset}
148+
value={viewMode}
148149
exclusive
149-
onChange={(e, val) => val && setStackOffset(val)}
150+
onChange={(e, val) => val && setViewMode(val)}
150151
size="small"
151-
sx={{ height: 26, '.MuiToggleButton-root': { py: 0, px: 1.5, fontSize: '0.7rem', fontWeight: 700 } }}
152+
sx={{ height: 26, '.MuiToggleButton-root': { py: 0, px: 2, fontSize: '0.7rem', fontWeight: 800 } }}
152153
>
153-
<ToggleButton value="none">Total</ToggleButton>
154-
<ToggleButton value="expand">%</ToggleButton>
154+
<ToggleButton value="volume">Total</ToggleButton>
155+
<ToggleButton value="lines">Lines</ToggleButton>
156+
<ToggleButton value="gains">Gains</ToggleButton>
155157
</ToggleButtonGroup>
156158
);
157159

@@ -162,7 +164,6 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
162164
<AreaChart
163165
data={chartData}
164166
margin={{ top: 10, right: 30, left: 10, bottom: 0 }}
165-
stackOffset={stackOffset}
166167
>
167168
<CartesianGrid strokeDasharray="3 3" opacity={0.1} vertical={false} style={{ pointerEvents: 'none' }} />
168169
<XAxis
@@ -174,8 +175,8 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
174175
fontSize={10}
175176
/>
176177
<YAxis
177-
tickFormatter={(v) => stackOffset === 'expand' ? `${(v * 100).toFixed(0)}%` : shorten(v)}
178-
domain={stackOffset === 'expand' ? [0, 1] : ['auto', 'auto']}
178+
tickFormatter={(v) => (viewMode === 'gains' && v > 0) ? `+${shorten(v)}` : shorten(v)}
179+
domain={['auto', 'auto']}
179180
stroke={theme.palette.text.secondary}
180181
fontSize={10}
181182
width={55}
@@ -198,12 +199,16 @@ const StackedAreaChart = ({ title, icon, color, prefix, names, baseColorHue = 0
198199
type="monotone"
199200
dataKey={seriesKey}
200201
name={name}
201-
stackId="1"
202+
stackId={viewMode === 'volume' ? "1" : undefined}
202203
stroke={fillColor}
203204
fill={fillColor}
204-
fillOpacity={activeSeries ? (activeSeries === seriesKey ? 0.8 : 0.1) : 0.5}
205+
fillOpacity={
206+
viewMode === 'volume'
207+
? (activeSeries ? (activeSeries === seriesKey ? 0.8 : 0.1) : 0.5)
208+
: (activeSeries === seriesKey ? 0.2 : 0)
209+
}
205210
strokeOpacity={activeSeries ? (activeSeries === seriesKey ? 1 : 0.2) : 1}
206-
strokeWidth={activeSeries === seriesKey ? 2 : 1}
211+
strokeWidth={viewMode !== 'volume' ? 2 : (activeSeries === seriesKey ? 2 : 1)}
207212
activeDot={{ r: 4, strokeWidth: 0 }}
208213
/>
209214
);

0 commit comments

Comments
 (0)