@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,236 +0,0 @@
|
|
|
1
|
-
# AreaChart Component
|
|
2
|
-
|
|
3
|
-
A flexible and customizable area chart component built with Chart.js and Fluent UI React. This component provides smooth area visualizations with interactive legends and responsive design.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Interactive Legend**: Toggle series visibility by clicking legend items
|
|
8
|
-
- **Fluent UI Integration**: Seamlessly integrates with Fluent UI themes
|
|
9
|
-
- **Responsive Design**: Automatically adapts to container size
|
|
10
|
-
- **Customizable**: Support for titles, data labels, and stacked charts
|
|
11
|
-
- **TypeScript Support**: Full TypeScript support with generic types
|
|
12
|
-
- **Smooth Animations**: Built-in smooth transitions and hover effects
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install chart.js react-chartjs-2 chartjs-plugin-datalabels @fluentui/react-components
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Basic Usage
|
|
21
|
-
|
|
22
|
-
```tsx
|
|
23
|
-
import React from 'react';
|
|
24
|
-
import { AreaChart } from './components/AreaChart/AreaChart';
|
|
25
|
-
import { webLightTheme } from '@fluentui/react-components';
|
|
26
|
-
|
|
27
|
-
interface SalesData {
|
|
28
|
-
month: string;
|
|
29
|
-
revenue: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const salesData: SalesData[] = [
|
|
33
|
-
{ month: 'Jan', revenue: 10000 },
|
|
34
|
-
{ month: 'Feb', revenue: 15000 },
|
|
35
|
-
{ month: 'Mar', revenue: 12000 },
|
|
36
|
-
{ month: 'Apr', revenue: 18000 },
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
function App() {
|
|
40
|
-
return (
|
|
41
|
-
<div style={{ width: '800px', height: '400px' }}>
|
|
42
|
-
<AreaChart
|
|
43
|
-
data={[
|
|
44
|
-
{ label: 'Sales', data: salesData }
|
|
45
|
-
]}
|
|
46
|
-
getPrimary={(datum) => datum.month}
|
|
47
|
-
getSecondary={(datum) => datum.revenue}
|
|
48
|
-
title="Monthly Sales Revenue"
|
|
49
|
-
theme={webLightTheme}
|
|
50
|
-
/>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Props
|
|
57
|
-
|
|
58
|
-
### AreaChartProps<T>
|
|
59
|
-
|
|
60
|
-
| Prop | Type | Required | Default | Description |
|
|
61
|
-
|------|------|----------|---------|-------------|
|
|
62
|
-
| `data` | `{ label: string; data: T[] }[]` | Yes | - | Array of data series with labels and data points |
|
|
63
|
-
| `getPrimary` | `(datum: T) => string \| number` | Yes | - | Function to extract the x-axis value from each data point |
|
|
64
|
-
| `getSecondary` | `(datum: T) => number` | Yes | - | Function to extract the y-axis value from each data point |
|
|
65
|
-
| `stacked` | `boolean` | No | `false` | Whether to stack the areas |
|
|
66
|
-
| `title` | `string` | No | - | Chart title displayed at the top |
|
|
67
|
-
| `showDatalabels` | `boolean` | No | `false` | Whether to show data labels on data points |
|
|
68
|
-
| `theme` | `Theme` | No | `webLightTheme` | Fluent UI theme for styling |
|
|
69
|
-
|
|
70
|
-
## Advanced Usage
|
|
71
|
-
|
|
72
|
-
### Multiple Series
|
|
73
|
-
|
|
74
|
-
```tsx
|
|
75
|
-
interface SalesData {
|
|
76
|
-
month: string;
|
|
77
|
-
product1: number;
|
|
78
|
-
product2: number;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const salesData: SalesData[] = [
|
|
82
|
-
{ month: 'Jan', product1: 10000, product2: 8000 },
|
|
83
|
-
{ month: 'Feb', product1: 15000, product2: 12000 },
|
|
84
|
-
{ month: 'Mar', product1: 12000, product2: 9000 },
|
|
85
|
-
];
|
|
86
|
-
|
|
87
|
-
<AreaChart
|
|
88
|
-
data={[
|
|
89
|
-
{
|
|
90
|
-
label: 'Product 1',
|
|
91
|
-
data: salesData.map(d => ({ month: d.month, value: d.product1 }))
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
label: 'Product 2',
|
|
95
|
-
data: salesData.map(d => ({ month: d.month, value: d.product2 }))
|
|
96
|
-
}
|
|
97
|
-
]}
|
|
98
|
-
getPrimary={(datum) => datum.month}
|
|
99
|
-
getSecondary={(datum) => datum.value}
|
|
100
|
-
title="Product Sales Comparison"
|
|
101
|
-
theme={webLightTheme}
|
|
102
|
-
/>
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Stacked Areas
|
|
106
|
-
|
|
107
|
-
```tsx
|
|
108
|
-
<AreaChart
|
|
109
|
-
data={[
|
|
110
|
-
{ label: 'Desktop', data: trafficData },
|
|
111
|
-
{ label: 'Mobile', data: trafficData },
|
|
112
|
-
{ label: 'Tablet', data: trafficData }
|
|
113
|
-
]}
|
|
114
|
-
getPrimary={(datum) => datum.date}
|
|
115
|
-
getSecondary={(datum) => datum.visits}
|
|
116
|
-
stacked={true}
|
|
117
|
-
title="Website Traffic by Device"
|
|
118
|
-
showDatalabels={true}
|
|
119
|
-
theme={webLightTheme}
|
|
120
|
-
/>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Custom Theme
|
|
124
|
-
|
|
125
|
-
```tsx
|
|
126
|
-
import { webDarkTheme } from '@fluentui/react-components';
|
|
127
|
-
|
|
128
|
-
<AreaChart
|
|
129
|
-
data={chartData}
|
|
130
|
-
getPrimary={(datum) => datum.category}
|
|
131
|
-
getSecondary={(datum) => datum.value}
|
|
132
|
-
title="Dark Theme Chart"
|
|
133
|
-
theme={webDarkTheme}
|
|
134
|
-
/>
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Data Structure
|
|
138
|
-
|
|
139
|
-
The component expects data in the following format:
|
|
140
|
-
|
|
141
|
-
```tsx
|
|
142
|
-
interface ChartData<T> {
|
|
143
|
-
label: string; // Series name (appears in legend)
|
|
144
|
-
data: T[]; // Array of data points
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
Each data point `T` should contain:
|
|
149
|
-
- A primary value (x-axis) - can be string or number
|
|
150
|
-
- A secondary value (y-axis) - must be number
|
|
151
|
-
|
|
152
|
-
## Styling
|
|
153
|
-
|
|
154
|
-
The component uses Fluent UI theme tokens for consistent styling:
|
|
155
|
-
|
|
156
|
-
- **Colors**: Automatically generated from theme palette
|
|
157
|
-
- **Typography**: Uses theme font families and sizes
|
|
158
|
-
- **Spacing**: Follows Fluent UI spacing guidelines
|
|
159
|
-
- **Interaction**: Hover states and animations
|
|
160
|
-
|
|
161
|
-
## Interactive Features
|
|
162
|
-
|
|
163
|
-
### Legend Interaction
|
|
164
|
-
- Click legend items to toggle series visibility
|
|
165
|
-
- At least one series must remain visible
|
|
166
|
-
- Colors are automatically assigned from the theme palette
|
|
167
|
-
|
|
168
|
-
### Responsive Behavior
|
|
169
|
-
- Chart automatically resizes to fit container
|
|
170
|
-
- Legend adapts to available space
|
|
171
|
-
- Maintains aspect ratio and readability
|
|
172
|
-
|
|
173
|
-
## Performance Considerations
|
|
174
|
-
|
|
175
|
-
The component uses React optimization techniques:
|
|
176
|
-
- `useMemo` for expensive calculations
|
|
177
|
-
- `useCallback` for event handlers
|
|
178
|
-
- Efficient re-rendering when data changes
|
|
179
|
-
|
|
180
|
-
## Browser Support
|
|
181
|
-
|
|
182
|
-
- Modern browsers with ES6+ support
|
|
183
|
-
- Canvas API required for Chart.js
|
|
184
|
-
- ResizeObserver for responsive features
|
|
185
|
-
|
|
186
|
-
## Examples
|
|
187
|
-
|
|
188
|
-
### Time Series Data
|
|
189
|
-
```tsx
|
|
190
|
-
interface TimeSeriesData {
|
|
191
|
-
timestamp: Date;
|
|
192
|
-
value: number;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
<AreaChart
|
|
196
|
-
data={[{ label: 'Temperature', data: temperatureData }]}
|
|
197
|
-
getPrimary={(datum) => datum.timestamp.toLocaleDateString()}
|
|
198
|
-
getSecondary={(datum) => datum.value}
|
|
199
|
-
title="Temperature Over Time"
|
|
200
|
-
/>
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### Percentage Data
|
|
204
|
-
```tsx
|
|
205
|
-
interface PercentageData {
|
|
206
|
-
category: string;
|
|
207
|
-
percentage: number;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
<AreaChart
|
|
211
|
-
data={[{ label: 'Market Share', data: marketData }]}
|
|
212
|
-
getPrimary={(datum) => datum.category}
|
|
213
|
-
getSecondary={(datum) => datum.percentage}
|
|
214
|
-
title="Market Share Distribution"
|
|
215
|
-
showDatalabels={true}
|
|
216
|
-
/>
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## Troubleshooting
|
|
220
|
-
|
|
221
|
-
### Common Issues
|
|
222
|
-
|
|
223
|
-
1. **Chart not rendering**: Ensure container has explicit width and height
|
|
224
|
-
2. **Data not showing**: Check that `getPrimary` and `getSecondary` return valid values
|
|
225
|
-
3. **Legend overlapping**: Increase container width or adjust legend positioning
|
|
226
|
-
4. **Theme not applied**: Verify theme object is properly imported and passed
|
|
227
|
-
|
|
228
|
-
### Performance Tips
|
|
229
|
-
|
|
230
|
-
- Limit data points for better performance (< 1000 points recommended)
|
|
231
|
-
- Use `useMemo` when transforming data props
|
|
232
|
-
- Consider virtualization for very large datasets
|
|
233
|
-
|
|
234
|
-
## License
|
|
235
|
-
|
|
236
|
-
This component is part of the FluentUI React Graphs library.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './AreaChart';
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BarElement,
|
|
3
|
-
CategoryScale,
|
|
4
|
-
Chart as ChartJS,
|
|
5
|
-
ChartOptions,
|
|
6
|
-
Legend,
|
|
7
|
-
LinearScale,
|
|
8
|
-
Title,
|
|
9
|
-
Tooltip,
|
|
10
|
-
} from 'chart.js';
|
|
11
|
-
import React, { useMemo, useState } from 'react';
|
|
12
|
-
|
|
13
|
-
import { Bar } from 'react-chartjs-2';
|
|
14
|
-
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
15
|
-
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
16
|
-
import { Theme } from '@fluentui/react-theme';
|
|
17
|
-
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
18
|
-
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
19
|
-
|
|
20
|
-
ChartJS.register(
|
|
21
|
-
CategoryScale,
|
|
22
|
-
LinearScale,
|
|
23
|
-
BarElement,
|
|
24
|
-
Tooltip,
|
|
25
|
-
Legend,
|
|
26
|
-
Title,
|
|
27
|
-
ChartDataLabels,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export interface BarHorizontalProps<T> {
|
|
35
|
-
data: { label: string; data: T[] }[];
|
|
36
|
-
getPrimary: (datum: T) => string | number;
|
|
37
|
-
getSecondary: (datum: T) => number;
|
|
38
|
-
stacked?: boolean;
|
|
39
|
-
title?: string;
|
|
40
|
-
showDatalabels?: boolean;
|
|
41
|
-
theme: Theme;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default function BarHorizontalChart<T extends object>({
|
|
45
|
-
data,
|
|
46
|
-
getPrimary,
|
|
47
|
-
getSecondary,
|
|
48
|
-
stacked = false,
|
|
49
|
-
showDatalabels = false,
|
|
50
|
-
title,
|
|
51
|
-
theme
|
|
52
|
-
}: BarHorizontalProps<T>) {
|
|
53
|
-
const [visibleSeries, setVisibleSeries] = useState(() =>
|
|
54
|
-
data.length > 1 ? data.map(s => s.label) : [data[0]?.label]
|
|
55
|
-
);
|
|
56
|
-
const styles = useGraphGlobalStyles();
|
|
57
|
-
|
|
58
|
-
const { lightenColor, getFluentPalette , createFluentTooltip} = useChartUtils(theme);
|
|
59
|
-
|
|
60
|
-
const seriesColors = useMemo(() => {
|
|
61
|
-
return data.reduce((acc, series, idx) => {
|
|
62
|
-
const base = getFluentPalette(theme)[
|
|
63
|
-
idx % getFluentPalette(theme).length
|
|
64
|
-
];
|
|
65
|
-
const color = lightenColor(base, 0.3);
|
|
66
|
-
acc[series.label] = color;
|
|
67
|
-
return acc;
|
|
68
|
-
}, {} as Record<string, string>);
|
|
69
|
-
}, [data]);
|
|
70
|
-
|
|
71
|
-
const toggleSeries = (label: string) => {
|
|
72
|
-
setVisibleSeries(prev => {
|
|
73
|
-
const isVisible = prev.includes(label);
|
|
74
|
-
const next = isVisible ? prev.filter(l => l !== label) : [...prev, label];
|
|
75
|
-
return next.length === 0 && data.length > 0 ? [data[0].label] : next;
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const allCategories = useMemo(() => {
|
|
80
|
-
const categorySet = new Set<string | number>();
|
|
81
|
-
data.forEach(series => {
|
|
82
|
-
series.data.forEach(datum => {
|
|
83
|
-
categorySet.add(getPrimary(datum));
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
return Array.from(categorySet);
|
|
87
|
-
}, [data, getPrimary]);
|
|
88
|
-
|
|
89
|
-
const chartData = useMemo(() => {
|
|
90
|
-
return {
|
|
91
|
-
labels: allCategories,
|
|
92
|
-
datasets: data
|
|
93
|
-
.filter(series => visibleSeries.includes(series.label))
|
|
94
|
-
.map(series => ({
|
|
95
|
-
label: series.label,
|
|
96
|
-
backgroundColor: seriesColors[series.label],
|
|
97
|
-
data: allCategories.map(cat => {
|
|
98
|
-
const found = series.data.find(d => getPrimary(d) === cat);
|
|
99
|
-
return found ? getSecondary(found) : 0;
|
|
100
|
-
}),
|
|
101
|
-
})),
|
|
102
|
-
};
|
|
103
|
-
}, [data, visibleSeries, allCategories, seriesColors]);
|
|
104
|
-
|
|
105
|
-
const { fontFamily, fontSize, labelColor, gridColor } = useMemo(() => ({
|
|
106
|
-
fontFamily: theme.fontFamilyBase,
|
|
107
|
-
fontSize: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
108
|
-
labelColor: theme.colorNeutralForeground1,
|
|
109
|
-
gridColor: theme.colorNeutralStroke2,
|
|
110
|
-
}), [theme]);
|
|
111
|
-
|
|
112
|
-
const options: ChartOptions<'bar'> = useMemo(() => ({
|
|
113
|
-
indexAxis: 'y',
|
|
114
|
-
responsive: true,
|
|
115
|
-
maintainAspectRatio: false,
|
|
116
|
-
plugins: {
|
|
117
|
-
title: {
|
|
118
|
-
display: !!title,
|
|
119
|
-
text: title,
|
|
120
|
-
font: {
|
|
121
|
-
size: 14,
|
|
122
|
-
family: theme.fontFamilyBase,
|
|
123
|
-
weight: theme.fontWeightSemibold,
|
|
124
|
-
},
|
|
125
|
-
color: theme.colorNeutralForeground1,
|
|
126
|
-
padding: {
|
|
127
|
-
top: 20,
|
|
128
|
-
bottom: 20,
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
datalabels: {
|
|
132
|
-
display: showDatalabels,
|
|
133
|
-
color: theme.colorNeutralForeground1,
|
|
134
|
-
font: {
|
|
135
|
-
family: theme.fontFamilyBase,
|
|
136
|
-
size: parseInt(theme.fontSizeBase200.replace('px', '')) || 14,
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
legend: {
|
|
140
|
-
display: false,
|
|
141
|
-
},
|
|
142
|
-
tooltip: createFluentTooltip<'bar'>(theme),
|
|
143
|
-
},
|
|
144
|
-
scales: {
|
|
145
|
-
x: {
|
|
146
|
-
stacked,
|
|
147
|
-
ticks: {
|
|
148
|
-
color: labelColor,
|
|
149
|
-
font: {
|
|
150
|
-
family: fontFamily,
|
|
151
|
-
size: fontSize,
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
grid: {
|
|
155
|
-
color: gridColor,
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
y: {
|
|
159
|
-
stacked,
|
|
160
|
-
ticks: {
|
|
161
|
-
color: labelColor,
|
|
162
|
-
font: {
|
|
163
|
-
family: fontFamily,
|
|
164
|
-
size: fontSize,
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
grid: {
|
|
168
|
-
color: gridColor,
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
}), [
|
|
173
|
-
title,
|
|
174
|
-
showDatalabels,
|
|
175
|
-
theme,
|
|
176
|
-
fontFamily,
|
|
177
|
-
fontSize,
|
|
178
|
-
labelColor,
|
|
179
|
-
gridColor,
|
|
180
|
-
stacked,
|
|
181
|
-
createFluentTooltip,
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<div className={styles.chartWithLegend}>
|
|
186
|
-
<div className={styles.chartArea}>
|
|
187
|
-
<Bar data={chartData} options={options} />
|
|
188
|
-
</div>
|
|
189
|
-
<div className={styles.legendArea} >
|
|
190
|
-
<RenderLegend
|
|
191
|
-
data={data}
|
|
192
|
-
visibleSeries={visibleSeries}
|
|
193
|
-
seriesColors={seriesColors}
|
|
194
|
-
toggleSeries={toggleSeries}
|
|
195
|
-
/>
|
|
196
|
-
</div>
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
);
|
|
200
|
-
}
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
# BarHorizontalChart Component
|
|
2
|
-
|
|
3
|
-
A flexible horizontal bar chart component built with Chart.js and Fluent UI React. This component displays data as horizontal bars, making it ideal for displaying categories with longer names or when you want to emphasize the comparison of values across different categories.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Horizontal Orientation**: Bars extend horizontally for better readability of category labels
|
|
8
|
-
- **Multiple Series Support**: Display multiple data series with different colors
|
|
9
|
-
- **Interactive Legend**: Toggle series visibility with click interactions
|
|
10
|
-
- **Stacked Charts**: Option to stack bars for comparative analysis
|
|
11
|
-
- **Fluent UI Integration**: Seamless integration with Fluent UI themes and design system
|
|
12
|
-
- **Data Labels**: Optional display of values directly on chart elements
|
|
13
|
-
- **Responsive Design**: Automatically adapts to container dimensions
|
|
14
|
-
- **TypeScript Support**: Full TypeScript support with generic types
|
|
15
|
-
- **Custom Tooltips**: Fluent UI styled tooltips with rich information
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install chart.js react-chartjs-2 chartjs-plugin-datalabels @fluentui/react-components
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Basic Usage
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
import React from 'react';
|
|
27
|
-
import { BarHorizontalChart } from './components/barHorizontalChart/BarHorizontalChart';
|
|
28
|
-
import { webLightTheme } from '@fluentui/react-components';
|
|
29
|
-
|
|
30
|
-
interface ProductData {
|
|
31
|
-
product: string;
|
|
32
|
-
sales: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const salesData: ProductData[] = [
|
|
36
|
-
{ product: 'Laptop Computers', sales: 15000 },
|
|
37
|
-
{ product: 'Desktop Computers', sales: 8000 },
|
|
38
|
-
{ product: 'Tablets', sales: 12000 },
|
|
39
|
-
{ product: 'Smartphones', sales: 25000 },
|
|
40
|
-
{ product: 'Smart Watches', sales: 6000 },
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
function App() {
|
|
44
|
-
return (
|
|
45
|
-
<div style={{ width: '800px', height: '400px' }}>
|
|
46
|
-
<BarHorizontalChart
|
|
47
|
-
data={[
|
|
48
|
-
{ label: 'Product Sales', data: salesData }
|
|
49
|
-
]}
|
|
50
|
-
getPrimary={(datum) => datum.product}
|
|
51
|
-
getSecondary={(datum) => datum.sales}
|
|
52
|
-
title="Product Sales Performance"
|
|
53
|
-
theme={webLightTheme}
|
|
54
|
-
/>
|
|
55
|
-
</div>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Props
|
|
61
|
-
|
|
62
|
-
### BarHorizontalProps<T>
|
|
63
|
-
|
|
64
|
-
| Prop | Type | Required | Default | Description |
|
|
65
|
-
|------|------|----------|---------|-------------|
|
|
66
|
-
| `data` | `{ label: string; data: T[] }[]` | Yes | - | Array of data series with labels and data points |
|
|
67
|
-
| `getPrimary` | `(datum: T) => string \| number` | Yes | - | Function to extract the y-axis category from each data point |
|
|
68
|
-
| `getSecondary` | `(datum: T) => number` | Yes | - | Function to extract the x-axis value from each data point |
|
|
69
|
-
| `stacked` | `boolean` | No | `false` | Whether to stack the bars horizontally |
|
|
70
|
-
| `title` | `string` | No | - | Chart title displayed at the top |
|
|
71
|
-
| `showDatalabels` | `boolean` | No | `false` | Whether to show data values on chart elements |
|
|
72
|
-
| `theme` | `Theme` | Yes | - | Fluent UI theme object for styling |
|
|
73
|
-
|
|
74
|
-
## Advanced Usage
|
|
75
|
-
|
|
76
|
-
### Multiple Series Comparison
|
|
77
|
-
|
|
78
|
-
```tsx
|
|
79
|
-
interface RegionData {
|
|
80
|
-
region: string;
|
|
81
|
-
q1Sales: number;
|
|
82
|
-
q2Sales: number;
|
|
83
|
-
q3Sales: number;
|
|
84
|
-
q4Sales: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const regionData: RegionData[] = [
|
|
88
|
-
{ region: 'North America', q1Sales: 120000, q2Sales: 135000, q3Sales: 125000, q4Sales: 150000 },
|
|
89
|
-
{ region: 'Europe', q1Sales: 95000, q2Sales: 105000, q3Sales: 98000, q4Sales: 115000 },
|
|
90
|
-
{ region: 'Asia Pacific', q1Sales: 85000, q2Sales: 92000, q3Sales: 88000, q4Sales: 105000 },
|
|
91
|
-
{ region: 'Latin America', q1Sales: 45000, q2Sales: 52000, q3Sales: 48000, q4Sales: 58000 },
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
<BarHorizontalChart
|
|
95
|
-
data={[
|
|
96
|
-
{
|
|
97
|
-
label: 'Q1 2024',
|
|
98
|
-
data: regionData.map(d => ({ region: d.region, value: d.q1Sales }))
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
label: 'Q2 2024',
|
|
102
|
-
data: regionData.map(d => ({ region: d.region, value: d.q2Sales }))
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
label: 'Q3 2024',
|
|
106
|
-
data: regionData.map(d => ({ region: d.region, value: d.q3Sales }))
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
label: 'Q4 2024',
|
|
110
|
-
data: regionData.map(d => ({ region: d.region, value: d.q4Sales }))
|
|
111
|
-
}
|
|
112
|
-
]}
|
|
113
|
-
getPrimary={(datum) => datum.region}
|
|
114
|
-
getSecondary={(datum) => datum.value}
|
|
115
|
-
title="Quarterly Sales by Region"
|
|
116
|
-
showDatalabels={true}
|
|
117
|
-
theme={webLightTheme}
|
|
118
|
-
/>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Stacked Horizontal Bars
|
|
122
|
-
|
|
123
|
-
```tsx
|
|
124
|
-
interface BudgetData {
|
|
125
|
-
department: string;
|
|
126
|
-
allocated: number;
|
|
127
|
-
spent: number;
|
|
128
|
-
remaining: number;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
<BarHorizontalChart
|
|
132
|
-
data={[
|
|
133
|
-
{ label: 'Allocated', data: budgetData },
|
|
134
|
-
{ label: 'Spent', data: budgetData },
|
|
135
|
-
{ label: 'Remaining', data: budgetData }
|
|
136
|
-
]}
|
|
137
|
-
getPrimary={(datum) => datum.department}
|
|
138
|
-
getSecondary={(datum) => datum.allocated} // or spent/remaining based on series
|
|
139
|
-
stacked={true}
|
|
140
|
-
title="Department Budget Analysis"
|
|
141
|
-
theme={webLightTheme}
|
|
142
|
-
/>
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Survey Results Visualization
|
|
146
|
-
|
|
147
|
-
```tsx
|
|
148
|
-
interface SurveyData {
|
|
149
|
-
question: string;
|
|
150
|
-
stronglyAgree: number;
|
|
151
|
-
agree: number;
|
|
152
|
-
neutral: number;
|
|
153
|
-
disagree: number;
|
|
154
|
-
stronglyDisagree: number;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
<BarHorizontalChart
|
|
158
|
-
data={[
|
|
159
|
-
{ label: 'Strongly Agree', data: surveyData },
|
|
160
|
-
{ label: 'Agree', data: surveyData },
|
|
161
|
-
{ label: 'Neutral', data: surveyData },
|
|
162
|
-
{ label: 'Disagree', data: surveyData },
|
|
163
|
-
{ label: 'Strongly Disagree', data: surveyData }
|
|
164
|
-
]}
|
|
165
|
-
getPrimary={(datum) => datum.question}
|
|
166
|
-
getSecondary={(datum) => datum.stronglyAgree} // adjust per series
|
|
167
|
-
stacked={true}
|
|
168
|
-
title="Customer Satisfaction Survey Results"
|
|
169
|
-
showDatalabels={true}
|
|
170
|
-
theme={webLightTheme}
|
|
171
|
-
/>
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## When to Use Horizontal Bar Charts
|
|
175
|
-
|
|
176
|
-
Horizontal bar charts are particularly effective for:
|
|
177
|
-
|
|
178
|
-
### Long Category Names
|
|
179
|
-
|
|
180
|
-
```tsx
|
|
181
|
-
// Perfect for lengthy category labels
|
|
182
|
-
const categoryData = [
|
|
183
|
-
{ category: 'Enterprise Software Solutions', value: 450000 },
|
|
184
|
-
{ category: 'Cloud Infrastructure Services', value: 380000 },
|
|
185
|
-
{ category: 'Cybersecurity and Compliance', value: 290000 },
|
|
186
|
-
{ category: 'Data Analytics and Business Intelligence', value: 320000 },
|
|
187
|
-
];
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Ranking and Comparison
|
|
191
|
-
|
|
192
|
-
```tsx
|
|
193
|
-
// Great for showing rankings
|
|
194
|
-
const performanceData = [
|
|
195
|
-
{ employee: 'Alice Johnson - Senior Developer', score: 95 },
|
|
196
|
-
{ employee: 'Bob Smith - Product Manager', score: 88 },
|
|
197
|
-
{ employee: 'Carol Davis - UX Designer', score: 92 },
|
|
198
|
-
{ employee: 'David Wilson - DevOps Engineer', score: 85 },
|
|
199
|
-
];
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Progress Tracking
|
|
203
|
-
|
|
204
|
-
```tsx
|
|
205
|
-
// Ideal for progress visualization
|
|
206
|
-
const projectProgress = [
|
|
207
|
-
{ phase: 'Requirements Gathering', completion: 100 },
|
|
208
|
-
{ phase: 'Design & Architecture', completion: 85 },
|
|
209
|
-
{ phase: 'Development', completion: 60 },
|
|
210
|
-
{ phase: 'Testing & QA', completion: 25 },
|
|
211
|
-
{ phase: 'Deployment', completion: 0 },
|
|
212
|
-
];
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## Data Structure
|
|
216
|
-
|
|
217
|
-
The component expects data in the following format:
|
|
218
|
-
|
|
219
|
-
```tsx
|
|
220
|
-
interface ChartSeries<T> {
|
|
221
|
-
label: string; // Series name (appears in legend)
|
|
222
|
-
data: T[]; // Array of data points
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Each data point `T` should contain:
|
|
227
|
-
|
|
228
|
-
- A primary value (y-axis category) - string or number
|
|
229
|
-
- A secondary value (x-axis value) - number
|
|
230
|
-
|
|
231
|
-
## Styling and Theme Integration
|
|
232
|
-
|
|
233
|
-
The component automatically applies Fluent UI theme styles:
|
|
234
|
-
|
|
235
|
-
```tsx
|
|
236
|
-
// Typography
|
|
237
|
-
fontFamily: theme.fontFamilyBase
|
|
238
|
-
fontSize: theme.fontSizeBase200
|
|
239
|
-
fontWeight: theme.fontWeightSemibold
|
|
240
|
-
|
|
241
|
-
// Colors
|
|
242
|
-
labelColor: theme.colorNeutralForeground1
|
|
243
|
-
gridColor: theme.colorNeutralStroke2
|
|
244
|
-
seriesColors: Derived from theme palette
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Interactive Features
|
|
248
|
-
|
|
249
|
-
### Legend Controls
|
|
250
|
-
|
|
251
|
-
- Click legend items to show/hide data series
|
|
252
|
-
- Visual feedback on hover states
|
|
253
|
-
- At least one series must remain visible
|
|
254
|
-
- Colors automatically assigned from theme palette
|
|
255
|
-
|
|
256
|
-
### Responsive Layout
|
|
257
|
-
|
|
258
|
-
- Chart automatically resizes to container dimensions
|
|
259
|
-
- Legend positioning adapts to available space
|
|
260
|
-
- Maintains readability across different screen sizes
|
|
261
|
-
|
|
262
|
-
## Performance Optimizations
|
|
263
|
-
|
|
264
|
-
The component includes several React optimizations:
|
|
265
|
-
|
|
266
|
-
````tsx
|
|
267
|
-
// Memoized calculations
|
|
268
|
-
const seriesColors = useMemo(() => {
|
|
269
|
-
// Color calculation logic
|
|
270
|
-
}, [data, theme]);
|
|
271
|
-
|
|
272
|
-
const chartData = useMemo(() => {
|
|
273
|
-
// Chart data transformation
|
|
274
|
-
}, [data, visibleSeries, allCategories, seriesColors]);
|
|
275
|
-
|
|
276
|
-
const options = useMemo(() => {
|
|
277
|
-
// Chart options configuration
|
|
278
|
-
}, [title, showDatalabels, theme, ...]);
|