@spteck/fluentui-react-charts 0.1.8

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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/dist/charts/BarChart/BarChart.d.ts +16 -0
  4. package/dist/charts/BarChart/index.d.ts +1 -0
  5. package/dist/charts/ComboChart/ComboChart.d.ts +16 -0
  6. package/dist/charts/ComboChart/index.d.ts +1 -0
  7. package/dist/charts/Doughnut/DoughnutChart.d.ts +14 -0
  8. package/dist/charts/Doughnut/index.d.ts +1 -0
  9. package/dist/charts/PieChart/PieChart.d.ts +14 -0
  10. package/dist/charts/PieChart/index.d.ts +1 -0
  11. package/dist/charts/areaChart/AreaChart.d.ts +15 -0
  12. package/dist/charts/areaChart/index.d.ts +1 -0
  13. package/dist/charts/barHorizontalChart/BarHotizontalChart.d.ts +15 -0
  14. package/dist/charts/barHorizontalChart/index.d.ts +1 -0
  15. package/dist/charts/bubbleChart/BubbleChart.d.ts +15 -0
  16. package/dist/charts/bubbleChart/index.d.ts +1 -0
  17. package/dist/charts/floatBarChart/FloatBarChart.d.ts +14 -0
  18. package/dist/charts/floatBarChart/index.d.ts +1 -0
  19. package/dist/charts/lineChart/LineChart.d.ts +14 -0
  20. package/dist/charts/lineChart/index.d.ts +1 -0
  21. package/dist/charts/polarChart/PolarChart.d.ts +14 -0
  22. package/dist/charts/polarChart/index.d.ts +1 -0
  23. package/dist/charts/radarChart/RadarChart.d.ts +14 -0
  24. package/dist/charts/radarChart/index.d.ts +1 -0
  25. package/dist/charts/scatterChart/ScatterChart.d.ts +14 -0
  26. package/dist/charts/scatterChart/index.d.ts +1 -0
  27. package/dist/charts/stackedLineChart/StackedLineChart.d.ts +14 -0
  28. package/dist/charts/stackedLineChart/index.d.ts +1 -0
  29. package/dist/charts/steamChart/SteamChart.d.ts +14 -0
  30. package/dist/charts/steamChart/index.d.ts +1 -0
  31. package/dist/components/DashBoard.d.ts +3 -0
  32. package/dist/components/RenderLegend/RenderLegend.d.ts +11 -0
  33. package/dist/components/RenderTooltip/RenderTooltip.d.ts +14 -0
  34. package/dist/components/buttonMenu/ButtonMenu.d.ts +3 -0
  35. package/dist/components/buttonMenu/IButtonMenuOption.d.ts +10 -0
  36. package/dist/components/buttonMenu/IButtonMenuProps.d.ts +37 -0
  37. package/dist/components/index.d.ts +15 -0
  38. package/dist/components/legendContainer/LegendContainer.d.ts +16 -0
  39. package/dist/components/legendeButton/LegendButton.d.ts +11 -0
  40. package/dist/components/renderSliceLegend/RenderSliceLegend.d.ts +9 -0
  41. package/dist/components/renderValueLegend/RenderValueLegend.d.ts +13 -0
  42. package/dist/components/stack/IStackProps.d.ts +76 -0
  43. package/dist/components/stack/Stack.d.ts +8 -0
  44. package/dist/components/themeProvider/ThemeProvider.d.ts +15 -0
  45. package/dist/constants/Constants.d.ts +1 -0
  46. package/dist/fluentui-react-charts.cjs.development.js +2916 -0
  47. package/dist/fluentui-react-charts.cjs.development.js.map +1 -0
  48. package/dist/fluentui-react-charts.cjs.production.min.js +2 -0
  49. package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -0
  50. package/dist/fluentui-react-charts.esm.js +2905 -0
  51. package/dist/fluentui-react-charts.esm.js.map +1 -0
  52. package/dist/graphGlobalStyles/useGraphGlobalStyles.d.ts +5 -0
  53. package/dist/hooks/index.d.ts +1 -0
  54. package/dist/hooks/useGraphUtils.d.ts +38 -0
  55. package/dist/hooks/useResponsiveLegend.d.ts +8 -0
  56. package/dist/index.d.ts +3 -0
  57. package/dist/index.js +8 -0
  58. package/dist/models/IChart.d.ts +25 -0
  59. package/dist/models/index.d.ts +1 -0
  60. package/package.json +66 -0
  61. package/src/assets/sample1.png +0 -0
  62. package/src/assets/sample2.png +0 -0
  63. package/src/assets/sample3.png +0 -0
  64. package/src/charts/BarChart/BarChart.tsx +227 -0
  65. package/src/charts/BarChart/README.MD +335 -0
  66. package/src/charts/BarChart/index.ts +1 -0
  67. package/src/charts/ComboChart/ComboChart.tsx +209 -0
  68. package/src/charts/ComboChart/README.MD +347 -0
  69. package/src/charts/ComboChart/index.ts +1 -0
  70. package/src/charts/Doughnut/DoughnutChart.tsx +152 -0
  71. package/src/charts/Doughnut/README.MD +296 -0
  72. package/src/charts/Doughnut/index.ts +1 -0
  73. package/src/charts/PieChart/PieChart.tsx +148 -0
  74. package/src/charts/PieChart/README.MD +315 -0
  75. package/src/charts/PieChart/index.ts +1 -0
  76. package/src/charts/areaChart/AreaChart.tsx +195 -0
  77. package/src/charts/areaChart/README.MD +236 -0
  78. package/src/charts/areaChart/index.ts +1 -0
  79. package/src/charts/barHorizontalChart/BarHotizontalChart.tsx +200 -0
  80. package/src/charts/barHorizontalChart/README.MD +278 -0
  81. package/src/charts/barHorizontalChart/index.ts +2 -0
  82. package/src/charts/bubbleChart/BubbleChart.tsx +184 -0
  83. package/src/charts/bubbleChart/README.MD +275 -0
  84. package/src/charts/bubbleChart/index.ts +1 -0
  85. package/src/charts/floatBarChart/FloatBarChart.tsx +178 -0
  86. package/src/charts/floatBarChart/README.MD +354 -0
  87. package/src/charts/floatBarChart/index.ts +1 -0
  88. package/src/charts/lineChart/LineChart.tsx +200 -0
  89. package/src/charts/lineChart/README.MD +354 -0
  90. package/src/charts/lineChart/index.ts +1 -0
  91. package/src/charts/polarChart/PolarChart.tsx +161 -0
  92. package/src/charts/polarChart/README.MD +336 -0
  93. package/src/charts/polarChart/index.ts +1 -0
  94. package/src/charts/radarChart/README.MD +388 -0
  95. package/src/charts/radarChart/RadarChart.tsx +173 -0
  96. package/src/charts/radarChart/index.ts +1 -0
  97. package/src/charts/scatterChart/README.MD +335 -0
  98. package/src/charts/scatterChart/ScatterChart.tsx +155 -0
  99. package/src/charts/scatterChart/index.ts +1 -0
  100. package/src/charts/stackedLineChart/README.MD +396 -0
  101. package/src/charts/stackedLineChart/StackedLineChart.tsx +188 -0
  102. package/src/charts/stackedLineChart/index.ts +1 -0
  103. package/src/charts/steamChart/README.MD +414 -0
  104. package/src/charts/steamChart/SteamChart.tsx +236 -0
  105. package/src/charts/steamChart/index.ts +1 -0
  106. package/src/components/DashBoard.tsx +409 -0
  107. package/src/components/RenderLegend/RenderLegend.tsx +40 -0
  108. package/src/components/RenderTooltip/RenderTooltip.tsx +111 -0
  109. package/src/components/buttonMenu/ButtonMenu.tsx +186 -0
  110. package/src/components/buttonMenu/IButtonMenuOption.ts +9 -0
  111. package/src/components/buttonMenu/IButtonMenuProps.tsx +40 -0
  112. package/src/components/index.ts +15 -0
  113. package/src/components/legendContainer/LegendContainer.tsx +118 -0
  114. package/src/components/legendeButton/LegendButton.tsx +57 -0
  115. package/src/components/renderSliceLegend/RenderSliceLegend.tsx +46 -0
  116. package/src/components/renderValueLegend/RenderValueLegend.tsx +43 -0
  117. package/src/components/stack/IStackProps.tsx +94 -0
  118. package/src/components/stack/Stack.tsx +103 -0
  119. package/src/components/themeProvider/ThemeProvider.tsx +48 -0
  120. package/src/constants/Constants.tsx +23 -0
  121. package/src/graphGlobalStyles/useGraphGlobalStyles.ts +28 -0
  122. package/src/hooks/index.ts +1 -0
  123. package/src/hooks/useGraphUtils.tsx +314 -0
  124. package/src/hooks/useResponsiveLegend.ts +35 -0
  125. package/src/index.tsx +4 -0
  126. package/src/models/IChart.ts +50 -0
  127. package/src/models/index.ts +1 -0
