@spteck/fluentui-react-charts 1.0.7 → 1.0.9
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.
- package/dist/charts/BarChart/BarChart.d.ts +2 -1
- package/dist/charts/ComboChart/ComboChart.d.ts +2 -1
- package/dist/charts/Doughnut/DoughnutChart.d.ts +2 -1
- package/dist/charts/PieChart/PieChart.d.ts +2 -1
- package/dist/charts/areaChart/AreaChart.d.ts +2 -1
- package/dist/charts/barHorizontalChart/BarHotizontalChart.d.ts +2 -1
- package/dist/charts/bubbleChart/BubbleChart.d.ts +2 -1
- package/dist/charts/floatBarChart/FloatBarChart.d.ts +2 -1
- package/dist/charts/index.d.ts +14 -0
- package/dist/charts/lineChart/LineChart.d.ts +2 -1
- package/dist/charts/polarChart/PolarChart.d.ts +2 -1
- package/dist/charts/radarChart/RadarChart.d.ts +2 -1
- package/dist/charts/scatterChart/ScatterChart.d.ts +2 -1
- package/dist/charts/stackedLineChart/StackedLineChart.d.ts +2 -1
- package/dist/charts/steamChart/SteamChart.d.ts +2 -1
- package/dist/components/index.d.ts +0 -14
- package/dist/fluentui-react-charts.cjs.development.js +1086 -1072
- package/dist/fluentui-react-charts.cjs.development.js.map +1 -1
- package/dist/fluentui-react-charts.cjs.production.min.js +1 -1
- package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -1
- package/dist/fluentui-react-charts.esm.js +1074 -1074
- package/dist/fluentui-react-charts.esm.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +5 -5
- package/src/assets/sample1.png +0 -0
- package/src/assets/sample2.png +0 -0
- package/src/assets/sample3.png +0 -0
- package/src/charts/BarChart/BarChart.tsx +0 -227
- package/src/charts/BarChart/README.MD +0 -335
- package/src/charts/BarChart/index.ts +0 -1
- package/src/charts/ComboChart/ComboChart.tsx +0 -209
- package/src/charts/ComboChart/README.MD +0 -347
- package/src/charts/ComboChart/index.ts +0 -1
- package/src/charts/Doughnut/DoughnutChart.tsx +0 -152
- package/src/charts/Doughnut/README.MD +0 -296
- package/src/charts/Doughnut/index.ts +0 -1
- package/src/charts/PieChart/PieChart.tsx +0 -148
- package/src/charts/PieChart/README.MD +0 -315
- package/src/charts/PieChart/index.ts +0 -1
- package/src/charts/areaChart/AreaChart.tsx +0 -195
- package/src/charts/areaChart/README.MD +0 -236
- package/src/charts/areaChart/index.ts +0 -1
- package/src/charts/barHorizontalChart/BarHotizontalChart.tsx +0 -200
- package/src/charts/barHorizontalChart/README.MD +0 -278
- package/src/charts/barHorizontalChart/index.ts +0 -2
- package/src/charts/bubbleChart/BubbleChart.tsx +0 -184
- package/src/charts/bubbleChart/README.MD +0 -275
- package/src/charts/bubbleChart/index.ts +0 -1
- package/src/charts/floatBarChart/FloatBarChart.tsx +0 -178
- package/src/charts/floatBarChart/README.MD +0 -354
- package/src/charts/floatBarChart/index.ts +0 -1
- package/src/charts/lineChart/LineChart.tsx +0 -200
- package/src/charts/lineChart/README.MD +0 -354
- package/src/charts/lineChart/index.ts +0 -1
- package/src/charts/polarChart/PolarChart.tsx +0 -161
- package/src/charts/polarChart/README.MD +0 -336
- package/src/charts/polarChart/index.ts +0 -1
- package/src/charts/radarChart/README.MD +0 -388
- package/src/charts/radarChart/RadarChart.tsx +0 -173
- package/src/charts/radarChart/index.ts +0 -1
- package/src/charts/scatterChart/README.MD +0 -335
- package/src/charts/scatterChart/ScatterChart.tsx +0 -155
- package/src/charts/scatterChart/index.ts +0 -1
- package/src/charts/stackedLineChart/README.MD +0 -396
- package/src/charts/stackedLineChart/StackedLineChart.tsx +0 -188
- package/src/charts/stackedLineChart/index.ts +0 -1
- package/src/charts/steamChart/README.MD +0 -414
- package/src/charts/steamChart/SteamChart.tsx +0 -236
- package/src/charts/steamChart/index.ts +0 -1
- package/src/components/RenderLabel/RenderLabel.tsx +0 -39
- package/src/components/RenderLabel/index.ts +0 -2
- package/src/components/RenderLabel/useRenderLabelStylesStyles.ts +0 -25
- package/src/components/RenderLegend/RenderLegend.tsx +0 -40
- package/src/components/RenderTooltip/RenderTooltip.tsx +0 -111
- package/src/components/buttonMenu/ButtonMenu.tsx +0 -186
- package/src/components/buttonMenu/IButtonMenuOption.ts +0 -9
- package/src/components/buttonMenu/IButtonMenuProps.tsx +0 -40
- package/src/components/dashboard/DashBoard.tsx +0 -314
- package/src/components/dashboard/ExampleDashboardUsage.tsx +0 -114
- package/src/components/dashboard/IDashboardProps.tsx +0 -11
- package/src/components/dashboard/NoDashboards.tsx +0 -26
- package/src/components/dashboard/index.ts +0 -3
- package/src/components/dashboard/selectZoom/SelectZoom.tsx +0 -184
- package/src/components/dashboard/useDashboardStyles.ts +0 -76
- package/src/components/index.ts +0 -17
- package/src/components/legendContainer/LegendContainer.tsx +0 -118
- package/src/components/legendeButton/LegendButton.tsx +0 -57
- package/src/components/renderSliceLegend/RenderSliceLegend.tsx +0 -46
- package/src/components/renderValueLegend/RenderValueLegend.tsx +0 -43
- package/src/components/stack/IStackProps.tsx +0 -94
- package/src/components/stack/Stack.tsx +0 -103
- package/src/components/svgImages/BusinessReportIcon.tsx +0 -218
- package/src/components/themeProvider/ThemeProvider.tsx +0 -48
- package/src/constants/Constants.tsx +0 -23
- package/src/graphGlobalStyles/useGraphGlobalStyles.ts +0 -28
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useChartFactory.tsx +0 -136
- package/src/hooks/useChartUtils.tsx +0 -187
- package/src/hooks/useIndexedDBCache.ts +0 -119
- package/src/hooks/useResponsiveLegend.ts +0 -35
- package/src/index.tsx +0 -5
- package/src/models/ChartDatum.ts +0 -4
- package/src/models/ICardChartContainer.tsx +0 -11
- package/src/models/IChart.ts +0 -50
- package/src/models/index.ts +0 -3
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
# LineChart Component
|
|
2
|
-
|
|
3
|
-
A versatile line chart component built with Chart.js and Fluent UI React. This component displays data as connected points with smooth lines, making it ideal for visualizing trends, time series data, and continuous data changes over categories or time periods.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Trend Visualization**: Display data trends with smooth, connected lines
|
|
8
|
-
- **Multiple Series Support**: Compare multiple data series with different colored lines
|
|
9
|
-
- **Interactive Legend**: Toggle series visibility with click interactions
|
|
10
|
-
- **Smooth Curves**: Configurable line tension for smooth or angular connections
|
|
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
|
-
- **Missing Data Handling**: Graceful handling of null/missing data points
|
|
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 { LineChart } from './components/lineChart/LineChart';
|
|
29
|
-
import { webLightTheme } from '@fluentui/react-components';
|
|
30
|
-
|
|
31
|
-
interface SalesData {
|
|
32
|
-
month: string;
|
|
33
|
-
revenue: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const salesData: SalesData[] = [
|
|
37
|
-
{ month: 'Jan', revenue: 150000 },
|
|
38
|
-
{ month: 'Feb', revenue: 180000 },
|
|
39
|
-
{ month: 'Mar', revenue: 165000 },
|
|
40
|
-
{ month: 'Apr', revenue: 200000 },
|
|
41
|
-
{ month: 'May', revenue: 220000 },
|
|
42
|
-
{ month: 'Jun', revenue: 195000 },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
function App() {
|
|
46
|
-
return (
|
|
47
|
-
<div style={{ width: '800px', height: '400px' }}>
|
|
48
|
-
<LineChart
|
|
49
|
-
data={[
|
|
50
|
-
{ label: 'Monthly Revenue', data: salesData }
|
|
51
|
-
]}
|
|
52
|
-
getPrimary={(datum) => datum.month}
|
|
53
|
-
getSecondary={(datum) => datum.revenue}
|
|
54
|
-
title="Revenue Trend Over Time"
|
|
55
|
-
theme={webLightTheme}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Props
|
|
63
|
-
|
|
64
|
-
### LineChartProps<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
|
-
| `getPrimary` | `(datum: T) => string \| number` | Yes | - | Function to extract the x-axis value from each data point |
|
|
70
|
-
| `getSecondary` | `(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
|
-
### Multiple Time Series
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
interface MetricsData {
|
|
81
|
-
date: string;
|
|
82
|
-
revenue: number;
|
|
83
|
-
expenses: number;
|
|
84
|
-
profit: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const metricsData: MetricsData[] = [
|
|
88
|
-
{ date: '2024-01', revenue: 250000, expenses: 180000, profit: 70000 },
|
|
89
|
-
{ date: '2024-02', revenue: 280000, expenses: 195000, profit: 85000 },
|
|
90
|
-
{ date: '2024-03', revenue: 310000, expenses: 210000, profit: 100000 },
|
|
91
|
-
{ date: '2024-04', revenue: 290000, expenses: 200000, profit: 90000 },
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
<LineChart
|
|
95
|
-
data={[
|
|
96
|
-
{
|
|
97
|
-
label: 'Revenue',
|
|
98
|
-
data: metricsData.map(d => ({ date: d.date, value: d.revenue }))
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
label: 'Expenses',
|
|
102
|
-
data: metricsData.map(d => ({ date: d.date, value: d.expenses }))
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
label: 'Profit',
|
|
106
|
-
data: metricsData.map(d => ({ date: d.date, value: d.profit }))
|
|
107
|
-
}
|
|
108
|
-
]}
|
|
109
|
-
getPrimary={(datum) => datum.date}
|
|
110
|
-
getSecondary={(datum) => datum.value}
|
|
111
|
-
title="Financial Performance Trends"
|
|
112
|
-
showDataLabels={true}
|
|
113
|
-
theme={webLightTheme}
|
|
114
|
-
/>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Performance Monitoring
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
interface PerformanceMetrics {
|
|
121
|
-
timestamp: string;
|
|
122
|
-
responseTime: number;
|
|
123
|
-
throughput: number;
|
|
124
|
-
errorRate: number;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const performanceData: PerformanceMetrics[] = [
|
|
128
|
-
{ timestamp: '09:00', responseTime: 120, throughput: 850, errorRate: 0.2 },
|
|
129
|
-
{ timestamp: '10:00', responseTime: 135, throughput: 920, errorRate: 0.3 },
|
|
130
|
-
{ timestamp: '11:00', responseTime: 118, throughput: 1100, errorRate: 0.1 },
|
|
131
|
-
{ timestamp: '12:00', responseTime: 145, throughput: 980, errorRate: 0.4 },
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
<LineChart
|
|
135
|
-
data={[
|
|
136
|
-
{
|
|
137
|
-
label: 'Response Time (ms)',
|
|
138
|
-
data: performanceData.map(d => ({ time: d.timestamp, value: d.responseTime }))
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
label: 'Error Rate (%)',
|
|
142
|
-
data: performanceData.map(d => ({ time: d.timestamp, value: d.errorRate }))
|
|
143
|
-
}
|
|
144
|
-
]}
|
|
145
|
-
getPrimary={(datum) => datum.time}
|
|
146
|
-
getSecondary={(datum) => datum.value}
|
|
147
|
-
title="System Performance Over Time"
|
|
148
|
-
theme={webLightTheme}
|
|
149
|
-
/>
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Growth Analysis
|
|
153
|
-
|
|
154
|
-
```tsx
|
|
155
|
-
interface GrowthData {
|
|
156
|
-
quarter: string;
|
|
157
|
-
userGrowth: number;
|
|
158
|
-
revenueGrowth: number;
|
|
159
|
-
marketShare: number;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const growthData: GrowthData[] = [
|
|
163
|
-
{ quarter: 'Q1 2023', userGrowth: 15.2, revenueGrowth: 12.8, marketShare: 8.5 },
|
|
164
|
-
{ quarter: 'Q2 2023', userGrowth: 18.7, revenueGrowth: 16.3, marketShare: 9.2 },
|
|
165
|
-
{ quarter: 'Q3 2023', userGrowth: 22.1, revenueGrowth: 19.7, marketShare: 10.1 },
|
|
166
|
-
{ quarter: 'Q4 2023', userGrowth: 25.8, revenueGrowth: 23.4, marketShare: 11.3 },
|
|
167
|
-
];
|
|
168
|
-
|
|
169
|
-
<LineChart
|
|
170
|
-
data={[
|
|
171
|
-
{
|
|
172
|
-
label: 'User Growth (%)',
|
|
173
|
-
data: growthData.map(d => ({ quarter: d.quarter, value: d.userGrowth }))
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
label: 'Revenue Growth (%)',
|
|
177
|
-
data: growthData.map(d => ({ quarter: d.quarter, value: d.revenueGrowth }))
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
label: 'Market Share (%)',
|
|
181
|
-
data: growthData.map(d => ({ quarter: d.quarter, value: d.marketShare }))
|
|
182
|
-
}
|
|
183
|
-
]}
|
|
184
|
-
getPrimary={(datum) => datum.quarter}
|
|
185
|
-
getSecondary={(datum) => datum.value}
|
|
186
|
-
title="Growth Metrics Trends"
|
|
187
|
-
showDataLabels={true}
|
|
188
|
-
theme={webLightTheme}
|
|
189
|
-
/>
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Stock Price Movement
|
|
193
|
-
|
|
194
|
-
```tsx
|
|
195
|
-
interface StockPrice {
|
|
196
|
-
date: Date;
|
|
197
|
-
price: number;
|
|
198
|
-
volume: number;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const stockData: StockPrice[] = [
|
|
202
|
-
{ date: new Date('2024-01-01'), price: 145.50, volume: 2500000 },
|
|
203
|
-
{ date: new Date('2024-01-02'), price: 148.25, volume: 3200000 },
|
|
204
|
-
{ date: new Date('2024-01-03'), price: 152.10, volume: 2800000 },
|
|
205
|
-
{ date: new Date('2024-01-04'), price: 149.75, volume: 3500000 },
|
|
206
|
-
];
|
|
207
|
-
|
|
208
|
-
<LineChart
|
|
209
|
-
data={[{ label: 'Stock Price', data: stockData }]}
|
|
210
|
-
getPrimary={(datum) => datum.date.toLocaleDateString()}
|
|
211
|
-
getSecondary={(datum) => datum.price}
|
|
212
|
-
title="Stock Price Movement"
|
|
213
|
-
showDataLabels={true}
|
|
214
|
-
theme={webLightTheme}
|
|
215
|
-
/>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Data Structure
|
|
219
|
-
|
|
220
|
-
The component expects data in the following format:
|
|
221
|
-
|
|
222
|
-
```tsx
|
|
223
|
-
interface ChartSeries<T> {
|
|
224
|
-
label: string; // Series name (appears in legend)
|
|
225
|
-
data: T[]; // Array of data points
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Each data point `T` should contain:
|
|
230
|
-
|
|
231
|
-
- A primary value (x-axis) - string or number
|
|
232
|
-
- A secondary value (y-axis) - number
|
|
233
|
-
|
|
234
|
-
## Line Styling
|
|
235
|
-
|
|
236
|
-
The component applies specific styling for optimal line visualization:
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
// Line properties
|
|
240
|
-
borderColor: Theme color from palette
|
|
241
|
-
backgroundColor: Same as border color
|
|
242
|
-
tension: 0.4 // Smooth curves
|
|
243
|
-
fill: false // No area fill
|
|
244
|
-
pointRadius: 4 // Visible data points
|
|
245
|
-
borderWidth: 2 // Line thickness
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## Use Cases
|
|
249
|
-
|
|
250
|
-
Line charts are particularly effective for:
|
|
251
|
-
|
|
252
|
-
### Time Series Analysis
|
|
253
|
-
|
|
254
|
-
- **Financial Data**: Stock prices, revenue trends, market indicators
|
|
255
|
-
- **Performance Metrics**: Response times, throughput, error rates
|
|
256
|
-
- **Business KPIs**: Growth rates, conversion rates, customer metrics
|
|
257
|
-
|
|
258
|
-
### Trend Visualization
|
|
259
|
-
|
|
260
|
-
- **Seasonal Patterns**: Sales cycles, website traffic, user engagement
|
|
261
|
-
- **Comparative Analysis**: Year-over-year comparisons, A/B test results
|
|
262
|
-
- **Forecasting**: Predictive analytics and trend projections
|
|
263
|
-
|
|
264
|
-
### Scientific Data
|
|
265
|
-
|
|
266
|
-
- **Experimental Results**: Measurement trends over time
|
|
267
|
-
- **Environmental Data**: Temperature, humidity, pollution levels
|
|
268
|
-
- **Research Analytics**: Survey responses, behavioral patterns
|
|
269
|
-
|
|
270
|
-
## Interactive Features
|
|
271
|
-
|
|
272
|
-
### Legend Controls
|
|
273
|
-
|
|
274
|
-
- Click legend items to show/hide data series
|
|
275
|
-
- Visual feedback on hover states
|
|
276
|
-
- At least one series must remain visible
|
|
277
|
-
- Colors automatically assigned from theme palette
|
|
278
|
-
|
|
279
|
-
### Point Interactions
|
|
280
|
-
|
|
281
|
-
- Hover effects on data points
|
|
282
|
-
- Rich tooltips showing detailed information
|
|
283
|
-
- Smooth transitions and animations
|
|
284
|
-
|
|
285
|
-
### Missing Data Handling
|
|
286
|
-
|
|
287
|
-
- Null values create gaps in lines
|
|
288
|
-
- Graceful handling of incomplete datasets
|
|
289
|
-
- Maintains line continuity where data exists
|
|
290
|
-
|
|
291
|
-
## Styling and Theme Integration
|
|
292
|
-
|
|
293
|
-
The component uses Fluent UI theme tokens:
|
|
294
|
-
|
|
295
|
-
```tsx
|
|
296
|
-
// Line styling
|
|
297
|
-
borderColor: Derived from theme palette
|
|
298
|
-
backgroundColor: Same as border color
|
|
299
|
-
pointBackgroundColor: White with border color outline
|
|
300
|
-
|
|
301
|
-
// Typography
|
|
302
|
-
fontFamily: theme.fontFamilyBase
|
|
303
|
-
fontSize: theme.fontSizeBase200
|
|
304
|
-
fontWeight: theme.fontWeightSemibold
|
|
305
|
-
color: theme.colorNeutralForeground1
|
|
306
|
-
|
|
307
|
-
// Grid and axes
|
|
308
|
-
labelColor: theme.colorNeutralForeground1
|
|
309
|
-
gridColor: theme.colorNeutralStroke2
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
## Performance Optimizations
|
|
313
|
-
|
|
314
|
-
The component includes several React optimizations:
|
|
315
|
-
|
|
316
|
-
````tsx
|
|
317
|
-
// Memoized color calculations
|
|
318
|
-
const seriesColors = useMemo(() => {
|
|
319
|
-
return data.reduce((acc, series, idx) => {
|
|
320
|
-
const base = getFluentPalette(theme)[idx % getFluentPalette(theme).length];
|
|
321
|
-
const color = lightenColor(base, 0.3);
|
|
322
|
-
acc[series.label] = color;
|
|
323
|
-
return acc;
|
|
324
|
-
}, {} as Record<string, string>);
|
|
325
|
-
}, [data, theme]);
|
|
326
|
-
|
|
327
|
-
// Memoized chart data transformation
|
|
328
|
-
const chartData = useMemo(() => {
|
|
329
|
-
return {
|
|
330
|
-
labels: allCategories,
|
|
331
|
-
datasets: data
|
|
332
|
-
.filter(series => visibleSeries.includes(series.label))
|
|
333
|
-
.map(series => ({
|
|
334
|
-
label: series.label,
|
|
335
|
-
data: allCategories.map(cat => {
|
|
336
|
-
const match = series.data.find(d => getPrimary(d) === cat);
|
|
337
|
-
return match ? getSecondary(match) : null;
|
|
338
|
-
}),
|
|
339
|
-
borderColor: seriesColors[series.label],
|
|
340
|
-
backgroundColor: seriesColors[series.label],
|
|
341
|
-
tension: 0.4,
|
|
342
|
-
fill: false,
|
|
343
|
-
pointRadius: 4,
|
|
344
|
-
})),
|
|
345
|
-
};
|
|
346
|
-
}, [data, visibleSeries, allCategories, getPrimary, getSecondary, seriesColors]);
|
|
347
|
-
|
|
348
|
-
// Memoized theme properties
|
|
349
|
-
const { fontFamily, fontSize, labelColor, gridColor } = useMemo(() => ({
|
|
350
|
-
fontFamily: theme.fontFamilyBase,
|
|
351
|
-
fontSize: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
352
|
-
labelColor: theme.colorNeutralForeground1,
|
|
353
|
-
gridColor: theme.colorNeutralStroke2,
|
|
354
|
-
}), [theme]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './LineChart';
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArcElement,
|
|
3
|
-
Chart as ChartJS,
|
|
4
|
-
ChartOptions,
|
|
5
|
-
Legend,
|
|
6
|
-
RadialLinearScale,
|
|
7
|
-
Title,
|
|
8
|
-
Tooltip,
|
|
9
|
-
} from 'chart.js';
|
|
10
|
-
import React, { useMemo, useState } from 'react';
|
|
11
|
-
import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
12
|
-
import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
|
|
13
|
-
|
|
14
|
-
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
15
|
-
import { PolarArea } from 'react-chartjs-2';
|
|
16
|
-
import RenderSliceLegend from '../../components/renderSliceLegend/RenderSliceLegend';
|
|
17
|
-
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
18
|
-
|
|
19
|
-
ChartJS.register(
|
|
20
|
-
RadialLinearScale,
|
|
21
|
-
ArcElement,
|
|
22
|
-
Tooltip,
|
|
23
|
-
Legend,
|
|
24
|
-
Title,
|
|
25
|
-
ChartDataLabels
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
export interface PolarChartProps<T> {
|
|
29
|
-
data: {
|
|
30
|
-
label: string;
|
|
31
|
-
data: T[];
|
|
32
|
-
}[];
|
|
33
|
-
getLabel: (datum: T) => string;
|
|
34
|
-
getValue: (datum: T) => number;
|
|
35
|
-
title?: string;
|
|
36
|
-
showDataLabels?: boolean;
|
|
37
|
-
theme?: Theme;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export default function PolarChart<T extends object>({
|
|
41
|
-
data,
|
|
42
|
-
getLabel,
|
|
43
|
-
getValue,
|
|
44
|
-
title,
|
|
45
|
-
showDataLabels = true,
|
|
46
|
-
theme = webLightTheme,
|
|
47
|
-
}: PolarChartProps<T>) {
|
|
48
|
-
const { getFluentPalette, lightenColor } = useChartUtils(theme);
|
|
49
|
-
const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
|
|
50
|
-
const styles = useGraphGlobalStyles();
|
|
51
|
-
const toggleLabel = (label: string) => {
|
|
52
|
-
setHiddenLabels(prev =>
|
|
53
|
-
prev.includes(label) ? prev.filter(l => l !== label) : [...prev, label]
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const valueMap = useMemo(() => {
|
|
58
|
-
const map = new Map<string, number>();
|
|
59
|
-
data.forEach(series => {
|
|
60
|
-
series.data.forEach(d => {
|
|
61
|
-
const label = getLabel(d);
|
|
62
|
-
const value = getValue(d);
|
|
63
|
-
map.set(label, (map.get(label) || 0) + value);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
return map;
|
|
67
|
-
}, [data, getLabel, getValue]);
|
|
68
|
-
|
|
69
|
-
const { allLabels, colors, filteredLabels, values, visibleColors } = useMemo(() => {
|
|
70
|
-
const allLabels = Array.from(valueMap.keys());
|
|
71
|
-
const palette = getFluentPalette(theme);
|
|
72
|
-
const colors = allLabels.map((_, i) =>
|
|
73
|
-
lightenColor(palette[i % palette.length], 0.3)
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const filteredLabels = allLabels.filter(
|
|
77
|
-
label => !hiddenLabels.includes(label)
|
|
78
|
-
);
|
|
79
|
-
const values = filteredLabels.map(label => valueMap.get(label) || 0);
|
|
80
|
-
const visibleColors = filteredLabels.map(label => {
|
|
81
|
-
const idx = allLabels.indexOf(label);
|
|
82
|
-
return colors[idx];
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
return { allLabels, colors, filteredLabels, values, visibleColors };
|
|
86
|
-
}, [valueMap, getFluentPalette, lightenColor, theme, hiddenLabels]);
|
|
87
|
-
|
|
88
|
-
const chartData = useMemo(() => ({
|
|
89
|
-
labels: filteredLabels,
|
|
90
|
-
datasets: [
|
|
91
|
-
{
|
|
92
|
-
data: values,
|
|
93
|
-
backgroundColor: visibleColors,
|
|
94
|
-
borderWidth: 1,
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
}), [filteredLabels, values, visibleColors]);
|
|
98
|
-
|
|
99
|
-
const options = useMemo<ChartOptions<'polarArea'>>(() => ({
|
|
100
|
-
responsive: true,
|
|
101
|
-
maintainAspectRatio: false,
|
|
102
|
-
plugins: {
|
|
103
|
-
title: {
|
|
104
|
-
display: !!title,
|
|
105
|
-
text: title,
|
|
106
|
-
font: {
|
|
107
|
-
size: 14,
|
|
108
|
-
family: theme.fontFamilyBase,
|
|
109
|
-
weight: theme.fontWeightSemibold,
|
|
110
|
-
},
|
|
111
|
-
color: theme.colorNeutralForeground1,
|
|
112
|
-
padding: {
|
|
113
|
-
top: 20,
|
|
114
|
-
bottom: 20,
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
datalabels: {
|
|
118
|
-
display: showDataLabels,
|
|
119
|
-
color: theme.colorNeutralForeground1,
|
|
120
|
-
font: {
|
|
121
|
-
family: theme.fontFamilyBase,
|
|
122
|
-
size: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
123
|
-
},
|
|
124
|
-
formatter: (value: number) => value,
|
|
125
|
-
},
|
|
126
|
-
tooltip: createFluentTooltip<'polarArea'>(theme),
|
|
127
|
-
legend: { display: false },
|
|
128
|
-
},
|
|
129
|
-
scales: {
|
|
130
|
-
r: {
|
|
131
|
-
ticks: {
|
|
132
|
-
color: theme.colorNeutralForeground1,
|
|
133
|
-
backdropColor: 'transparent',
|
|
134
|
-
font: {
|
|
135
|
-
family: theme.fontFamilyBase,
|
|
136
|
-
size: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
grid: {
|
|
140
|
-
color: theme.colorNeutralStroke2,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
}), [theme, title, showDataLabels, createFluentTooltip]);
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<div className={styles.chartWithLegend}>
|
|
148
|
-
<div className={styles.chartArea}>
|
|
149
|
-
<PolarArea data={chartData} options={options} />
|
|
150
|
-
</div>
|
|
151
|
-
<div className={styles.legendArea}>
|
|
152
|
-
<RenderSliceLegend
|
|
153
|
-
labels={allLabels}
|
|
154
|
-
colors={colors}
|
|
155
|
-
visibleLabels={filteredLabels}
|
|
156
|
-
toggleLabel={toggleLabel}
|
|
157
|
-
/>
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
160
|
-
);
|
|
161
|
-
}
|