1
- import { BarChart , Card , Subtitle , Title } from '@tremor/react' ;
1
+ import { Card , Subtitle , Title } from '@tremor/react' ;
2
+ import { ChartTypeRegistry , TooltipItem } from 'chart.js' ;
3
+ import { useMemo } from 'react' ;
4
+ import { Bar } from 'react-chartjs-2' ;
5
+ import { valueFormatter , getColor } from '@/components/analytics/helpers' ;
2
6
import ExportButton from '@/components/buttons/ExportButton' ;
3
7
4
- const valueFormatter = ( number : number ) => `${ new Intl . NumberFormat ( 'us' ) . format ( number ) . toString ( ) } %` ;
5
-
6
8
export default function Histogram ( {
7
9
index,
8
10
onExport,
@@ -22,22 +24,91 @@ export default function Histogram({
22
24
categories : string [ ] ;
23
25
colors : string [ ] ;
24
26
} ) {
27
+ const { data, options } = useMemo ( ( ) => {
28
+ if ( ! chartData ) return { data : { labels : [ ] , datasets : [ ] } , options : { } } ;
29
+
30
+ const labels : string [ ] = [ ] ;
31
+ const datasetMap : Record < string , number [ ] > = { } ;
32
+
33
+ for ( const row of chartData ) {
34
+ for ( const [ key , value ] of Object . entries ( row ) ) {
35
+ if ( key === 'time' ) {
36
+ labels . push ( String ( value ) ) ;
37
+ continue ;
38
+ }
39
+
40
+ if ( ! datasetMap [ key ] ) {
41
+ datasetMap [ key ] = [ ] ;
42
+ }
43
+
44
+ datasetMap [ key ] . push ( Number ( value ) ) ;
45
+ }
46
+ }
47
+
48
+ const _data = {
49
+ labels,
50
+ datasets : Object . entries ( datasetMap ) . map ( ( [ label , data ] , index ) => ( {
51
+ label,
52
+ data,
53
+ backgroundColor : getColor ( index ) ,
54
+ borderRadius : 4 ,
55
+ barThickness : 'flex' as const ,
56
+ } ) ) ,
57
+ } ;
58
+
59
+ const _options = {
60
+ responsive : true ,
61
+ maintainAspectRatio : true ,
62
+ interaction : {
63
+ mode : 'index' as const ,
64
+ intersect : false ,
65
+ } ,
66
+ plugins : {
67
+ legend : {
68
+ position : 'top' as const ,
69
+ } ,
70
+ title : {
71
+ display : false ,
72
+ text : '' ,
73
+ } ,
74
+ tooltip : {
75
+ callbacks : {
76
+ label : function ( context : TooltipItem < keyof ChartTypeRegistry > ) {
77
+ const label = context . dataset . label || 'Unknown' ;
78
+ const value = valueFormatter ( Number ( context . raw as number ) ) ;
79
+ return `${ label } : ${ value } ` ;
80
+ } ,
81
+ } ,
82
+ } ,
83
+ } ,
84
+ scales : {
85
+ x : {
86
+ ticks : {
87
+ autoSkip : true ,
88
+ maxRotation : 0 ,
89
+ minRotation : 0 ,
90
+ } ,
91
+ } ,
92
+ y : {
93
+ ticks : {
94
+ callback : ( value : string | number ) => `${ value } %` ,
95
+ } ,
96
+ beginAtZero : true ,
97
+ } ,
98
+ } ,
99
+ } ;
100
+
101
+ return { data : _data , options : _options } ;
102
+ } , [ chartData ] ) ;
103
+
25
104
return (
26
105
< div className = "flex flex-col items-end" >
27
106
< ExportButton className = "mb-4" onExport = { onExport } downloadUrl = { exportApiEndpoint } />
28
107
< Card >
29
108
< Title > { title } </ Title >
30
109
< Subtitle > { subtitle } </ Subtitle >
31
110
< div className = "relative" >
32
- < BarChart
33
- className = "mt-6"
34
- data = { chartData }
35
- index = { index }
36
- categories = { categories }
37
- colors = { colors }
38
- valueFormatter = { valueFormatter }
39
- yAxisWidth = { 48 }
40
- />
111
+ < Bar className = "max-h-[28rem] mt-4" data = { data } options = { options } />
41
112
</ div >
42
113
</ Card >
43
114
</ div >
0 commit comments