@shohojdhara/atomix 0.2.3 β†’ 0.2.5

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 (225) hide show
  1. package/README.md +19 -0
  2. package/dist/atomix.css +1703 -1544
  3. package/dist/atomix.min.css +4 -4
  4. package/dist/index.d.ts +1465 -963
  5. package/dist/index.esm.js +16289 -25908
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +15650 -21780
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/dist/themes/applemix.css +15008 -0
  12. package/dist/themes/applemix.min.css +72 -0
  13. package/dist/themes/boomdevs.css +1608 -1450
  14. package/dist/themes/boomdevs.min.css +5 -5
  15. package/dist/themes/esrar.css +1702 -1543
  16. package/dist/themes/esrar.min.css +4 -4
  17. package/dist/themes/flashtrade.css +15159 -0
  18. package/dist/themes/flashtrade.min.css +86 -0
  19. package/dist/themes/mashroom.css +1699 -1540
  20. package/dist/themes/mashroom.min.css +7 -7
  21. package/dist/themes/shaj-default.css +1693 -1534
  22. package/dist/themes/shaj-default.min.css +4 -4
  23. package/package.json +6 -17
  24. package/src/components/Accordion/Accordion.stories.tsx +662 -21
  25. package/src/components/Accordion/Accordion.tsx +21 -14
  26. package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +529 -1195
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +400 -0
  29. package/src/components/AtomixGlass/GlassFilter.tsx +156 -0
  30. package/src/components/AtomixGlass/README.md +124 -2
  31. package/src/components/AtomixGlass/atomixGLass.old.tsx +1266 -0
  32. package/src/components/AtomixGlass/glass-utils.ts +263 -0
  33. package/src/components/AtomixGlass/shader-utils.ts +792 -68
  34. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1250 -0
  35. package/src/components/AtomixGlass/stories/Examples.stories.tsx +5768 -0
  36. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1065 -0
  37. package/src/components/AtomixGlass/stories/Playground.stories.tsx +1129 -0
  38. package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +395 -0
  39. package/src/components/AtomixGlass/stories/shared-components.tsx +301 -0
  40. package/src/components/AtomixGlass/utils.ts +3 -3
  41. package/src/components/Avatar/Avatar.tsx +3 -0
  42. package/src/components/Avatar/AvatarGroup.tsx +2 -1
  43. package/src/components/Badge/Badge.stories.tsx +76 -55
  44. package/src/components/Badge/Badge.tsx +12 -14
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
  46. package/src/components/Button/Button.stories.tsx +501 -20
  47. package/src/components/Button/Button.tsx +5 -8
  48. package/src/components/Callout/Callout.stories.tsx +86 -35
  49. package/src/components/Callout/Callout.tsx +31 -9
  50. package/src/components/Card/Card.stories.tsx +565 -2
  51. package/src/components/Card/Card.tsx +15 -4
  52. package/src/components/Card/ElevationCard.tsx +2 -0
  53. package/src/components/Chart/AnimatedChart.tsx +179 -156
  54. package/src/components/Chart/AreaChart.tsx +123 -12
  55. package/src/components/Chart/BarChart.tsx +91 -100
  56. package/src/components/Chart/BaseChart.tsx +80 -0
  57. package/src/components/Chart/BubbleChart.tsx +114 -290
  58. package/src/components/Chart/CandlestickChart.tsx +282 -622
  59. package/src/components/Chart/Chart.stories.tsx +576 -179
  60. package/src/components/Chart/Chart.tsx +374 -75
  61. package/src/components/Chart/ChartRenderer.tsx +371 -220
  62. package/src/components/Chart/ChartToolbar.tsx +372 -61
  63. package/src/components/Chart/ChartTooltip.tsx +33 -18
  64. package/src/components/Chart/DonutChart.tsx +172 -254
  65. package/src/components/Chart/FunnelChart.tsx +169 -240
  66. package/src/components/Chart/GaugeChart.tsx +224 -392
  67. package/src/components/Chart/HeatmapChart.tsx +302 -440
  68. package/src/components/Chart/LineChart.tsx +148 -103
  69. package/src/components/Chart/MultiAxisChart.tsx +267 -395
  70. package/src/components/Chart/PieChart.tsx +114 -64
  71. package/src/components/Chart/RadarChart.tsx +202 -218
  72. package/src/components/Chart/ScatterChart.tsx +111 -97
  73. package/src/components/Chart/TreemapChart.tsx +147 -222
  74. package/src/components/Chart/WaterfallChart.tsx +253 -291
  75. package/src/components/Chart/index.ts +11 -9
  76. package/src/components/Chart/types.ts +85 -9
  77. package/src/components/Chart/utils.ts +66 -0
  78. package/src/components/ColorModeToggle/ColorModeToggle.tsx +6 -3
  79. package/src/components/Countdown/Countdown.tsx +4 -0
  80. package/src/components/DataTable/DataTable.tsx +2 -1
  81. package/src/components/DatePicker/DatePicker.stories.tsx +689 -12
  82. package/src/components/DatePicker/DatePicker.tsx +3 -9
  83. package/src/components/DatePicker/types.ts +5 -0
  84. package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
  85. package/src/components/Dropdown/Dropdown.tsx +26 -28
  86. package/src/components/EdgePanel/EdgePanel.stories.tsx +473 -2
  87. package/src/components/EdgePanel/EdgePanel.tsx +101 -13
  88. package/src/components/Footer/Footer.stories.tsx +187 -60
  89. package/src/components/Footer/Footer.test.tsx +134 -0
  90. package/src/components/Footer/Footer.tsx +133 -34
  91. package/src/components/Footer/FooterLink.tsx +1 -1
  92. package/src/components/Footer/FooterSection.tsx +53 -36
  93. package/src/components/Footer/FooterSocialLink.tsx +32 -29
  94. package/src/components/Footer/README.md +82 -3
  95. package/src/components/Footer/index.ts +1 -1
  96. package/src/components/Form/Checkbox.stories.tsx +13 -5
  97. package/src/components/Form/Checkbox.tsx +3 -6
  98. package/src/components/Form/Form.stories.tsx +10 -3
  99. package/src/components/Form/Form.tsx +2 -0
  100. package/src/components/Form/FormGroup.tsx +2 -1
  101. package/src/components/Form/Input.stories.tsx +12 -11
  102. package/src/components/Form/Input.tsx +97 -95
  103. package/src/components/Form/Radio.stories.tsx +22 -7
  104. package/src/components/Form/Radio.tsx +3 -6
  105. package/src/components/Form/Select.stories.tsx +21 -6
  106. package/src/components/Form/Select.tsx +3 -5
  107. package/src/components/Form/Textarea.stories.tsx +13 -11
  108. package/src/components/Form/Textarea.tsx +88 -86
  109. package/src/components/Hero/Hero.stories.tsx +2 -3
  110. package/src/components/Hero/Hero.tsx +5 -6
  111. package/src/components/Icon/Icon.tsx +12 -1
  112. package/src/components/List/List.tsx +2 -1
  113. package/src/components/List/ListGroup.tsx +2 -1
  114. package/src/components/Messages/Messages.stories.tsx +113 -0
  115. package/src/components/Messages/Messages.tsx +52 -9
  116. package/src/components/Modal/Modal.stories.tsx +48 -32
  117. package/src/components/Modal/Modal.tsx +19 -24
  118. package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
  119. package/src/components/Navigation/Menu/Menu.tsx +2 -2
  120. package/src/components/Navigation/Nav/Nav.stories.tsx +469 -0
  121. package/src/components/Navigation/Nav/Nav.tsx +22 -4
  122. package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
  123. package/src/components/Navigation/Navbar/Navbar.stories.tsx +413 -0
  124. package/src/components/Navigation/Navbar/Navbar.tsx +70 -29
  125. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +340 -0
  126. package/src/components/Navigation/SideMenu/SideMenu.tsx +29 -2
  127. package/src/components/Pagination/Pagination.stories.tsx +13 -6
  128. package/src/components/Pagination/Pagination.tsx +7 -6
  129. package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
  130. package/src/components/Popover/Popover.stories.tsx +32 -24
  131. package/src/components/Popover/Popover.tsx +4 -1
  132. package/src/components/ProductReview/ProductReview.tsx +8 -2
  133. package/src/components/Progress/Progress.tsx +19 -3
  134. package/src/components/Rating/Rating.stories.tsx +11 -6
  135. package/src/components/Rating/Rating.tsx +3 -5
  136. package/src/components/River/River.tsx +5 -5
  137. package/src/components/SectionIntro/SectionIntro.tsx +8 -2
  138. package/src/components/Slider/Slider.stories.tsx +4 -4
  139. package/src/components/Slider/Slider.tsx +4 -3
  140. package/src/components/Spinner/Spinner.tsx +19 -3
  141. package/src/components/Steps/Steps.stories.tsx +5 -4
  142. package/src/components/Steps/Steps.tsx +8 -5
  143. package/src/components/Tab/Tab.stories.tsx +4 -3
  144. package/src/components/Tab/Tab.tsx +8 -6
  145. package/src/components/Testimonial/Testimonial.tsx +8 -2
  146. package/src/components/Todo/Todo.tsx +2 -1
  147. package/src/components/Toggle/Toggle.stories.tsx +5 -4
  148. package/src/components/Toggle/Toggle.tsx +8 -5
  149. package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
  150. package/src/components/Tooltip/Tooltip.tsx +9 -2
  151. package/src/components/Upload/Upload.stories.tsx +252 -0
  152. package/src/components/Upload/Upload.tsx +92 -53
  153. package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
  154. package/src/components/index.ts +0 -4
  155. package/src/layouts/Grid/Grid.stories.tsx +10 -23
  156. package/src/layouts/Grid/Grid.tsx +20 -1
  157. package/src/layouts/Grid/GridCol.tsx +76 -48
  158. package/src/lib/composables/useAtomixGlass.ts +861 -44
  159. package/src/lib/composables/useBarChart.ts +21 -4
  160. package/src/lib/composables/useChart.ts +227 -370
  161. package/src/lib/composables/useChartExport.ts +19 -78
  162. package/src/lib/composables/useChartToolbar.ts +11 -21
  163. package/src/lib/composables/useEdgePanel.ts +125 -71
  164. package/src/lib/composables/useFooter.ts +3 -3
  165. package/src/lib/composables/useGlassContainer.ts +16 -7
  166. package/src/lib/composables/useLineChart.ts +11 -2
  167. package/src/lib/composables/usePieChart.ts +4 -14
  168. package/src/lib/composables/useRiver.ts +5 -0
  169. package/src/lib/composables/useSlider.ts +62 -24
  170. package/src/lib/composables/useVideoPlayer.ts +60 -63
  171. package/src/lib/constants/components.ts +147 -32
  172. package/src/lib/types/components.ts +355 -25
  173. package/src/lib/utils/displacement-generator.ts +55 -49
  174. package/src/lib/utils/icons.ts +1 -1
  175. package/src/lib/utils/index.ts +16 -10
  176. package/src/styles/01-settings/_settings.accordion.scss +19 -19
  177. package/src/styles/01-settings/_settings.animations.scss +5 -5
  178. package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
  179. package/src/styles/01-settings/_settings.avatar.scss +17 -17
  180. package/src/styles/01-settings/_settings.background.scss +0 -3
  181. package/src/styles/01-settings/_settings.badge.scss +1 -1
  182. package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
  183. package/src/styles/01-settings/_settings.card.scss +1 -1
  184. package/src/styles/01-settings/_settings.chart.scss +65 -2
  185. package/src/styles/01-settings/_settings.dropdown.scss +1 -1
  186. package/src/styles/01-settings/_settings.edge-panel.scss +1 -1
  187. package/src/styles/01-settings/_settings.footer.scss +35 -42
  188. package/src/styles/01-settings/_settings.input.scss +1 -1
  189. package/src/styles/01-settings/_settings.list.scss +1 -1
  190. package/src/styles/01-settings/_settings.rating.scss +1 -1
  191. package/src/styles/01-settings/_settings.tabs.scss +1 -1
  192. package/src/styles/01-settings/_settings.upload.scss +6 -5
  193. package/src/styles/02-tools/_tools.animations.scss +4 -5
  194. package/src/styles/02-tools/_tools.background.scss +1 -13
  195. package/src/styles/02-tools/_tools.glass.scss +0 -1
  196. package/src/styles/02-tools/_tools.utility-api.scss +91 -48
  197. package/src/styles/03-generic/_generic.root.scss +1 -4
  198. package/src/styles/04-elements/_elements.body.scss +0 -1
  199. package/src/styles/06-components/_components.atomix-glass.scss +249 -0
  200. package/src/styles/06-components/_components.badge.scss +8 -23
  201. package/src/styles/06-components/_components.button.scss +8 -3
  202. package/src/styles/06-components/_components.callout.scss +10 -5
  203. package/src/styles/06-components/_components.card.scss +2 -14
  204. package/src/styles/06-components/_components.chart.scss +969 -1449
  205. package/src/styles/06-components/_components.dropdown.scss +19 -7
  206. package/src/styles/06-components/_components.edge-panel.scss +103 -0
  207. package/src/styles/06-components/_components.footer.scss +166 -85
  208. package/src/styles/06-components/_components.input.scss +8 -9
  209. package/src/styles/06-components/_components.list.scss +1 -0
  210. package/src/styles/06-components/_components.messages.scss +176 -0
  211. package/src/styles/06-components/_components.modal.scss +16 -4
  212. package/src/styles/06-components/_components.navbar.scss +12 -1
  213. package/src/styles/06-components/_components.side-menu.scss +5 -0
  214. package/src/styles/06-components/_components.skeleton.scss +8 -6
  215. package/src/styles/06-components/_components.upload.scss +219 -4
  216. package/src/styles/06-components/old.chart.styles.scss +1 -30
  217. package/src/styles/99-utilities/_index.scss +1 -0
  218. package/src/styles/99-utilities/_utilities.glass-fixes.scss +1 -0
  219. package/src/styles/99-utilities/_utilities.scss +1 -1
  220. package/src/components/AtomixGlass/AtomixGlass.stories.tsx +0 -3011
  221. package/src/components/AtomixGlass/AtomixGlassComprehensivePreview.stories.tsx +0 -1369
  222. package/src/components/Chart/AdvancedChart.tsx +0 -624
  223. package/src/components/Chart/LineChartNew.tsx +0 -167
  224. package/src/components/Chart/RealTimeChart.tsx +0 -436
  225. package/src/components/DatePicker/DatePicker copy.tsx +0 -551
