@takaro/lib-components 0.4.9 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/package.json +1 -1
  2. package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +1 -1
  3. package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +1 -1
  4. package/src/components/charts/AreaChart/AreaChart.stories.tsx +11 -7
  5. package/src/components/charts/AreaChart/index.tsx +114 -63
  6. package/src/components/charts/BarChart/BarChart.stories.tsx +33 -10
  7. package/src/components/charts/BarChart/index.tsx +280 -147
  8. package/src/components/charts/EmptyChart.tsx +45 -0
  9. package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +15 -9
  10. package/src/components/charts/GeoMercator/index.tsx +15 -172
  11. package/src/components/charts/Heatmap/Heatmap.stories.tsx +167 -33
  12. package/src/components/charts/Heatmap/index.tsx +427 -193
  13. package/src/components/charts/LineChart/LineChart.stories.tsx +77 -3
  14. package/src/components/charts/LineChart/index.tsx +200 -79
  15. package/src/components/charts/PieChart/PieChart.stories.tsx +128 -20
  16. package/src/components/charts/PieChart/index.tsx +353 -59
  17. package/src/components/charts/PointHighlight.tsx +2 -2
  18. package/src/components/charts/RadarChart/RadarChart.stories.tsx +14 -5
  19. package/src/components/charts/RadarChart/index.tsx +94 -45
  20. package/src/components/charts/RadialBarChart/RadialBarChart.stories.tsx +26 -1
  21. package/src/components/charts/RadialBarChart/index.tsx +100 -34
  22. package/src/components/charts/RadialLineChart/RadialLineChart.stories.tsx +19 -2
  23. package/src/components/charts/RadialLineChart/index.tsx +116 -26
  24. package/src/components/charts/index.tsx +0 -26
  25. package/src/components/charts/util.ts +50 -12
  26. package/src/components/data/CountryList/index.tsx +146 -0
  27. package/src/components/data/Stats/Sparkline.tsx +48 -0
  28. package/src/components/data/Stats/Stat.tsx +15 -4
  29. package/src/components/data/Stats/context.tsx +1 -1
  30. package/src/components/data/Stats/index.tsx +8 -3
  31. package/src/components/data/index.ts +3 -0
  32. package/src/components/feedback/IconTooltip/index.tsx +9 -6
  33. package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +13 -14
  34. package/src/components/feedback/ProgressBar/index.tsx +1 -1
  35. package/src/components/inputs/DurationField/__tests__/Generic.test.tsx +12 -0
  36. package/src/components/visual/Card/CardTitle.tsx +7 -1
  37. package/src/components/visual/Card/index.tsx +0 -4
  38. package/src/helpers/formatNumber.ts +6 -0
  39. package/src/helpers/index.ts +1 -0
  40. package/src/components/charts/echarts/EChartsArea.stories.tsx +0 -139
  41. package/src/components/charts/echarts/EChartsArea.tsx +0 -139
  42. package/src/components/charts/echarts/EChartsBar.stories.tsx +0 -141
  43. package/src/components/charts/echarts/EChartsBar.tsx +0 -133
  44. package/src/components/charts/echarts/EChartsBase.tsx +0 -264
  45. package/src/components/charts/echarts/EChartsFunnel.stories.tsx +0 -164
  46. package/src/components/charts/echarts/EChartsFunnel.tsx +0 -114
  47. package/src/components/charts/echarts/EChartsHeatmap.stories.tsx +0 -168
  48. package/src/components/charts/echarts/EChartsHeatmap.tsx +0 -141
  49. package/src/components/charts/echarts/EChartsLine.stories.tsx +0 -132
  50. package/src/components/charts/echarts/EChartsLine.tsx +0 -111
  51. package/src/components/charts/echarts/EChartsPie.stories.tsx +0 -131
  52. package/src/components/charts/echarts/EChartsPie.tsx +0 -124
  53. package/src/components/charts/echarts/EChartsRadialBar.stories.tsx +0 -124
  54. package/src/components/charts/echarts/EChartsRadialBar.tsx +0 -118
  55. package/src/components/charts/echarts/EChartsScatter.stories.tsx +0 -166
  56. package/src/components/charts/echarts/EChartsScatter.tsx +0 -135
  57. package/src/components/charts/echarts/index.ts +0 -26
