@spteck/fluentui-react-charts 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -409,6 +409,261 @@ const metricsData = [
|
|
|
409
409
|
|
|
410
410
|
*Interactive chart components with Fluent UI design system
|
|
411
411
|
|
|
412
|
+
## 📊 Dashboard Component
|
|
413
|
+
|
|
414
|
+
The Dashboard component provides a sophisticated grid-based layout for displaying multiple charts with drag & drop reordering and resizable grid spanning.
|
|
415
|
+
|
|
416
|
+
### Features
|
|
417
|
+
|
|
418
|
+
- **Grid-based Layout**: Responsive grid system with automatic column calculation
|
|
419
|
+
- **Drag & Drop**: Reorder charts by dragging and dropping
|
|
420
|
+
- **Grid Spanning**: Charts can span multiple columns and rows
|
|
421
|
+
- **Zoom Controls**: Interactive zoom controls for resizing chart containers
|
|
422
|
+
- **Responsive**: Automatically adapts to container width
|
|
423
|
+
- **Theme Integration**: Full Fluent UI theme support
|
|
424
|
+
|
|
425
|
+
### Basic Usage
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
import React from 'react';
|
|
429
|
+
import { Dashboard } from '@spteck/fluentui-react-charts';
|
|
430
|
+
import { webLightTheme } from '@fluentui/react-components';
|
|
431
|
+
|
|
432
|
+
// Define your chart containers
|
|
433
|
+
const chartContainers = [
|
|
434
|
+
{
|
|
435
|
+
id: '1',
|
|
436
|
+
cardTitle: 'Monthly Sales',
|
|
437
|
+
chart: {
|
|
438
|
+
id: '1',
|
|
439
|
+
title: 'Sales Performance',
|
|
440
|
+
type: 'line',
|
|
441
|
+
data: [{
|
|
442
|
+
label: 'Sales',
|
|
443
|
+
data: [
|
|
444
|
+
{ name: 'Jan', value: 10000 },
|
|
445
|
+
{ name: 'Feb', value: 15000 },
|
|
446
|
+
{ name: 'Mar', value: 12000 },
|
|
447
|
+
{ name: 'Apr', value: 18000 },
|
|
448
|
+
]
|
|
449
|
+
}],
|
|
450
|
+
},
|
|
451
|
+
defaultSpan: { spanCols: 2, spanRows: 1 },
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
id: '2',
|
|
455
|
+
cardTitle: 'Revenue Distribution',
|
|
456
|
+
chart: {
|
|
457
|
+
id: '2',
|
|
458
|
+
title: 'Q2 Revenue',
|
|
459
|
+
type: 'pie',
|
|
460
|
+
data: [{
|
|
461
|
+
label: 'Revenue',
|
|
462
|
+
data: [
|
|
463
|
+
{ name: 'Product A', value: 35000 },
|
|
464
|
+
{ name: 'Product B', value: 25000 },
|
|
465
|
+
{ name: 'Product C', value: 18000 },
|
|
466
|
+
{ name: 'Services', value: 15000 },
|
|
467
|
+
]
|
|
468
|
+
}],
|
|
469
|
+
},
|
|
470
|
+
defaultSpan: { spanCols: 1, spanRows: 1 },
|
|
471
|
+
},
|
|
472
|
+
];
|
|
473
|
+
|
|
474
|
+
function MyDashboard() {
|
|
475
|
+
return (
|
|
476
|
+
<div style={{ width: '100%', height: '100vh' }}>
|
|
477
|
+
<Dashboard
|
|
478
|
+
cardCharts={chartContainers}
|
|
479
|
+
theme={webLightTheme}
|
|
480
|
+
containerWidth={1200}
|
|
481
|
+
containerHeight={800}
|
|
482
|
+
/>
|
|
483
|
+
</div>
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Advanced Dashboard Example
|
|
489
|
+
|
|
490
|
+
```tsx
|
|
491
|
+
import React, { useState, useEffect } from 'react';
|
|
492
|
+
import { Dashboard } from '@spteck/fluentui-react-charts';
|
|
493
|
+
import { webDarkTheme, tokens, Text } from '@fluentui/react-components';
|
|
494
|
+
|
|
495
|
+
function AdvancedDashboard() {
|
|
496
|
+
const [containerWidth, setContainerWidth] = useState(1200);
|
|
497
|
+
|
|
498
|
+
// Sample data for multiple charts
|
|
499
|
+
const salesData = [
|
|
500
|
+
{ month: 'Jan', sales: 10000, expenses: 8000 },
|
|
501
|
+
{ month: 'Feb', sales: 15000, expenses: 9000 },
|
|
502
|
+
{ month: 'Mar', sales: 12000, expenses: 7500 },
|
|
503
|
+
{ month: 'Apr', sales: 18000, expenses: 10000 },
|
|
504
|
+
{ month: 'May', sales: 16000, expenses: 8500 },
|
|
505
|
+
{ month: 'Jun', sales: 22000, expenses: 11000 },
|
|
506
|
+
];
|
|
507
|
+
|
|
508
|
+
const chartContainers = [
|
|
509
|
+
{
|
|
510
|
+
id: 'sales-trend',
|
|
511
|
+
cardTitle: 'Sales Trend',
|
|
512
|
+
chart: {
|
|
513
|
+
id: 'sales-trend',
|
|
514
|
+
title: 'Monthly Sales Performance',
|
|
515
|
+
type: 'line',
|
|
516
|
+
data: [{
|
|
517
|
+
label: 'Sales',
|
|
518
|
+
data: salesData.map(d => ({ name: d.month, value: d.sales }))
|
|
519
|
+
}],
|
|
520
|
+
},
|
|
521
|
+
defaultSpan: { spanCols: 2, spanRows: 1 },
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
id: 'sales-vs-expenses',
|
|
525
|
+
cardTitle: 'Financial Overview',
|
|
526
|
+
chart: {
|
|
527
|
+
id: 'sales-vs-expenses',
|
|
528
|
+
title: 'Sales vs Expenses',
|
|
529
|
+
type: 'bar',
|
|
530
|
+
data: [
|
|
531
|
+
{
|
|
532
|
+
label: 'Sales',
|
|
533
|
+
data: salesData.map(d => ({ name: d.month, value: d.sales }))
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
label: 'Expenses',
|
|
537
|
+
data: salesData.map(d => ({ name: d.month, value: d.expenses }))
|
|
538
|
+
}
|
|
539
|
+
],
|
|
540
|
+
},
|
|
541
|
+
defaultSpan: { spanCols: 2, spanRows: 2 },
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
id: 'revenue-breakdown',
|
|
545
|
+
cardTitle: 'Revenue Breakdown',
|
|
546
|
+
chart: {
|
|
547
|
+
id: 'revenue-breakdown',
|
|
548
|
+
title: 'Revenue by Category',
|
|
549
|
+
type: 'doughnut',
|
|
550
|
+
data: [{
|
|
551
|
+
label: 'Revenue',
|
|
552
|
+
data: [
|
|
553
|
+
{ name: 'Product A', value: 35000 },
|
|
554
|
+
{ name: 'Product B', value: 25000 },
|
|
555
|
+
{ name: 'Product C', value: 18000 },
|
|
556
|
+
{ name: 'Services', value: 15000 },
|
|
557
|
+
]
|
|
558
|
+
}],
|
|
559
|
+
},
|
|
560
|
+
defaultSpan: { spanCols: 1, spanRows: 1 },
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
id: 'growth-trend',
|
|
564
|
+
cardTitle: 'Growth Analysis',
|
|
565
|
+
chart: {
|
|
566
|
+
id: 'growth-trend',
|
|
567
|
+
title: 'Monthly Growth Rate',
|
|
568
|
+
type: 'area',
|
|
569
|
+
data: [{
|
|
570
|
+
label: 'Growth',
|
|
571
|
+
data: salesData.map(d => {
|
|
572
|
+
const growthPercentage = ((d.sales - d.expenses) / d.expenses * 100);
|
|
573
|
+
return { name: d.month, value: Number(growthPercentage.toFixed(1)) };
|
|
574
|
+
})
|
|
575
|
+
}],
|
|
576
|
+
},
|
|
577
|
+
defaultSpan: { spanCols: 2, spanRows: 1 },
|
|
578
|
+
},
|
|
579
|
+
];
|
|
580
|
+
|
|
581
|
+
// Handle responsive container width
|
|
582
|
+
useEffect(() => {
|
|
583
|
+
const handleResize = () => {
|
|
584
|
+
setContainerWidth(window.innerWidth - 40); // Account for padding
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
window.addEventListener('resize', handleResize);
|
|
588
|
+
handleResize(); // Initial call
|
|
589
|
+
|
|
590
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
591
|
+
}, []);
|
|
592
|
+
|
|
593
|
+
return (
|
|
594
|
+
<div style={{
|
|
595
|
+
padding: tokens.spacingHorizontalXL,
|
|
596
|
+
backgroundColor: tokens.colorNeutralBackground1,
|
|
597
|
+
minHeight: '100vh'
|
|
598
|
+
}}>
|
|
599
|
+
<Text
|
|
600
|
+
|
|
601
|
+
size={900}
|
|
602
|
+
weight="bold"
|
|
603
|
+
style={{
|
|
604
|
+
color: tokens.colorNeutralForeground1,
|
|
605
|
+
marginBottom: tokens.spacingVerticalL,
|
|
606
|
+
display: 'block'
|
|
607
|
+
}}
|
|
608
|
+
>
|
|
609
|
+
Analytics Dashboard
|
|
610
|
+
</Text>
|
|
611
|
+
<Dashboard
|
|
612
|
+
cardCharts={chartContainers}
|
|
613
|
+
theme={webDarkTheme}
|
|
614
|
+
containerWidth={containerWidth}
|
|
615
|
+
containerHeight={600}
|
|
616
|
+
/>
|
|
617
|
+
</div>
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Dashboard Props
|
|
623
|
+
|
|
624
|
+
| Prop | Type | Required | Description |
|
|
625
|
+
|------|------|----------|-------------|
|
|
626
|
+
| `cardCharts` | `ICardChartContainer[]` | ✅ | Array of chart container configurations |
|
|
627
|
+
| `theme` | `Theme` | ✅ | Fluent UI theme object |
|
|
628
|
+
| `containerWidth` | `number` | ✅ | Width of the dashboard container in pixels |
|
|
629
|
+
| `containerHeight` | `number` | ✅ | Height of the dashboard container in pixels |
|
|
630
|
+
|
|
631
|
+
### ICardChartContainer Interface
|
|
632
|
+
|
|
633
|
+
```tsx
|
|
634
|
+
interface ICardChartContainer {
|
|
635
|
+
id: string; // Unique identifier for the chart container
|
|
636
|
+
cardTitle: string; // Title displayed in the card header
|
|
637
|
+
chart: IChart; // Chart configuration object
|
|
638
|
+
showZoom?: boolean; // Whether to show zoom controls (optional)
|
|
639
|
+
defaultSpan?: { // Default grid spanning (optional)
|
|
640
|
+
spanCols: number; // Number of columns to span (1-4)
|
|
641
|
+
spanRows: number; // Number of rows to span (1-4)
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Dashboard Features
|
|
647
|
+
|
|
648
|
+
#### Grid Spanning
|
|
649
|
+
|
|
650
|
+
Charts can span multiple grid cells for larger visualizations:
|
|
651
|
+
|
|
652
|
+
- `spanCols`: 1-4 columns
|
|
653
|
+
- `spanRows`: 1-4 rows
|
|
654
|
+
|
|
655
|
+
#### Responsive Behavior
|
|
656
|
+
|
|
657
|
+
- Grid automatically calculates columns based on container width
|
|
658
|
+
- Zoom controls are hidden on mobile devices (width < 600px)
|
|
659
|
+
- Charts automatically resize to fit their containers
|
|
660
|
+
|
|
661
|
+
#### Drag & Drop
|
|
662
|
+
|
|
663
|
+
- Click and drag any chart card to reorder
|
|
664
|
+
- Visual feedback during drag operations
|
|
665
|
+
- Smooth animations and transitions
|
|
666
|
+
|
|
412
667
|
## 🎨 Theming
|
|
413
668
|
|
|
414
669
|
All charts support Fluent UI themes for consistent styling:
|