@spteck/fluentui-react-charts 1.0.6 → 1.0.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.
- 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 +1367 -1066
- 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 +1353 -1066
- package/dist/fluentui-react-charts.esm.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +4 -4
- 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 -189
- 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 -122
- 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,388 +0,0 @@
|
|
|
1
|
-
# RadarChart Component
|
|
2
|
-
|
|
3
|
-
A powerful radar (spider/web) chart component built with Chart.js and Fluent UI React. This component displays multivariate data on a circular grid with multiple axes radiating from the center, making it perfect for comparing multiple quantitative variables across different entities or showing performance profiles.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Multi-dimensional Data Visualization**: Display multiple metrics on radial axes
|
|
8
|
-
- **Multiple Series Support**: Compare different entities or time periods on the same chart
|
|
9
|
-
- **Interactive Legend**: Toggle series visibility with click interactions
|
|
10
|
-
- **Filled Areas**: Semi-transparent fill areas for better visual comparison
|
|
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 metric information
|
|
16
|
-
- **Radial Grid**: Concentric circles and radial lines for value reference
|
|
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 { RadarChart } from './components/radarChart/RadarChart';
|
|
29
|
-
import { webLightTheme } from '@fluentui/react-components';
|
|
30
|
-
|
|
31
|
-
interface SkillAssessment {
|
|
32
|
-
skill: string;
|
|
33
|
-
score: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const skillData: SkillAssessment[] = [
|
|
37
|
-
{ skill: 'Communication', score: 85 },
|
|
38
|
-
{ skill: 'Technical Skills', score: 92 },
|
|
39
|
-
{ skill: 'Leadership', score: 78 },
|
|
40
|
-
{ skill: 'Problem Solving', score: 88 },
|
|
41
|
-
{ skill: 'Teamwork', score: 90 },
|
|
42
|
-
{ skill: 'Creativity', score: 82 },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
function App() {
|
|
46
|
-
return (
|
|
47
|
-
<div style={{ width: '600px', height: '500px' }}>
|
|
48
|
-
<RadarChart
|
|
49
|
-
data={[
|
|
50
|
-
{ label: 'Employee Skills', data: skillData }
|
|
51
|
-
]}
|
|
52
|
-
getLabel={(datum) => datum.skill}
|
|
53
|
-
getValue={(datum) => datum.score}
|
|
54
|
-
title="Skill Assessment Profile"
|
|
55
|
-
theme={webLightTheme}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Props
|
|
63
|
-
|
|
64
|
-
### RadarChartProps<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
|
-
| `getLabel` | `(datum: T) => string` | Yes | - | Function to extract the axis label from each data point |
|
|
70
|
-
| `getValue` | `(datum: T) => number` | Yes | - | Function to extract the 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
|
-
### Employee Performance Comparison
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
interface PerformanceMetric {
|
|
81
|
-
metric: string;
|
|
82
|
-
employee1: number;
|
|
83
|
-
employee2: number;
|
|
84
|
-
employee3: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const performanceData: PerformanceMetric[] = [
|
|
88
|
-
{ metric: 'Quality', employee1: 88, employee2: 92, employee3: 85 },
|
|
89
|
-
{ metric: 'Productivity', employee1: 85, employee2: 78, employee3: 90 },
|
|
90
|
-
{ metric: 'Innovation', employee1: 90, employee2: 95, employee3: 82 },
|
|
91
|
-
{ metric: 'Collaboration', employee1: 82, employee2: 88, employee3: 95 },
|
|
92
|
-
{ metric: 'Leadership', employee1: 78, employee2: 85, employee3: 88 },
|
|
93
|
-
{ metric: 'Communication', employee1: 92, employee2: 90, employee3: 90 },
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
<RadarChart
|
|
97
|
-
data={[
|
|
98
|
-
{
|
|
99
|
-
label: 'Alice Johnson',
|
|
100
|
-
data: performanceData.map(d => ({ metric: d.metric, value: d.employee1 }))
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
label: 'Bob Smith',
|
|
104
|
-
data: performanceData.map(d => ({ metric: d.metric, value: d.employee2 }))
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
label: 'Carol Davis',
|
|
108
|
-
data: performanceData.map(d => ({ metric: d.metric, value: d.employee3 }))
|
|
109
|
-
}
|
|
110
|
-
]}
|
|
111
|
-
getLabel={(datum) => datum.metric}
|
|
112
|
-
getValue={(datum) => datum.value}
|
|
113
|
-
title="Employee Performance Comparison"
|
|
114
|
-
showDataLabels={true}
|
|
115
|
-
theme={webLightTheme}
|
|
116
|
-
/>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Product Feature Analysis
|
|
120
|
-
|
|
121
|
-
```tsx
|
|
122
|
-
interface ProductFeature {
|
|
123
|
-
feature: string;
|
|
124
|
-
currentVersion: number;
|
|
125
|
-
competitorA: number;
|
|
126
|
-
competitorB: number;
|
|
127
|
-
targetVersion: number;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const featureData: ProductFeature[] = [
|
|
131
|
-
{ feature: 'User Experience', currentVersion: 85, competitorA: 90, competitorB: 82, targetVersion: 95 },
|
|
132
|
-
{ feature: 'Performance', currentVersion: 88, competitorA: 85, competitorB: 92, targetVersion: 95 },
|
|
133
|
-
{ feature: 'Security', currentVersion: 92, competitorA: 88, competitorB: 90, targetVersion: 98 },
|
|
134
|
-
{ feature: 'Scalability', currentVersion: 78, competitorA: 85, competitorB: 80, targetVersion: 90 },
|
|
135
|
-
{ feature: 'Integration', currentVersion: 82, competitorA: 88, competitorB: 85, targetVersion: 92 },
|
|
136
|
-
{ feature: 'Support', currentVersion: 90, competitorA: 85, competitorB: 88, targetVersion: 95 },
|
|
137
|
-
];
|
|
138
|
-
|
|
139
|
-
<RadarChart
|
|
140
|
-
data={[
|
|
141
|
-
{
|
|
142
|
-
label: 'Our Product',
|
|
143
|
-
data: featureData.map(d => ({ feature: d.feature, value: d.currentVersion }))
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
label: 'Competitor A',
|
|
147
|
-
data: featureData.map(d => ({ feature: d.feature, value: d.competitorA }))
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
label: 'Target Goals',
|
|
151
|
-
data: featureData.map(d => ({ feature: d.feature, value: d.targetVersion }))
|
|
152
|
-
}
|
|
153
|
-
]}
|
|
154
|
-
getLabel={(datum) => datum.feature}
|
|
155
|
-
getValue={(datum) => datum.value}
|
|
156
|
-
title="Product Feature Competitive Analysis"
|
|
157
|
-
theme={webLightTheme}
|
|
158
|
-
/>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Financial Health Assessment
|
|
162
|
-
|
|
163
|
-
```tsx
|
|
164
|
-
interface FinancialMetric {
|
|
165
|
-
category: string;
|
|
166
|
-
q1Score: number;
|
|
167
|
-
q2Score: number;
|
|
168
|
-
q3Score: number;
|
|
169
|
-
q4Score: number;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const financialData: FinancialMetric[] = [
|
|
173
|
-
{ category: 'Liquidity', q1Score: 85, q2Score: 88, q3Score: 82, q4Score: 90 },
|
|
174
|
-
{ category: 'Profitability', q1Score: 78, q2Score: 82, q3Score: 85, q4Score: 88 },
|
|
175
|
-
{ category: 'Efficiency', q1Score: 88, q2Score: 85, q3Score: 90, q4Score: 92 },
|
|
176
|
-
{ category: 'Leverage', q1Score: 75, q2Score: 78, q3Score: 80, q4Score: 82 },
|
|
177
|
-
{ category: 'Growth', q1Score: 82, q2Score: 85, q3Score: 88, q4Score: 90 },
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
<RadarChart
|
|
181
|
-
data={[
|
|
182
|
-
{
|
|
183
|
-
label: 'Q1 2024',
|
|
184
|
-
data: financialData.map(d => ({ category: d.category, value: d.q1Score }))
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
label: 'Q4 2024',
|
|
188
|
-
data: financialData.map(d => ({ category: d.category, value: d.q4Score }))
|
|
189
|
-
}
|
|
190
|
-
]}
|
|
191
|
-
getLabel={(datum) => datum.category}
|
|
192
|
-
getValue={(datum) => datum.value}
|
|
193
|
-
title="Financial Health: Q1 vs Q4 Comparison"
|
|
194
|
-
showDataLabels={true}
|
|
195
|
-
theme={webLightTheme}
|
|
196
|
-
/>
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Technology Stack Evaluation
|
|
200
|
-
|
|
201
|
-
```tsx
|
|
202
|
-
interface TechnologyAssessment {
|
|
203
|
-
criterion: string;
|
|
204
|
-
react: number;
|
|
205
|
-
vue: number;
|
|
206
|
-
angular: number;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const techData: TechnologyAssessment[] = [
|
|
210
|
-
{ criterion: 'Learning Curve', react: 85, vue: 90, angular: 70 },
|
|
211
|
-
{ criterion: 'Performance', react: 88, vue: 85, angular: 82 },
|
|
212
|
-
{ criterion: 'Community Support', react: 95, vue: 85, angular: 88 },
|
|
213
|
-
{ criterion: 'Ecosystem', react: 92, vue: 82, angular: 90 },
|
|
214
|
-
{ criterion: 'Developer Experience', react: 90, vue: 88, angular: 78 },
|
|
215
|
-
{ criterion: 'Enterprise Readiness', react: 85, vue: 80, angular: 92 },
|
|
216
|
-
];
|
|
217
|
-
|
|
218
|
-
<RadarChart
|
|
219
|
-
data={[
|
|
220
|
-
{
|
|
221
|
-
label: 'React',
|
|
222
|
-
data: techData.map(d => ({ criterion: d.criterion, value: d.react }))
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
label: 'Vue.js',
|
|
226
|
-
data: techData.map(d => ({ criterion: d.criterion, value: d.vue }))
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
label: 'Angular',
|
|
230
|
-
data: techData.map(d => ({ criterion: d.criterion, value: d.angular }))
|
|
231
|
-
}
|
|
232
|
-
]}
|
|
233
|
-
getLabel={(datum) => datum.criterion}
|
|
234
|
-
getValue={(datum) => datum.value}
|
|
235
|
-
title="Frontend Framework Comparison"
|
|
236
|
-
theme={webLightTheme}
|
|
237
|
-
/>
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Data Structure
|
|
241
|
-
|
|
242
|
-
The component expects data in the following format:
|
|
243
|
-
|
|
244
|
-
```tsx
|
|
245
|
-
interface ChartSeries<T> {
|
|
246
|
-
label: string; // Series name (appears in legend)
|
|
247
|
-
data: T[]; // Array of data points
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Each data point `T` should contain:
|
|
252
|
-
|
|
253
|
-
- A label value (axis name) - string
|
|
254
|
-
- A numeric value (distance from center) - number
|
|
255
|
-
|
|
256
|
-
## Radar Chart Characteristics
|
|
257
|
-
|
|
258
|
-
### Axes Configuration
|
|
259
|
-
|
|
260
|
-
- **Radial Axes**: Each metric becomes a spoke radiating from center
|
|
261
|
-
- **Equal Spacing**: Axes are evenly distributed around the circle
|
|
262
|
-
- **Scale**: All axes share the same scale (0 to maximum value)
|
|
263
|
-
|
|
264
|
-
### Visual Elements
|
|
265
|
-
|
|
266
|
-
- **Points**: Data values plotted on each axis
|
|
267
|
-
- **Lines**: Connect points to form polygonal shapes
|
|
268
|
-
- **Fill Areas**: Semi-transparent areas enclosed by the polygon
|
|
269
|
-
- **Grid**: Concentric circles and radial lines for reference
|
|
270
|
-
|
|
271
|
-
## Use Cases
|
|
272
|
-
|
|
273
|
-
Radar charts are particularly effective for:
|
|
274
|
-
|
|
275
|
-
### Performance Analysis
|
|
276
|
-
|
|
277
|
-
- **Employee Evaluation**: Multi-dimensional skill assessment
|
|
278
|
-
- **Product Comparison**: Feature-by-feature analysis
|
|
279
|
-
- **Team Performance**: Various performance metrics
|
|
280
|
-
|
|
281
|
-
### Competitive Analysis
|
|
282
|
-
|
|
283
|
-
- **Market Positioning**: Compare products across multiple criteria
|
|
284
|
-
- **SWOT Analysis**: Strengths, weaknesses, opportunities, threats
|
|
285
|
-
- **Vendor Evaluation**: Multi-criteria decision analysis
|
|
286
|
-
|
|
287
|
-
### Quality Assessment
|
|
288
|
-
|
|
289
|
-
- **Customer Satisfaction**: Various satisfaction dimensions
|
|
290
|
-
- **System Performance**: Multiple performance metrics
|
|
291
|
-
- **Risk Assessment**: Different risk factors
|
|
292
|
-
|
|
293
|
-
### Portfolio Analysis
|
|
294
|
-
|
|
295
|
-
- **Investment Options**: Risk vs return across multiple factors
|
|
296
|
-
- **Project Evaluation**: Multiple project criteria
|
|
297
|
-
- **Technology Selection**: Various technical and business criteria
|
|
298
|
-
|
|
299
|
-
## Interactive Features
|
|
300
|
-
|
|
301
|
-
### Legend Controls
|
|
302
|
-
|
|
303
|
-
- Click legend items to show/hide data series
|
|
304
|
-
- Visual feedback on hover states
|
|
305
|
-
- Color-coded entries matching chart areas
|
|
306
|
-
- Series can be toggled independently
|
|
307
|
-
|
|
308
|
-
### Point Interactions
|
|
309
|
-
|
|
310
|
-
- Hover effects on data points
|
|
311
|
-
- Rich tooltips showing metric details
|
|
312
|
-
- Smooth transitions and animations
|
|
313
|
-
|
|
314
|
-
### Radial Grid
|
|
315
|
-
|
|
316
|
-
- Concentric circles showing value scales
|
|
317
|
-
- Radial lines for each metric axis
|
|
318
|
-
- Theme-aware styling and colors
|
|
319
|
-
|
|
320
|
-
## Styling and Theme Integration
|
|
321
|
-
|
|
322
|
-
The component uses Fluent UI theme tokens:
|
|
323
|
-
|
|
324
|
-
```tsx
|
|
325
|
-
// Area styling
|
|
326
|
-
backgroundColor: seriesColor + '33' (20% opacity)
|
|
327
|
-
borderColor: seriesColor
|
|
328
|
-
borderWidth: 2
|
|
329
|
-
pointBackgroundColor: seriesColor
|
|
330
|
-
|
|
331
|
-
// Grid styling
|
|
332
|
-
angleLines: { color: theme.colorNeutralStroke2 }
|
|
333
|
-
grid: { color: theme.colorNeutralStroke2 }
|
|
334
|
-
|
|
335
|
-
// Typography
|
|
336
|
-
fontFamily: theme.fontFamilyBase
|
|
337
|
-
fontSize: theme.fontSizeBase200
|
|
338
|
-
color: theme.colorNeutralForeground1
|
|
339
|
-
|
|
340
|
-
// Point labels (axis names)
|
|
341
|
-
color: theme.colorNeutralForeground1
|
|
342
|
-
font: { family: fontFamily, size: fontSize }
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
## Performance Optimizations
|
|
346
|
-
|
|
347
|
-
The component includes several React optimizations:
|
|
348
|
-
|
|
349
|
-
````tsx
|
|
350
|
-
// Memoized color calculations
|
|
351
|
-
const seriesColors = useMemo(() => {
|
|
352
|
-
return data.reduce((acc, series, idx) => {
|
|
353
|
-
const base = getFluentPalette(theme)[
|
|
354
|
-
idx % getFluentPalette(theme).length
|
|
355
|
-
];
|
|
356
|
-
acc[series.label] = lightenColor(base, 0.3);
|
|
357
|
-
return acc;
|
|
358
|
-
}, {} as Record<string, string>);
|
|
359
|
-
}, [data, getFluentPalette, lightenColor, theme]);
|
|
360
|
-
|
|
361
|
-
// Memoized axis labels
|
|
362
|
-
const allLabels = useMemo(() => {
|
|
363
|
-
const set = new Set<string>();
|
|
364
|
-
data.forEach(series => {
|
|
365
|
-
series.data.forEach(d => set.add(getLabel(d)));
|
|
366
|
-
});
|
|
367
|
-
return Array.from(set);
|
|
368
|
-
}, [data, getLabel]);
|
|
369
|
-
|
|
370
|
-
// Memoized chart data transformation
|
|
371
|
-
const chartData = useMemo(() => {
|
|
372
|
-
return {
|
|
373
|
-
labels: allLabels,
|
|
374
|
-
datasets: data
|
|
375
|
-
.filter(series => visibleSeries.includes(series.label))
|
|
376
|
-
.map(series => ({
|
|
377
|
-
label: series.label,
|
|
378
|
-
data: allLabels.map(label => {
|
|
379
|
-
const match = series.data.find(d => getLabel(d) === label);
|
|
380
|
-
return match ? getValue(match) : 0;
|
|
381
|
-
}),
|
|
382
|
-
backgroundColor: seriesColors[series.label] + '33',
|
|
383
|
-
borderColor: seriesColors[series.label],
|
|
384
|
-
borderWidth: 2,
|
|
385
|
-
pointBackgroundColor: seriesColors[series.label],
|
|
386
|
-
})),
|
|
387
|
-
};
|
|
388
|
-
}, [data, visibleSeries, allLabels, getLabel, getValue, seriesColors]);
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Chart as ChartJS,
|
|
3
|
-
ChartOptions,
|
|
4
|
-
Filler,
|
|
5
|
-
Legend,
|
|
6
|
-
LineElement,
|
|
7
|
-
PointElement,
|
|
8
|
-
RadialLinearScale,
|
|
9
|
-
Title,
|
|
10
|
-
Tooltip,
|
|
11
|
-
} from 'chart.js';
|
|
12
|
-
import React, { useMemo, useState } from 'react';
|
|
13
|
-
import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
14
|
-
import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
|
|
15
|
-
|
|
16
|
-
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
17
|
-
import { Radar } from 'react-chartjs-2';
|
|
18
|
-
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
19
|
-
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
20
|
-
|
|
21
|
-
ChartJS.register(ChartDataLabels);
|
|
22
|
-
ChartJS.register(
|
|
23
|
-
RadialLinearScale,
|
|
24
|
-
PointElement,
|
|
25
|
-
LineElement,
|
|
26
|
-
Filler,
|
|
27
|
-
Tooltip,
|
|
28
|
-
Legend,
|
|
29
|
-
Title
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
export interface RadarChartProps<T> {
|
|
33
|
-
data: { label: string; data: T[] }[];
|
|
34
|
-
getLabel: (datum: T) => string;
|
|
35
|
-
getValue: (datum: T) => number;
|
|
36
|
-
title?: string;
|
|
37
|
-
showDataLabels?: boolean;
|
|
38
|
-
theme?: Theme;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default function RadarChart<T extends object>({
|
|
42
|
-
data,
|
|
43
|
-
getLabel,
|
|
44
|
-
getValue,
|
|
45
|
-
title,
|
|
46
|
-
showDataLabels = false,
|
|
47
|
-
theme = webLightTheme,
|
|
48
|
-
}: RadarChartProps<T>) {
|
|
49
|
-
const [visibleSeries, setVisibleSeries] = useState(() =>
|
|
50
|
-
data.map(s => s.label)
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const styles = useGraphGlobalStyles();
|
|
54
|
-
const { lightenColor, getFluentPalette } = useChartUtils(theme);
|
|
55
|
-
|
|
56
|
-
const seriesColors = useMemo(() => {
|
|
57
|
-
return data.reduce((acc, series, idx) => {
|
|
58
|
-
const base = getFluentPalette(theme)[
|
|
59
|
-
idx % getFluentPalette(theme).length
|
|
60
|
-
];
|
|
61
|
-
acc[series.label] = lightenColor(base, 0.3);
|
|
62
|
-
return acc;
|
|
63
|
-
}, {} as Record<string, string>);
|
|
64
|
-
}, [data, getFluentPalette, lightenColor, theme]);
|
|
65
|
-
|
|
66
|
-
const toggleSeries = (label: string) => {
|
|
67
|
-
setVisibleSeries(prev =>
|
|
68
|
-
prev.includes(label) ? prev.filter(l => l !== label) : [...prev, label]
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const allLabels = useMemo(() => {
|
|
73
|
-
const set = new Set<string>();
|
|
74
|
-
data.forEach(series => {
|
|
75
|
-
series.data.forEach(d => set.add(getLabel(d)));
|
|
76
|
-
});
|
|
77
|
-
return Array.from(set);
|
|
78
|
-
}, [data, getLabel]);
|
|
79
|
-
|
|
80
|
-
const chartData = useMemo(() => {
|
|
81
|
-
return {
|
|
82
|
-
labels: allLabels,
|
|
83
|
-
datasets: data
|
|
84
|
-
.filter(series => visibleSeries.includes(series.label))
|
|
85
|
-
.map(series => ({
|
|
86
|
-
label: series.label,
|
|
87
|
-
data: allLabels.map(label => {
|
|
88
|
-
const match = series.data.find(d => getLabel(d) === label);
|
|
89
|
-
return match ? getValue(match) : 0;
|
|
90
|
-
}),
|
|
91
|
-
backgroundColor: seriesColors[series.label] + '33',
|
|
92
|
-
borderColor: seriesColors[series.label],
|
|
93
|
-
borderWidth: 2,
|
|
94
|
-
pointBackgroundColor: seriesColors[series.label],
|
|
95
|
-
})),
|
|
96
|
-
};
|
|
97
|
-
}, [data, visibleSeries, allLabels, getLabel, getValue, seriesColors]);
|
|
98
|
-
|
|
99
|
-
const { fontFamily, fontSize, labelColor, gridColor } = useMemo(() => ({
|
|
100
|
-
fontFamily: theme.fontFamilyBase,
|
|
101
|
-
fontSize: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
102
|
-
labelColor: theme.colorNeutralForeground1,
|
|
103
|
-
gridColor: theme.colorNeutralStroke2,
|
|
104
|
-
}), [theme]);
|
|
105
|
-
|
|
106
|
-
const options = useMemo<ChartOptions<'radar'>>(() => ({
|
|
107
|
-
responsive: true,
|
|
108
|
-
maintainAspectRatio: false,
|
|
109
|
-
plugins: {
|
|
110
|
-
title: {
|
|
111
|
-
display: !!title,
|
|
112
|
-
text: title,
|
|
113
|
-
font: {
|
|
114
|
-
size: 14,
|
|
115
|
-
family: theme.fontFamilyBase,
|
|
116
|
-
weight: theme.fontWeightSemibold,
|
|
117
|
-
},
|
|
118
|
-
color: theme.colorNeutralForeground1,
|
|
119
|
-
padding: {
|
|
120
|
-
top: 20,
|
|
121
|
-
bottom: 20,
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
datalabels: {
|
|
125
|
-
display: showDataLabels,
|
|
126
|
-
color: theme.colorNeutralForeground1,
|
|
127
|
-
font: {
|
|
128
|
-
family: theme.fontFamilyBase,
|
|
129
|
-
size: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
tooltip: createFluentTooltip<'radar'>(theme),
|
|
133
|
-
legend: { display: false },
|
|
134
|
-
},
|
|
135
|
-
scales: {
|
|
136
|
-
r: {
|
|
137
|
-
angleLines: { color: gridColor },
|
|
138
|
-
grid: { color: gridColor },
|
|
139
|
-
pointLabels: {
|
|
140
|
-
color: labelColor,
|
|
141
|
-
font: { family: fontFamily, size: fontSize },
|
|
142
|
-
},
|
|
143
|
-
ticks: {
|
|
144
|
-
color: labelColor,
|
|
145
|
-
font: { family: fontFamily, size: fontSize },
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
}), [
|
|
150
|
-
theme,
|
|
151
|
-
title,
|
|
152
|
-
showDataLabels,
|
|
153
|
-
createFluentTooltip,
|
|
154
|
-
gridColor,
|
|
155
|
-
labelColor,
|
|
156
|
-
fontFamily,
|
|
157
|
-
fontSize,
|
|
158
|
-
]);
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<div className={styles.chartWithLegend}>
|
|
162
|
-
<div className={styles.chartArea}>
|
|
163
|
-
<Radar data={chartData} options={options} />
|
|
164
|
-
</div>
|
|
165
|
-
<RenderLegend
|
|
166
|
-
data={data}
|
|
167
|
-
visibleSeries={visibleSeries}
|
|
168
|
-
seriesColors={seriesColors}
|
|
169
|
-
toggleSeries={toggleSeries}
|
|
170
|
-
/>
|
|
171
|
-
</div>
|
|
172
|
-
);
|
|
173
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './RadarChart';
|