@@ -1,264 +0,0 @@
1
- import { FC, useEffect, useRef, useMemo } from 'react';
2
- import ReactEChartsCore from 'echarts-for-react/lib/core';
3
- import * as echarts from 'echarts/core';
4
- import { CanvasRenderer } from 'echarts/renderers';
5
- import {
6
- TitleComponent,
7
- TooltipComponent,
8
- GridComponent,
9
- LegendComponent,
10
- ToolboxComponent,
11
- DataZoomComponent,
12
- VisualMapComponent,
13
- MarkLineComponent,
14
- MarkPointComponent,
15
- MarkAreaComponent,
16
- PolarComponent,
17
- } from 'echarts/components';
18
- import {
19
- LineChart,
20
- BarChart,
21
- PieChart,
22
- ScatterChart,
23
- RadarChart,
24
- MapChart,
25
- TreeChart,
26
- TreemapChart,
27
- GraphChart,
28
- GaugeChart,
29
- FunnelChart,
30
- ParallelChart,
31
- SankeyChart,
32
- BoxplotChart,
33
- CandlestickChart,
34
- EffectScatterChart,
35
- LinesChart,
36
- HeatmapChart,
37
- PictorialBarChart,
38
- ThemeRiverChart,
39
- SunburstChart,
40
- CustomChart,
41
- } from 'echarts/charts';
42
- import { useTheme } from '../../../hooks';
43
- import { ParentSize } from '@visx/responsive';
44
- import { EChartsOption } from 'echarts';
45
-
46
- // Register all components
47
- echarts.use([
48
- CanvasRenderer,
49
- TitleComponent,
50
- TooltipComponent,
51
- GridComponent,
52
- LegendComponent,
53
- ToolboxComponent,
54
- DataZoomComponent,
55
- VisualMapComponent,
56
- MarkLineComponent,
57
- MarkPointComponent,
58
- MarkAreaComponent,
59
- PolarComponent,
60
- LineChart,
61
- BarChart,
62
- PieChart,
63
- ScatterChart,
64
- RadarChart,
65
- MapChart,
66
- TreeChart,
67
- TreemapChart,
68
- GraphChart,
69
- GaugeChart,
70
- FunnelChart,
71
- ParallelChart,
72
- SankeyChart,
73
- BoxplotChart,
74
- CandlestickChart,
75
- EffectScatterChart,
76
- LinesChart,
77
- HeatmapChart,
78
- PictorialBarChart,
79
- ThemeRiverChart,
80
- SunburstChart,
81
- CustomChart,
82
- ]);
83
-
84
- export interface EChartsBaseProps {
85
- option: EChartsOption;
86
- height?: string | number;
87
- width?: string | number;
88
- loading?: boolean;
89
- onChartReady?: (instance: any) => void;
90
- onEvents?: Record<string, (params: any) => void>;
91
- style?: React.CSSProperties;
92
- className?: string;
93
- }
94
-
95
- export const EChartsBase: FC<EChartsBaseProps> = ({
96
- option,
97
- height = '100%',
98
- width = '100%',
99
- loading = false,
100
- onChartReady,
101
- onEvents,
102
- style,
103
- className,
104
- }) => {
105
- const theme = useTheme();
106
- const chartRef = useRef<ReactEChartsCore>(null);
107
-
108
- // Create theme-aware default options
109
- const themeOptions = useMemo(() => {
110
- return {
111
- backgroundColor: 'transparent',
112
- textStyle: {
113
- color: theme.colors.text,
114
- fontFamily: 'inherit',
115
- },
116
- title: {
117
- textStyle: {
118
- color: theme.colors.text,
119
- fontSize: 16,
120
- fontWeight: 'bold',
121
- },
122
- subtextStyle: {
123
- color: theme.colors.textAlt,
124
- fontSize: 12,
125
- },
126
- },
127
- legend: {
128
- textStyle: {
129
- color: theme.colors.text,
130
- },
131
- pageTextStyle: {
132
- color: theme.colors.text,
133
- },
134
- },
135
- tooltip: {
136
- backgroundColor: theme.colors.backgroundAlt,
137
- borderColor: theme.colors.backgroundAccent,
138
- borderWidth: 1,
139
- textStyle: {
140
- color: theme.colors.text,
141
- },
142
- },
143
- grid: {
144
- left: '3%',
145
- right: '4%',
146
- bottom: '3%',
147
- containLabel: true,
148
- },
149
- xAxis: {
150
- axisLine: {
151
- lineStyle: {
152
- color: theme.colors.backgroundAccent,
153
- },
154
- },
155
- axisTick: {
156
- lineStyle: {
157
- color: theme.colors.backgroundAccent,
158
- },
159
- },
160
- axisLabel: {
161
- color: theme.colors.textAlt,
162
- },
163
- splitLine: {
164
- lineStyle: {
165
- color: theme.colors.backgroundAccent,
166
- type: 'dashed',
167
- },
168
- },
169
- },
170
- yAxis: {
171
- axisLine: {
172
- lineStyle: {
173
- color: theme.colors.backgroundAccent,
174
- },
175
- },
176
- axisTick: {
177
- lineStyle: {
178
- color: theme.colors.backgroundAccent,
179
- },
180
- },
181
- axisLabel: {
182
- color: theme.colors.textAlt,
183
- },
184
- splitLine: {
185
- lineStyle: {
186
- color: theme.colors.backgroundAccent,
187
- type: 'dashed',
188
- },
189
- },
190
- },
191
- color: [
192
- theme.colors.primary,
193
- theme.colors.success,
194
- theme.colors.warning,
195
- theme.colors.error,
196
- theme.colors.info,
197
- '#8b5cf6',
198
- '#06b6d4',
199
- '#f59e0b',
200
- '#ec4899',
201
- '#10b981',
202
- ],
203
- };
204
- }, [theme]);
205
-
206
- // Merge theme options with provided options
207
- const mergedOptions = useMemo(() => {
208
- // Check if this is a chart type that doesn't use axes
209
- const hasNonCartesianChart =
210
- option.series &&
211
- Array.isArray(option.series) &&
212
- option.series.some((s: any) =>
213
- ['pie', 'radar', 'gauge', 'funnel', 'sankey', 'graph', 'tree', 'treemap', 'sunburst'].includes(s.type),
214
- );
215
-
216
- // Create adjusted theme options based on chart type
217
- const adjustedThemeOptions = hasNonCartesianChart
218
- ? {
219
- backgroundColor: themeOptions.backgroundColor,
220
- textStyle: themeOptions.textStyle,
221
- title: themeOptions.title,
222
- legend: themeOptions.legend,
223
- tooltip: themeOptions.tooltip,
224
- color: themeOptions.color,
225
- }
226
- : themeOptions;
227
-
228
- return echarts.util.merge(adjustedThemeOptions, option);
229
- }, [themeOptions, option]);
230
-
231
- // Handle resize
232
- useEffect(() => {
233
- const handleResize = () => {
234
- if (chartRef.current) {
235
- const instance = chartRef.current.getEchartsInstance();
236
- instance.resize();
237
- }
238
- };
239
-
240
- window.addEventListener('resize', handleResize);
241
- return () => window.removeEventListener('resize', handleResize);
242
- }, []);
243
-
244
- return (
245
- <ReactEChartsCore
246
- ref={chartRef}
247
- echarts={echarts}
248
- option={mergedOptions}
249
- style={{ height, width, ...style }}
250
- className={className}
251
- showLoading={loading}
252
- onChartReady={onChartReady}
253
- onEvents={onEvents}
254
- opts={{ renderer: 'canvas' }}
255
- notMerge={true}
256
- lazyUpdate={true}
257
- />
258
- );
259
- };
260
-
261
- // Wrapper with ParentSize for responsive sizing
262
- export const ResponsiveECharts: FC<Omit<EChartsBaseProps, 'width' | 'height'>> = (props) => {
263
- return <ParentSize>{({ width, height }) => <EChartsBase {...props} width={width} height={height} />}</ParentSize>;
264
- };
@@ -1,164 +0,0 @@
1
- import React from 'react';
2
- import { Meta, StoryFn } from '@storybook/react';
3
- import { EChartsFunnel, EChartsFunnelProps } from './EChartsFunnel';
4
- import { styled } from '../../../styled';
5
- import { Card } from '../../../components';
6
-
7
- export default {
8
- title: 'Charts/ECharts/Funnel',
9
- component: EChartsFunnel,
10
- args: {
11
- showLegend: true,
12
- showLabel: true,
13
- sort: 'descending',
14
- title: 'Funnel Chart',
15
- gap: 2,
16
- },
17
- } as Meta<EChartsFunnelProps>;
18
-
19
- const Wrapper = styled.div`
20
- height: 500px;
21
- width: 100%;
22
- `;
23
-
24
- interface FunnelData {
25
- stage: string;
26
- count: number;
27
- }
28
-
29
- // Generate sample funnel data
30
- function generateFunnelData(): FunnelData[] {
31
- return [
32
- { stage: 'Visits', count: 1000 },
33
- { stage: 'Registrations', count: 650 },
34
- { stage: 'First Purchase', count: 400 },
35
- { stage: 'Repeat Purchase', count: 250 },
36
- { stage: 'VIP Status', count: 100 },
37
- ];
38
- }
39
-
40
- export const Default: StoryFn<EChartsFunnelProps<FunnelData>> = (args) => {
41
- const data = generateFunnelData();
42
-
43
- return (
44
- <Wrapper>
45
- <EChartsFunnel<FunnelData>
46
- {...args}
47
- data={data}
48
- nameAccessor={(d) => d.stage}
49
- valueAccessor={(d) => d.count}
50
- seriesName="Conversion"
51
- />
52
- </Wrapper>
53
- );
54
- };
55
-
56
- export const PlayerConversion: StoryFn = () => {
57
- const conversionData = [
58
- { stage: 'New Players', count: 5000 },
59
- { stage: 'Tutorial Completed', count: 3500 },
60
- { stage: 'First Mission', count: 2800 },
61
- { stage: 'Level 10 Reached', count: 1800 },
62
- { stage: 'First Purchase', count: 900 },
63
- { stage: 'Regular Player', count: 450 },
64
- ];
65
-
66
- return (
67
- <Wrapper>
68
- <Card variant="outline">
69
- <Card.Title label="Player Conversion Funnel" />
70
- <Card.Body>
71
- <div style={{ height: '400px' }}>
72
- <EChartsFunnel
73
- data={conversionData}
74
- nameAccessor={(d) => d.stage}
75
- valueAccessor={(d) => d.count}
76
- seriesName="Players"
77
- showLegend={false}
78
- labelPosition="inside"
79
- tooltipFormatter={(params: any) => {
80
- return `${params.name}<br/>Players: ${params.value.toLocaleString()} (${params.percent}%)`;
81
- }}
82
- />
83
- </div>
84
- </Card.Body>
85
- </Card>
86
- </Wrapper>
87
- );
88
- };
89
-
90
- export const SalesProcess: StoryFn<EChartsFunnelProps<FunnelData>> = (args) => {
91
- const salesData = [
92
- { stage: 'Leads', count: 100 },
93
- { stage: 'Qualified', count: 80 },
94
- { stage: 'Proposal', count: 60 },
95
- { stage: 'Negotiation', count: 40 },
96
- { stage: 'Closed', count: 30 },
97
- ];
98
-
99
- return (
100
- <Wrapper>
101
- <EChartsFunnel<FunnelData>
102
- {...args}
103
- data={salesData}
104
- nameAccessor={(d) => d.stage}
105
- valueAccessor={(d) => d.count}
106
- seriesName="Sales"
107
- title="Sales Pipeline"
108
- subtitle="Q4 2024"
109
- labelPosition="right"
110
- />
111
- </Wrapper>
112
- );
113
- };
114
-
115
- export const AscendingFunnel: StoryFn<EChartsFunnelProps<FunnelData>> = (args) => {
116
- const growthData = [
117
- { stage: 'Bronze', count: 30 },
118
- { stage: 'Silver', count: 50 },
119
- { stage: 'Gold', count: 75 },
120
- { stage: 'Platinum', count: 90 },
121
- { stage: 'Diamond', count: 100 },
122
- ];
123
-
124
- return (
125
- <Wrapper>
126
- <EChartsFunnel<FunnelData>
127
- {...args}
128
- data={growthData}
129
- nameAccessor={(d) => d.stage}
130
- valueAccessor={(d) => d.count}
131
- seriesName="Tier Distribution"
132
- sort="ascending"
133
- title="Player Tier Progression"
134
- subtitle="Inverted funnel showing growth"
135
- gap={5}
136
- />
137
- </Wrapper>
138
- );
139
- };
140
-
141
- export const NoSort: StoryFn<EChartsFunnelProps<FunnelData>> = (args) => {
142
- const customData = [
143
- { stage: 'Start', count: 80 },
144
- { stage: 'Middle', count: 100 },
145
- { stage: 'Peak', count: 120 },
146
- { stage: 'Decline', count: 60 },
147
- { stage: 'End', count: 40 },
148
- ];
149
-
150
- return (
151
- <Wrapper>
152
- <EChartsFunnel<FunnelData>
153
- {...args}
154
- data={customData}
155
- nameAccessor={(d) => d.stage}
156
- valueAccessor={(d) => d.count}
157
- seriesName="Custom Flow"
158
- sort="none"
159
- title="Custom Process Flow"
160
- subtitle="Maintains data order"
161
- />
162
- </Wrapper>
163
- );
164
- };
@@ -1,114 +0,0 @@
1
- import { FC, useMemo } from 'react';
2
- import { EChartsOption } from 'echarts';
3
- import { ResponsiveECharts, EChartsBaseProps } from './EChartsBase';
4
-
5
- export interface EChartsFunnelProps<T = any> extends Omit<EChartsBaseProps, 'option'> {
6
- data: T[];
7
- nameAccessor: (d: T) => string;
8
- valueAccessor: (d: T) => number;
9
- seriesName?: string;
10
- showLegend?: boolean;
11
- showLabel?: boolean;
12
- title?: string;
13
- subtitle?: string;
14
- sort?: 'ascending' | 'descending' | 'none';
15
- gap?: number;
16
- tooltipFormatter?: (params: any) => string;
17
- labelPosition?: 'left' | 'right' | 'inside';
18
- }
19
-
20
- export const EChartsFunnel: FC<EChartsFunnelProps> = ({
21
- data,
22
- nameAccessor,
23
- valueAccessor,
24
- seriesName = 'Funnel',
25
- showLegend = true,
26
- showLabel = true,
27
- title,
28
- subtitle,
29
- sort = 'descending',
30
- gap = 2,
31
- tooltipFormatter,
32
- labelPosition = 'inside',
33
- ...chartProps
34
- }) => {
35
- const option: EChartsOption = useMemo(() => {
36
- const funnelData = data.map((d) => ({
37
- name: nameAccessor(d),
38
- value: valueAccessor(d),
39
- }));
40
-
41
- return {
42
- title: title
43
- ? {
44
- text: title,
45
- subtext: subtitle,
46
- left: 'center',
47
- }
48
- : undefined,
49
- legend: showLegend
50
- ? {
51
- orient: 'vertical',
52
- left: 'left',
53
- top: 'middle',
54
- }
55
- : undefined,
56
- tooltip: {
57
- trigger: 'item',
58
- formatter: tooltipFormatter || '{a} <br/>{b}: {c} ({d}%)',
59
- },
60
- series: [
61
- {
62
- name: seriesName,
63
- type: 'funnel',
64
- left: '10%',
65
- top: 60,
66
- bottom: 60,
67
- width: '80%',
68
- min: 0,
69
- max: 100,
70
- minSize: '0%',
71
- maxSize: '100%',
72
- sort: sort,
73
- gap: gap,
74
- label: {
75
- show: showLabel,
76
- position: labelPosition,
77
- formatter: '{b}: {c}',
78
- },
79
- labelLine: {
80
- length: 10,
81
- lineStyle: {
82
- width: 1,
83
- type: 'solid',
84
- },
85
- },
86
- itemStyle: {
87
- borderWidth: 0,
88
- },
89
- emphasis: {
90
- label: {
91
- fontSize: 20,
92
- },
93
- },
94
- data: funnelData,
95
- },
96
- ],
97
- };
98
- }, [
99
- data,
100
- nameAccessor,
101
- valueAccessor,
102
- seriesName,
103
- showLegend,
104
- showLabel,
105
- title,
106
- subtitle,
107
- sort,
108
- gap,
109
- tooltipFormatter,
110
- labelPosition,
111
- ]);
112
-
113
- return <ResponsiveECharts option={option} {...chartProps} />;
114
- };
@@ -1,168 +0,0 @@
1
- import React from 'react';
2
- import { Meta, StoryFn } from '@storybook/react';
3
- import { EChartsHeatmap, EChartsHeatmapProps } from './EChartsHeatmap';
4
- import { styled } from '../../../styled';
5
- import { Card } from '../../../components';
6
- import { faker } from '@faker-js/faker';
7
-
8
- export default {
9
- title: 'Charts/ECharts/Heatmap',
10
- component: EChartsHeatmap,
11
- args: {
12
- title: 'Heatmap Example',
13
- xAxisLabel: 'Hour',
14
- yAxisLabel: 'Day',
15
- showLabel: false,
16
- },
17
- } as Meta<EChartsHeatmapProps>;
18
-
19
- const Wrapper = styled.div`
20
- height: 500px;
21
- width: 100%;
22
- `;
23
-
24
- interface HeatmapData {
25
- hour: number;
26
- day: number;
27
- value: number;
28
- }
29
-
30
- // Generate sample heatmap data
31
- function generateHeatmapData(): HeatmapData[] {
32
- const data: HeatmapData[] = [];
33
- const days = 7;
34
- const hours = 24;
35
-
36
- for (let day = 0; day < days; day++) {
37
- for (let hour = 0; hour < hours; hour++) {
38
- // Simulate peak hours (lunch and evening)
39
- let baseValue = 10;
40
- if (hour >= 11 && hour <= 13) baseValue = 40; // Lunch peak
41
- if (hour >= 18 && hour <= 21) baseValue = 60; // Evening peak
42
- if (hour >= 0 && hour <= 6) baseValue = 2; // Night low
43
-
44
- // Weekend bonus
45
- if (day === 5 || day === 6) baseValue *= 1.5;
46
-
47
- data.push({
48
- hour,
49
- day,
50
- value: baseValue + faker.number.int({ min: -5, max: 20 }),
51
- });
52
- }
53
- }
54
-
55
- return data;
56
- }
57
-
58
- const dayNames = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
59
- const hourLabels = Array.from({ length: 24 }, (_, i) =>
60
- i === 0 ? '12am' : i < 12 ? `${i}am` : i === 12 ? '12pm' : `${i - 12}pm`,
61
- );
62
-
63
- export const Default: StoryFn<EChartsHeatmapProps<HeatmapData>> = (args) => {
64
- const data = generateHeatmapData();
65
-
66
- return (
67
- <Wrapper>
68
- <EChartsHeatmap<HeatmapData>
69
- {...args}
70
- data={data}
71
- xAccessor={(d) => d.hour}
72
- yAccessor={(d) => d.day}
73
- valueAccessor={(d) => d.value}
74
- xCategories={hourLabels}
75
- yCategories={dayNames}
76
- />
77
- </Wrapper>
78
- );
79
- };
80
-
81
- export const PeakSalesHeatmap: StoryFn = () => {
82
- const data = generateHeatmapData();
83
-
84
- return (
85
- <Wrapper>
86
- <Card variant="outline">
87
- <Card.Title label="Peak Sales Heatmap" />
88
- <Card.Body>
89
- <div style={{ height: '400px' }}>
90
- <EChartsHeatmap
91
- data={data}
92
- xAccessor={(d) => d.hour}
93
- yAccessor={(d) => d.day}
94
- valueAccessor={(d) => d.value}
95
- xCategories={hourLabels}
96
- yCategories={dayNames}
97
- xAxisLabel="Hour of Day"
98
- yAxisLabel="Day of Week"
99
- tooltipFormatter={(params: any) => {
100
- const value = params.value;
101
- return `${dayNames[value[1]]}, ${hourLabels[value[0]]}<br/>Sales: ${value[2]}`;
102
- }}
103
- />
104
- </div>
105
- </Card.Body>
106
- </Card>
107
- </Wrapper>
108
- );
109
- };
110
-
111
- export const PlayerActivityHeatmap: StoryFn<EChartsHeatmapProps<HeatmapData>> = (args) => {
112
- const data = generateHeatmapData().map((d) => ({
113
- ...d,
114
- value: d.value * 2, // Higher values for player activity
115
- }));
116
-
117
- return (
118
- <Wrapper>
119
- <EChartsHeatmap<HeatmapData>
120
- {...args}
121
- data={data}
122
- xAccessor={(d) => d.hour}
123
- yAccessor={(d) => d.day}
124
- valueAccessor={(d) => d.value}
125
- xCategories={hourLabels}
126
- yCategories={dayNames}
127
- title="Player Activity Patterns"
128
- subtitle="Average players online by hour and day"
129
- showLabel={false}
130
- minValue={0}
131
- maxValue={150}
132
- />
133
- </Wrapper>
134
- );
135
- };
136
-
137
- export const WithLabels: StoryFn<EChartsHeatmapProps<HeatmapData>> = (args) => {
138
- // Smaller dataset for label visibility
139
- const data: HeatmapData[] = [];
140
- for (let day = 0; day < 5; day++) {
141
- for (let hour = 0; hour < 12; hour++) {
142
- data.push({
143
- hour: hour * 2, // Every 2 hours
144
- day,
145
- value: faker.number.int({ min: 10, max: 100 }),
146
- });
147
- }
148
- }
149
-
150
- const sparseHours = hourLabels.filter((_, i) => i % 2 === 0);
151
- const weekdays = dayNames.slice(0, 5);
152
-
153
- return (
154
- <Wrapper>
155
- <EChartsHeatmap<HeatmapData>
156
- {...args}
157
- data={data}
158
- xAccessor={(d) => d.hour / 2}
159
- yAccessor={(d) => d.day}
160
- valueAccessor={(d) => d.value}
161
- xCategories={sparseHours}
162
- yCategories={weekdays}
163
- title="Resource Usage"
164
- showLabel={true}
165
- />
166
- </Wrapper>
167
- );
168
- };