@@ -1,167 +0,0 @@
1
- import { forwardRef, memo, useState } from 'react';
2
- import { useChartData } from '../../lib/composables/useChartData';
3
- import { useChartInteraction } from '../../lib/composables/useChartInteraction';
4
- import { useChartScale } from '../../lib/composables/useChartScale';
5
- import Chart from './Chart';
6
- import ChartTooltip from './ChartTooltip';
7
- import { ChartDataPoint, ChartProps } from './types';
8
-
9
- interface LineChartProps extends Omit<ChartProps, 'type'> {
10
- /**
11
- * Whether to show area fill
12
- */
13
- showArea?: boolean;
14
- /**
15
- * Whether to show data points
16
- */
17
- showPoints?: boolean;
18
- /**
19
- * Whether to use smooth curves
20
- */
21
- smooth?: boolean;
22
- }
23
-
24
- /**
25
- * Simplified LineChart component
26
- */
27
- const LineChart = memo(
28
- forwardRef<HTMLDivElement, LineChartProps>(
29
- (
30
- {
31
- datasets,
32
- showArea = false,
33
- showPoints = true,
34
- smooth = false,
35
- onDataPointClick,
36
- interactive = true,
37
- ...props
38
- },
39
- ref
40
- ) => {
41
- const chartData = datasets?.[0]?.data || [];
42
- const { data: processedData, stats } = useChartData(chartData);
43
- const { interaction, handlePointHover, handlePointClick } = useChartInteraction();
44
- const [tooltipData, setTooltipData] = useState<{
45
- point: ChartDataPoint;
46
- position: { x: number; y: number };
47
- } | null>(null);
48
-
49
- const scales = useChartScale(processedData, 800, 400);
50
-
51
- const generatePath = () => {
52
- if (!processedData.length) return '';
53
- return processedData
54
- .map((point, index) => {
55
- const x = scales.xScale(index);
56
- const y = scales.yScale(point.value);
57
- return `${index === 0 ? 'M' : 'L'} ${x},${y}`;
58
- })
59
- .join(' ');
60
- };
61
-
62
- const generateAreaPath = () => {
63
- if (!processedData.length) return '';
64
- const linePath = generatePath();
65
- const lastPoint = scales.xScale(processedData.length - 1);
66
- const firstPoint = scales.xScale(0);
67
- const baseline = scales.yScale(0);
68
-
69
- return `${linePath} L ${lastPoint},${baseline} L ${firstPoint},${baseline} Z`;
70
- };
71
-
72
- const renderChart = () => (
73
- <svg width="100%" height="100%" viewBox={`0 0 ${scales.width} ${scales.height}`}>
74
- {/* Grid lines */}
75
- <defs>
76
- <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
77
- <path
78
- d="M 20 0 L 0 0 0 20"
79
- fill="none"
80
- stroke="currentColor"
81
- strokeWidth="0.5"
82
- opacity="0.1"
83
- />
84
- </pattern>
85
- </defs>
86
- <rect width="100%" height="100%" fill="url(#grid)" />
87
-
88
- {/* Area fill */}
89
- {showArea && <path d={generateAreaPath()} className="c-chart__area-path" />}
90
-
91
- {/* Line path */}
92
- <path
93
- d={generatePath()}
94
- fill="none"
95
- stroke="var(--atomix-primary)"
96
- className="c-chart__line-path"
97
- />
98
-
99
- {/* Data points */}
100
- {showPoints &&
101
- processedData.map((point, index) => {
102
- const x = scales.xScale(index);
103
- const y = scales.yScale(point.value);
104
- const isHovered = interaction.hoveredIndex === index;
105
- const isSelected = interaction.selectedIndex === index;
106
-
107
- return (
108
- <circle
109
- key={index}
110
- cx={x}
111
- cy={y}
112
- r={isHovered || isSelected ? 6 : 4}
113
- fill={point.color || 'var(--atomix-primary)'}
114
- className="c-chart__data-point"
115
- style={{ cursor: interactive ? 'pointer' : 'default' }}
116
- onMouseEnter={e => {
117
- if (interactive) {
118
- handlePointHover(index);
119
- const rect = e.currentTarget.ownerSVGElement?.getBoundingClientRect();
120
- const clientX = rect ? rect.left + x : e.clientX;
121
- const clientY = rect ? rect.top + y : e.clientY;
122
- setTooltipData({ point, position: { x: clientX, y: clientY } });
123
- }
124
- }}
125
- onMouseLeave={() => {
126
- if (interactive) {
127
- handlePointHover(null);
128
- setTooltipData(null);
129
- }
130
- }}
131
- onClick={() => {
132
- if (interactive) {
133
- handlePointClick(index);
134
- onDataPointClick?.(point, 0, index);
135
- }
136
- }}
137
- />
138
- );
139
- })}
140
- </svg>
141
- );
142
-
143
- return (
144
- <Chart
145
- ref={ref}
146
- type="line"
147
- datasets={[{ label: 'Line Chart', data: chartData }]}
148
- {...props}
149
- >
150
- {renderChart()}
151
- {tooltipData && (
152
- <ChartTooltip
153
- dataPoint={tooltipData.point}
154
- datasetLabel="Line Chart"
155
- position={tooltipData.position}
156
- visible={true}
157
- />
158
- )}
159
- </Chart>
160
- );
161
- }
162
- )
163
- );
164
-
165
- LineChart.displayName = 'LineChart';
166
- export default LineChart;
167
- export type { LineChartProps };
@@ -1,436 +0,0 @@
1
- import { forwardRef, memo, useCallback, useEffect, useRef, useState } from 'react';
2
- import { ChartProps } from '../../lib/types/components';
3
- import Chart from './Chart';
4
- import ChartRenderer from './ChartRenderer';
5
-
6
- interface RealTimeChartProps extends Omit<ChartProps, 'type'> {
7
- /**
8
- * Data stream configuration
9
- */
10
- streamConfig?: {
11
- /**
12
- * Update interval in milliseconds
13
- */
14
- interval: number;
15
- /**
16
- * Maximum number of data points to keep
17
- */
18
- maxDataPoints: number;
19
- /**
20
- * Whether to auto-scroll to latest data
21
- */
22
- autoScroll: boolean;
23
- /**
24
- * Buffer size for smooth updates
25
- */
26
- bufferSize?: number;
27
- };
28
-
29
- /**
30
- * Data source function that returns new data points
31
- */
32
- dataSource?: () => Promise<{ label: string; value: number; timestamp?: number }[]>;
33
-
34
- /**
35
- * WebSocket URL for real-time data
36
- */
37
- websocketUrl?: string;
38
-
39
- /**
40
- * Callback when new data arrives
41
- */
42
- onDataUpdate?: (newData: any[]) => void;
43
-
44
- /**
45
- * Performance monitoring
46
- */
47
- enablePerformanceMonitoring?: boolean;
48
- }
49
-
50
- const RealTimeChart = memo(
51
- forwardRef<HTMLDivElement, RealTimeChartProps>(
52
- (
53
- {
54
- datasets = [],
55
- config = {},
56
- streamConfig = {
57
- interval: 1000,
58
- maxDataPoints: 100,
59
- autoScroll: true,
60
- bufferSize: 10,
61
- },
62
- dataSource,
63
- websocketUrl,
64
- onDataUpdate,
65
- enablePerformanceMonitoring = false,
66
- ...props
67
- },
68
- ref
69
- ) => {
70
- const [realTimeData, setRealTimeData] = useState(datasets);
71
- const [isStreaming, setIsStreaming] = useState(false);
72
- const [performanceMetrics, setPerformanceMetrics] = useState({
73
- fps: 0,
74
- updateTime: 0,
75
- dataPoints: 0,
76
- });
77
-
78
- const intervalRef = useRef<NodeJS.Timeout | null>(null);
79
- const websocketRef = useRef<WebSocket | null>(null);
80
- const frameCountRef = useRef(0);
81
- const lastFrameTimeRef = useRef(Date.now());
82
- const dataBufferRef = useRef<any[]>([]);
83
-
84
- // Performance monitoring
85
- const updatePerformanceMetrics = useCallback(() => {
86
- if (!enablePerformanceMonitoring) return;
87
-
88
- const now = Date.now();
89
- const deltaTime = now - lastFrameTimeRef.current;
90
-
91
- if (deltaTime >= 1000) {
92
- const fps = Math.round((frameCountRef.current * 1000) / deltaTime);
93
- setPerformanceMetrics(prev => ({
94
- ...prev,
95
- fps,
96
- dataPoints: realTimeData.reduce((sum, dataset) => sum + (dataset.data?.length || 0), 0),
97
- }));
98
-
99
- frameCountRef.current = 0;
100
- lastFrameTimeRef.current = now;
101
- }
102
-
103
- frameCountRef.current++;
104
- }, [enablePerformanceMonitoring, realTimeData]);
105
-
106
- // Data buffer management for smooth updates
107
- const processDataBuffer = useCallback(() => {
108
- if (dataBufferRef.current.length === 0) return;
109
-
110
- const startTime = performance.now();
111
-
112
- setRealTimeData(prevData => {
113
- const newData = [...prevData];
114
-
115
- // Process buffered data points
116
- dataBufferRef.current.forEach(newPoints => {
117
- newPoints.forEach((point: any, datasetIndex: number) => {
118
- if (!newData[datasetIndex]) {
119
- newData[datasetIndex] = {
120
- label: `Dataset ${datasetIndex + 1}`,
121
- data: [],
122
- color: `hsl(${datasetIndex * 60}, 70%, 50%)`,
123
- };
124
- }
125
-
126
- const dataset = newData[datasetIndex];
127
- const currentData = dataset.data || [];
128
-
129
- // Add new point with timestamp
130
- const newPoint = {
131
- ...point,
132
- timestamp: point.timestamp || Date.now(),
133
- };
134
-
135
- currentData.push(newPoint);
136
-
137
- // Maintain max data points
138
- if (currentData.length > streamConfig.maxDataPoints) {
139
- currentData.splice(0, currentData.length - streamConfig.maxDataPoints);
140
- }
141
-
142
- dataset.data = currentData;
143
- });
144
- });
145
-
146
- return newData;
147
- });
148
-
149
- // Clear buffer
150
- dataBufferRef.current = [];
151
-
152
- const endTime = performance.now();
153
- setPerformanceMetrics(prev => ({
154
- ...prev,
155
- updateTime: endTime - startTime,
156
- }));
157
-
158
- onDataUpdate?.(realTimeData);
159
- updatePerformanceMetrics();
160
- }, [streamConfig.maxDataPoints, onDataUpdate, realTimeData, updatePerformanceMetrics]);
161
-
162
- // WebSocket connection
163
- const connectWebSocket = useCallback(() => {
164
- if (!websocketUrl) return;
165
-
166
- try {
167
- websocketRef.current = new WebSocket(websocketUrl);
168
-
169
- websocketRef.current.onopen = () => {
170
- setIsStreaming(true);
171
- };
172
-
173
- websocketRef.current.onmessage = event => {
174
- try {
175
- const data = JSON.parse(event.data);
176
- dataBufferRef.current.push(Array.isArray(data) ? data : [data]);
177
- } catch (error) {
178
- console.error('Error parsing WebSocket data:', error);
179
- }
180
- };
181
-
182
- websocketRef.current.onclose = () => {
183
- setIsStreaming(false);
184
- };
185
-
186
- websocketRef.current.onerror = error => {
187
- console.error('WebSocket error:', error);
188
- setIsStreaming(false);
189
- };
190
- } catch (error) {
191
- console.error('Error connecting to WebSocket:', error);
192
- }
193
- }, [websocketUrl]);
194
-
195
- // Polling data source
196
- const startPolling = useCallback(() => {
197
- if (!dataSource) return;
198
-
199
- intervalRef.current = setInterval(async () => {
200
- try {
201
- const newData = await dataSource();
202
- if (newData && newData.length > 0) {
203
- dataBufferRef.current.push(newData);
204
- }
205
- } catch (error) {
206
- console.error('Error fetching data:', error);
207
- }
208
- }, streamConfig.interval);
209
-
210
- setIsStreaming(true);
211
- }, [dataSource, streamConfig.interval]);
212
-
213
- // Start streaming
214
- const startStreaming = useCallback(() => {
215
- if (websocketUrl) {
216
- connectWebSocket();
217
- } else if (dataSource) {
218
- startPolling();
219
- }
220
- }, [websocketUrl, dataSource, connectWebSocket, startPolling]);
221
-
222
- // Stop streaming
223
- const stopStreaming = useCallback(() => {
224
- setIsStreaming(false);
225
-
226
- if (intervalRef.current) {
227
- clearInterval(intervalRef.current);
228
- intervalRef.current = null;
229
- }
230
-
231
- if (websocketRef.current) {
232
- websocketRef.current.close();
233
- websocketRef.current = null;
234
- }
235
- }, []);
236
-
237
- // Process buffer at regular intervals
238
- useEffect(() => {
239
- const bufferInterval = setInterval(processDataBuffer, streamConfig.interval / 4);
240
- return () => clearInterval(bufferInterval);
241
- }, [processDataBuffer, streamConfig.interval]);
242
-
243
- // Auto-start streaming
244
- useEffect(() => {
245
- if (dataSource || websocketUrl) {
246
- startStreaming();
247
- }
248
-
249
- return () => {
250
- stopStreaming();
251
- };
252
- }, [dataSource, websocketUrl, startStreaming, stopStreaming]);
253
-
254
- // Render content with real-time optimizations
255
- const renderContent = useCallback(
256
- ({
257
- scales,
258
- colors,
259
- datasets: renderedDatasets,
260
- handlers,
261
- }: {
262
- scales: any;
263
- colors: any;
264
- datasets: any;
265
- handlers: any;
266
- }) => {
267
- if (!renderedDatasets.length) return null;
268
-
269
- return renderedDatasets.map((dataset: any, datasetIndex: number) => {
270
- const color = dataset.color || colors[datasetIndex];
271
- const points =
272
- dataset.data?.map((point: any, i: number) => ({
273
- x: scales.xScale(i, dataset.data?.length),
274
- y: scales.yScale(point.value),
275
- timestamp: point.timestamp,
276
- })) || [];
277
-
278
- // Generate path with performance optimization
279
- const path =
280
- points.length > 1 ? `M ${points.map((p: any) => `${p.x},${p.y}`).join(' L ')}` : '';
281
-
282
- return (
283
- <g key={`realtime-dataset-${datasetIndex}`}>
284
- {/* Animated line with gradient */}
285
- <defs>
286
- <linearGradient id={`gradient-${datasetIndex}`} x1="0%" y1="0%" x2="100%" y2="0%">
287
- <stop offset="0%" stopColor={color} stopOpacity="0.1" />
288
- <stop offset="100%" stopColor={color} stopOpacity="0.8" />
289
- </linearGradient>
290
- </defs>
291
-
292
- {/* Main line */}
293
- <path
294
- d={path}
295
- stroke={`url(#gradient-${datasetIndex})`}
296
- fill="none"
297
- strokeWidth="2"
298
- strokeLinecap="round"
299
- strokeLinejoin="round"
300
- />
301
-
302
- {/* Data points with pulse animation for latest */}
303
- {dataset.data?.map((point: any, i: number) => {
304
- const x = scales.xScale(i, dataset.data?.length);
305
- const y = scales.yScale(point.value);
306
- const isLatest = i === (dataset.data?.length || 0) - 1;
307
-
308
- return (
309
- <g key={`point-${i}`}>
310
- {isLatest && (
311
- <circle cx={x} cy={y} r="8" fill={color} opacity="0.3">
312
- <animate
313
- attributeName="r"
314
- values="4;12;4"
315
- dur="2s"
316
- repeatCount="indefinite"
317
- />
318
- <animate
319
- attributeName="opacity"
320
- values="0.8;0.1;0.8"
321
- dur="2s"
322
- repeatCount="indefinite"
323
- />
324
- </circle>
325
- )}
326
- <circle
327
- cx={x}
328
- cy={y}
329
- r="3"
330
- fill={color}
331
- stroke="white"
332
- strokeWidth="1"
333
- onClick={() => handlers.onDataPointClick?.(point, datasetIndex, i)}
334
- style={{ cursor: 'pointer' }}
335
- />
336
- </g>
337
- );
338
- })}
339
- </g>
340
- );
341
- });
342
- },
343
- []
344
- );
345
-
346
- return (
347
- <Chart
348
- ref={ref}
349
- type="line"
350
- datasets={realTimeData}
351
- config={config}
352
- title={`Real-time Chart ${isStreaming ? 'πŸ”΄ LIVE' : '⏸️ PAUSED'}`}
353
- showToolbar
354
- enableRefresh
355
- onRefresh={startStreaming}
356
- {...props}
357
- >
358
- <ChartRenderer
359
- datasets={realTimeData}
360
- config={config}
361
- renderContent={renderContent}
362
- enableRealTime
363
- enablePerformanceOptimization
364
- />
365
-
366
- {/* Performance overlay */}
367
- {enablePerformanceMonitoring && (
368
- <div
369
- style={{
370
- position: 'absolute',
371
- top: '10px',
372
- right: '10px',
373
- background: 'rgba(0, 0, 0, 0.8)',
374
- color: 'white',
375
- padding: '8px',
376
- borderRadius: '4px',
377
- fontSize: '12px',
378
- fontFamily: 'monospace',
379
- }}
380
- >
381
- <div>FPS: {performanceMetrics.fps}</div>
382
- <div>Update: {performanceMetrics.updateTime.toFixed(2)}ms</div>
383
- <div>Points: {performanceMetrics.dataPoints}</div>
384
- <div>Status: {isStreaming ? 'STREAMING' : 'STOPPED'}</div>
385
- </div>
386
- )}
387
-
388
- {/* Streaming controls */}
389
- <div
390
- style={{
391
- position: 'absolute',
392
- bottom: '10px',
393
- left: '10px',
394
- display: 'flex',
395
- gap: '8px',
396
- }}
397
- >
398
- <button
399
- onClick={isStreaming ? stopStreaming : startStreaming}
400
- style={{
401
- padding: '6px 12px',
402
- borderRadius: '4px',
403
- border: 'none',
404
- background: isStreaming ? '#ef4444' : '#10b981',
405
- color: 'white',
406
- cursor: 'pointer',
407
- fontSize: '12px',
408
- }}
409
- >
410
- {isStreaming ? 'Stop' : 'Start'}
411
- </button>
412
-
413
- <button
414
- onClick={() => setRealTimeData([])}
415
- style={{
416
- padding: '6px 12px',
417
- borderRadius: '4px',
418
- border: 'none',
419
- background: '#6b7280',
420
- color: 'white',
421
- cursor: 'pointer',
422
- fontSize: '12px',
423
- }}
424
- >
425
- Clear
426
- </button>
427
- </div>
428
- </Chart>
429
- );
430
- }
431
- )
432
- );
433
-
434
- RealTimeChart.displayName = 'RealTimeChart';
435
- export default RealTimeChart;
436
- export type { RealTimeChartProps };