@@ -0,0 +1,335 @@
1
+ # ScatterChart Component
2
+
3
+ A versatile scatter chart component built with Chart.js and Fluent UI React. This component displays data as points on a two-dimensional coordinate system, making it perfect for visualizing correlations, distributions, and relationships between two continuous variables.
4
+
5
+ ## Features
6
+
7
+ - **Two-Dimensional Data Visualization**: Plot data points using X and Y coordinates
8
+ - **Multiple Series Support**: Compare multiple datasets with different colored point series
9
+ - **Interactive Legend**: Toggle series visibility with click interactions
10
+ - **Correlation Analysis**: Ideal for identifying patterns and relationships
11
+ - **Fluent UI Integration**: Seamless integration with Fluent UI themes and design system
12
+ - **Data Labels**: Optional display of values directly on data points
13
+ - **Responsive Design**: Automatically adapts to container dimensions
14
+ - **TypeScript Support**: Full TypeScript support with generic types
15
+ - **Custom Tooltips**: Rich tooltips showing detailed point information
16
+ - **Linear Scaling**: Automatic scaling for both X and Y axes
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install chart.js react-chartjs-2 chartjs-plugin-datalabels @fluentui/react-components
22
+ ```
23
+
24
+ ## Basic Usage
25
+
26
+ ```tsx
27
+ import React from 'react';
28
+ import { ScatterChart } from './components/scatterChart/ScatterChart';
29
+ import { webLightTheme } from '@fluentui/react-components';
30
+
31
+ interface SalesData {
32
+ adSpend: number;
33
+ revenue: number;
34
+ region: string;
35
+ }
36
+
37
+ const salesData: SalesData[] = [
38
+ { adSpend: 1000, revenue: 15000, region: 'North' },
39
+ { adSpend: 1500, revenue: 22000, region: 'North' },
40
+ { adSpend: 800, revenue: 12000, region: 'North' },
41
+ { adSpend: 2000, revenue: 28000, region: 'North' },
42
+ { adSpend: 1200, revenue: 18000, region: 'North' },
43
+ ];
44
+
45
+ function App() {
46
+ return (
47
+ <div style={{ width: '800px', height: '500px' }}>
48
+ <ScatterChart
49
+ data={[
50
+ { label: 'Sales Performance', data: salesData }
51
+ ]}
52
+ getX={(datum) => datum.adSpend}
53
+ getY={(datum) => datum.revenue}
54
+ title="Advertising Spend vs Revenue"
55
+ theme={webLightTheme}
56
+ />
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ## Props
63
+
64
+ ### ScatterChartProps<T>
65
+
66
+ | Prop | Type | Required | Default | Description |
67
+ |------|------|----------|---------|-------------|
68
+ | `data` | `{ label: string; data: T[] }[]` | Yes | - | Array of data series with labels and data points |
69
+ | `getX` | `(datum: T) => number` | Yes | - | Function to extract the X-axis value from each data point |
70
+ | `getY` | `(datum: T) => number` | Yes | - | Function to extract the Y-axis value from each data point |
71
+ | `title` | `string` | No | - | Chart title displayed at the top |
72
+ | `showDataLabels` | `boolean` | No | `false` | Whether to show data values on data points |
73
+ | `theme` | `Theme` | No | `webLightTheme` | Fluent UI theme object for styling |
74
+
75
+ ## Advanced Usage
76
+
77
+ ### Multi-Variable Analysis
78
+
79
+ ```tsx
80
+ interface ProductMetrics {
81
+ price: number;
82
+ quality: number;
83
+ customerSatisfaction: number;
84
+ marketShare: number;
85
+ category: string;
86
+ }
87
+
88
+ const productData: ProductMetrics[] = [
89
+ { price: 299, quality: 85, customerSatisfaction: 88, marketShare: 15, category: 'Electronics' },
90
+ { price: 149, quality: 78, customerSatisfaction: 82, marketShare: 22, category: 'Electronics' },
91
+ { price: 599, quality: 95, customerSatisfaction: 94, marketShare: 8, category: 'Electronics' },
92
+ { price: 899, quality: 92, customerSatisfaction: 90, marketShare: 5, category: 'Electronics' },
93
+ ];
94
+
95
+ <ScatterChart
96
+ data={[{ label: 'Product Analysis', data: productData }]}
97
+ getX={(datum) => datum.price}
98
+ getY={(datum) => datum.quality}
99
+ title="Price vs Quality Analysis"
100
+ showDataLabels={true}
101
+ theme={webLightTheme}
102
+ />
103
+ ```
104
+
105
+ ### Comparative Market Analysis
106
+
107
+ ```tsx
108
+ interface CompanyPerformance {
109
+ revenue: number;
110
+ profitMargin: number;
111
+ employees: number;
112
+ marketCap: number;
113
+ industry: string;
114
+ }
115
+
116
+ const techCompanies: CompanyPerformance[] = [
117
+ { revenue: 50000, profitMargin: 25, employees: 500, marketCap: 1000000, industry: 'Tech' },
118
+ { revenue: 75000, profitMargin: 18, employees: 750, marketCap: 1500000, industry: 'Tech' },
119
+ { revenue: 120000, profitMargin: 22, employees: 1200, marketCap: 2500000, industry: 'Tech' },
120
+ ];
121
+
122
+ const financeCompanies: CompanyPerformance[] = [
123
+ { revenue: 80000, profitMargin: 15, employees: 800, marketCap: 1800000, industry: 'Finance' },
124
+ { revenue: 95000, profitMargin: 12, employees: 950, marketCap: 2100000, industry: 'Finance' },
125
+ { revenue: 110000, profitMargin: 18, employees: 1100, marketCap: 2800000, industry: 'Finance' },
126
+ ];
127
+
128
+ <ScatterChart
129
+ data={[
130
+ { label: 'Technology Companies', data: techCompanies },
131
+ { label: 'Financial Companies', data: financeCompanies }
132
+ ]}
133
+ getX={(datum) => datum.revenue}
134
+ getY={(datum) => datum.profitMargin}
135
+ title="Revenue vs Profit Margin by Industry"
136
+ showDataLabels={true}
137
+ theme={webLightTheme}
138
+ />
139
+ ```
140
+
141
+ ### Performance vs Resource Analysis
142
+
143
+ ```tsx
144
+ interface TeamMetrics {
145
+ teamSize: number;
146
+ productivity: number;
147
+ satisfaction: number;
148
+ experience: number;
149
+ department: string;
150
+ }
151
+
152
+ const teamData: TeamMetrics[] = [
153
+ { teamSize: 8, productivity: 85, satisfaction: 88, experience: 3.2, department: 'Engineering' },
154
+ { teamSize: 12, productivity: 78, satisfaction: 82, experience: 2.8, department: 'Engineering' },
155
+ { teamSize: 6, productivity: 92, satisfaction: 90, experience: 4.1, department: 'Engineering' },
156
+ { teamSize: 15, productivity: 75, satisfaction: 79, experience: 2.5, department: 'Engineering' },
157
+ ];
158
+
159
+ <ScatterChart
160
+ data={[{ label: 'Engineering Teams', data: teamData }]}
161
+ getX={(datum) => datum.teamSize}
162
+ getY={(datum) => datum.productivity}
163
+ title="Team Size vs Productivity"
164
+ showDataLabels={true}
165
+ theme={webLightTheme}
166
+ />
167
+ ```
168
+
169
+ ### Risk vs Return Analysis
170
+
171
+ ```tsx
172
+ interface InvestmentOption {
173
+ risk: number; // Risk percentage
174
+ expectedReturn: number; // Expected return percentage
175
+ volatility: number; // Volatility measure
176
+ liquidity: number; // Liquidity score
177
+ assetClass: string;
178
+ }
179
+
180
+ const investments: InvestmentOption[] = [
181
+ { risk: 15, expectedReturn: 8, volatility: 12, liquidity: 95, assetClass: 'Bonds' },
182
+ { risk: 35, expectedReturn: 15, volatility: 25, liquidity: 88, assetClass: 'Stocks' },
183
+ { risk: 50, expectedReturn: 22, volatility: 40, liquidity: 70, assetClass: 'Growth Stocks' },
184
+ { risk: 25, expectedReturn: 12, volatility: 18, liquidity: 82, assetClass: 'Balanced Fund' },
185
+ ];
186
+
187
+ <ScatterChart
188
+ data={[{ label: 'Investment Options', data: investments }]}
189
+ getX={(datum) => datum.risk}
190
+ getY={(datum) => datum.expectedReturn}
191
+ title="Investment Risk vs Expected Return"
192
+ showDataLabels={true}
193
+ theme={webLightTheme}
194
+ />
195
+ ```
196
+
197
+ ## Data Structure
198
+
199
+ The component expects data in the following format:
200
+
201
+ ```tsx
202
+ interface ChartSeries<T> {
203
+ label: string; // Series name (appears in legend)
204
+ data: T[]; // Array of data points
205
+ }
206
+ ```
207
+
208
+ Each data point `T` should contain:
209
+
210
+ - An X-axis value (horizontal position) - number
211
+ - A Y-axis value (vertical position) - number
212
+
213
+ ## Coordinate System
214
+
215
+ ### X-Axis (Horizontal)
216
+
217
+ - Represents the independent variable
218
+ - Linear scale with automatic range detection
219
+ - Left-to-right increases in value
220
+
221
+ ### Y-Axis (Vertical)
222
+
223
+ - Represents the dependent variable
224
+ - Linear scale with automatic range detection
225
+ - Bottom-to-top increases in value
226
+
227
+ ## Use Cases
228
+
229
+ Scatter charts are particularly effective for:
230
+
231
+ ### Correlation Analysis
232
+
233
+ - **Sales Performance**: Marketing spend vs revenue
234
+ - **Quality Control**: Input variables vs output quality
235
+ - **Resource Optimization**: Input resources vs productivity
236
+
237
+ ### Market Research
238
+
239
+ - **Competitive Analysis**: Price vs quality positioning
240
+ - **Customer Segmentation**: Spend vs frequency analysis
241
+ - **Product Portfolio**: Performance vs investment analysis
242
+
243
+ ### Scientific Data
244
+
245
+ - **Experimental Results**: Variable relationships
246
+ - **Performance Metrics**: Multiple factor analysis
247
+ - **Trend Identification**: Pattern recognition in data
248
+
249
+ ### Financial Analysis
250
+
251
+ - **Risk Assessment**: Risk vs return portfolios
252
+ - **Performance Evaluation**: Benchmark comparisons
253
+ - **Market Analysis**: Valuation vs fundamentals
254
+
255
+ ## Interactive Features
256
+
257
+ ### Legend Controls
258
+
259
+ - Click legend items to show/hide data series
260
+ - Visual feedback on hover states
261
+ - At least one series must remain visible
262
+ - Colors automatically assigned from theme palette
263
+
264
+ ### Point Interactions
265
+
266
+ - Hover effects on data points
267
+ - Rich tooltips showing X and Y coordinates
268
+ - Smooth transitions and animations
269
+
270
+ ### Zoom and Pan
271
+
272
+ - Mouse wheel zoom functionality
273
+ - Pan by dragging (when enabled)
274
+ - Reset zoom controls
275
+
276
+ ## Styling and Theme Integration
277
+
278
+ The component uses Fluent UI theme tokens:
279
+
280
+ ```tsx
281
+ // Point styling
282
+ backgroundColor: Derived from theme palette
283
+ borderColor: Same as background color
284
+ pointRadius: 4
285
+ pointHoverRadius: 6
286
+
287
+ // Typography
288
+ fontFamily: theme.fontFamilyBase
289
+ fontSize: theme.fontSizeBase200
290
+ fontWeight: theme.fontWeightSemibold
291
+ color: theme.colorNeutralForeground1
292
+
293
+ // Grid and axes
294
+ labelColor: theme.colorNeutralForeground1
295
+ gridColor: theme.colorNeutralStroke2
296
+ ```
297
+
298
+ ## Performance Optimizations
299
+
300
+ The component includes several React optimizations:
301
+
302
+ ````tsx
303
+ // Memoized color calculations
304
+ const seriesColors = useMemo(() => {
305
+ return data.reduce((acc, series, idx) => {
306
+ const base = getFluentPalette(theme)[
307
+ idx % getFluentPalette(theme).length
308
+ ];
309
+ acc[series.label] = lightenColor(base, 0.3);
310
+ return acc;
311
+ }, {} as Record<string, string>);
312
+ }, [data, theme]);
313
+
314
+ // Memoized chart data transformation
315
+ const chartData = useMemo(() => {
316
+ return {
317
+ datasets: data
318
+ .filter(series => visibleSeries.includes(series.label))
319
+ .map(series => ({
320
+ label: series.label,
321
+ data: series.data.map(d => ({ x: getX(d), y: getY(d) })),
322
+ backgroundColor: seriesColors[series.label],
323
+ borderColor: seriesColors[series.label],
324
+ pointRadius: 4,
325
+ })),
326
+ };
327
+ }, [data, visibleSeries, getX, getY, seriesColors]);
328
+
329
+ // Memoized theme properties
330
+ const { fontFamily, fontSize, labelColor, gridColor } = useMemo(() => ({
331
+ fontFamily: theme.fontFamilyBase,
332
+ fontSize: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
333
+ labelColor: theme.colorNeutralForeground1,
334
+ gridColor: theme.colorNeutralStroke2,
335
+ }), [theme]);
@@ -0,0 +1,155 @@
1
+ import {
2
+ Chart as ChartJS,
3
+ ChartOptions,
4
+ Legend,
5
+ LinearScale,
6
+ PointElement,
7
+ Tooltip,
8
+ } from 'chart.js';
9
+ import React, { useMemo, useState } from 'react';
10
+ import { Theme, webLightTheme } from '@fluentui/react-components';
11
+
12
+ import ChartDataLabels from 'chartjs-plugin-datalabels';
13
+ import RenderLegend from '../../components/RenderLegend/RenderLegend';
14
+ import { Scatter } from 'react-chartjs-2';
15
+ import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
16
+ import { useGraphUtils } from '../../hooks/useGraphUtils';
17
+
18
+ ChartJS.register(ChartDataLabels);
19
+ ChartJS.register(LinearScale, PointElement, Tooltip, Legend);
20
+
21
+ export interface ScatterChartProps<T> {
22
+ data: { label: string; data: T[] }[];
23
+ getX: (datum: T) => number;
24
+ getY: (datum: T) => number;
25
+ title?: string;
26
+ showDataLabels?: boolean;
27
+ theme?: Theme;
28
+ }
29
+
30
+ export default function ScatterChart<T extends object>({
31
+ data,
32
+ getX,
33
+ getY,
34
+ title,
35
+ showDataLabels = false,
36
+ theme = webLightTheme,
37
+ }: ScatterChartProps<T>) {
38
+ const [visibleSeries, setVisibleSeries] = useState(() =>
39
+ data.map(s => s.label)
40
+ );
41
+ const styles = useGraphGlobalStyles();
42
+ const { getFluentPalette, lightenColor, createFluentTooltip } = useGraphUtils(
43
+ theme
44
+ );
45
+
46
+ const seriesColors = useMemo(() => {
47
+ return data.reduce((acc, series, idx) => {
48
+ const base = getFluentPalette(theme)[
49
+ idx % getFluentPalette(theme).length
50
+ ];
51
+ acc[series.label] = lightenColor(base, 0.3);
52
+ return acc;
53
+ }, {} as Record<string, string>);
54
+ }, [data, theme]);
55
+
56
+ const toggleSeries = React.useCallback((label: string) => {
57
+ setVisibleSeries(prev =>
58
+ prev.includes(label) ? prev.filter(l => l !== label) : [...prev, label]
59
+ );
60
+ }, []);
61
+
62
+ const chartData = useMemo(() => {
63
+ return {
64
+ datasets: data
65
+ .filter(series => visibleSeries.includes(series.label))
66
+ .map(series => ({
67
+ label: series.label,
68
+ data: series.data.map(d => ({ x: getX(d), y: getY(d) })),
69
+ backgroundColor: seriesColors[series.label],
70
+ borderColor: seriesColors[series.label],
71
+ pointRadius: 4,
72
+ })),
73
+ };
74
+ }, [data, visibleSeries, getX, getY, seriesColors]);
75
+
76
+ const { fontFamily, fontSize, labelColor, gridColor } = useMemo(() => ({
77
+ fontFamily: theme.fontFamilyBase,
78
+ fontSize: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
79
+ labelColor: theme.colorNeutralForeground1,
80
+ gridColor: theme.colorNeutralStroke2,
81
+ }), [theme]);
82
+
83
+ const options = useMemo<ChartOptions<'scatter'>>(() => ({
84
+ responsive: true,
85
+ maintainAspectRatio: false,
86
+ plugins: {
87
+ title: {
88
+ display: !!title,
89
+ text: title,
90
+ font: {
91
+ size: 14,
92
+ family: theme.fontFamilyBase,
93
+ weight: theme.fontWeightSemibold,
94
+ },
95
+ color: theme.colorNeutralForeground1,
96
+ padding: {
97
+ top: 20,
98
+ bottom: 20,
99
+ },
100
+ },
101
+ datalabels: {
102
+ display: showDataLabels,
103
+ color: theme.colorNeutralForeground1,
104
+ font: {
105
+ family: theme.fontFamilyBase,
106
+ size: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
107
+ },
108
+ },
109
+ legend: { display: false },
110
+ tooltip: createFluentTooltip<'scatter'>(theme),
111
+ },
112
+ scales: {
113
+ x: {
114
+ type: 'linear',
115
+ position: 'bottom',
116
+ ticks: {
117
+ color: labelColor,
118
+ font: { family: fontFamily, size: fontSize },
119
+ },
120
+ grid: { color: gridColor },
121
+ },
122
+ y: {
123
+ type: 'linear',
124
+ ticks: {
125
+ color: labelColor,
126
+ font: { family: fontFamily, size: fontSize },
127
+ },
128
+ grid: { color: gridColor },
129
+ },
130
+ },
131
+ }), [
132
+ theme,
133
+ title,
134
+ showDataLabels,
135
+ createFluentTooltip,
136
+ labelColor,
137
+ fontFamily,
138
+ fontSize,
139
+ gridColor,
140
+ ]);
141
+
142
+ return (
143
+ <div className={styles.chartWithLegend}>
144
+ <div className={styles.chartArea}>
145
+ <Scatter data={chartData} options={options} />
146
+ </div>
147
+ <RenderLegend
148
+ data={data}
149
+ visibleSeries={visibleSeries}
150
+ seriesColors={seriesColors}
151
+ toggleSeries={toggleSeries}
152
+ />
153
+ </div>
154
+ );
155
+ }
@@ -0,0 +1 @@
1
+ export * from './ScatterChart';