1
- import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils' ;
2
1
import { ThemingParameters } from '@ui5/webcomponents-react-base/lib/ThemingParameters' ;
3
2
import { useConsolidatedRef } from '@ui5/webcomponents-react-base/lib/useConsolidatedRef' ;
3
+ import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils' ;
4
4
import { BarChartPlaceholder } from '@ui5/webcomponents-react-charts/lib/BarChartPlaceholder' ;
5
- import { useInitialize } from '@ui5/webcomponents-react-charts/lib/initialize' ;
6
5
import { ChartContainer } from '@ui5/webcomponents-react-charts/lib/next/ChartContainer' ;
7
6
import { useLegendItemClick } from '@ui5/webcomponents-react-charts/lib/useLegendItemClick' ;
8
- import { useResolveDataKeys } from '@ui5/webcomponents-react-charts/lib/useResolveDataKeys' ;
9
7
import React , { FC , forwardRef , Ref , useCallback } from 'react' ;
10
8
import {
11
9
Bar ,
@@ -18,51 +16,99 @@ import {
18
16
XAxis ,
19
17
YAxis
20
18
} from 'recharts' ;
21
- import { RechartBaseProps } from '../../interfaces/RechartBaseProps' ;
22
- import { useDataLabel , useAxisLabel , useSecondaryDimensionLabel } from '../../hooks/useLabelElements' ;
23
19
import { useChartMargin } from '../../hooks/useChartMargin' ;
20
+ import { useAxisLabel , useDataLabel , useSecondaryDimensionLabel } from '../../hooks/useLabelElements' ;
21
+ import { usePrepareDimensionsAndMeasures } from '../../hooks/usePrepareDimensionsAndMeasures' ;
22
+ import { useTooltipFormatter } from '../../hooks/useTooltipFormatter' ;
23
+ import { IChartDimension } from '../../interfaces/IChartDimension' ;
24
+ import { IChartMeasure } from '../../interfaces/IChartMeasure' ;
25
+ import { RechartBaseProps } from '../../interfaces/RechartBaseProps' ;
26
+
27
+ const formatYAxisTicks = ( tick ) => {
28
+ const splitTick = tick . split ( ' ' ) ;
29
+ return splitTick . length > 3
30
+ ? `${ splitTick . slice ( 0 , 3 ) . join ( ' ' ) } ...`
31
+ : tick . length > 11
32
+ ? `${ tick . slice ( 0 , 12 ) } ...`
33
+ : tick ;
34
+ } ;
24
35
25
- type BarChartProps = RechartBaseProps ;
36
+ const dimensionDefaults = {
37
+ formatter : formatYAxisTicks
38
+ } ;
39
+
40
+ const measureDefaults = {
41
+ formatter : ( d ) => d ,
42
+ opacity : 1
43
+ } ;
44
+
45
+ interface MeasureConfig extends IChartMeasure {
46
+ /**
47
+ * Bar Width
48
+ * @default auto
49
+ */
50
+ width ?: number ;
51
+ /**
52
+ * Bar Opacity
53
+ * @default 1
54
+ */
55
+ opacity ?: number ;
56
+ /**
57
+ * Bar Stack ID
58
+ * @default undefined
59
+ */
60
+ stackId ?: string ;
61
+ }
62
+
63
+ interface DimensionConfig extends IChartDimension {
64
+ interval ?: number ;
65
+ }
66
+
67
+ interface BarChartProps extends RechartBaseProps {
68
+ dimensions : DimensionConfig [ ] ;
69
+ /**
70
+ * An array of config objects. Each object is defining one bar in the chart.
71
+ *
72
+ * <h4>Required properties</h4>
73
+ * - `accessor`: string containing the path to the dataset key this bar should display. Supports object structures by using <code>'parent.child'</code>.
74
+ * Can also be a getter.
75
+ *
76
+ * <h4>Optional properties</h4>
77
+ *
78
+ * - `label`: Label to display in legends or tooltips. Falls back to the <code>accessor</code> if not present.
79
+ * - `color`: any valid CSS Color or CSS Variable. Defaults to the `sapChart_OrderedColor_` colors
80
+ * - `formatter`: function will be called for each data label and allows you to format it according to your needs
81
+ * - `hideDataLabel`: flag whether the data labels should be hidden in the chart for this bar.
82
+ * - `DataLabel`: a custom component to be used for the data label
83
+ * - `width`: bar width, defaults to `auto`
84
+ * - `opacity`: bar opacity, defaults to `1`
85
+ * - `stackId`: bars with the same stackId will be stacked
86
+ *
87
+ */
88
+ measures : MeasureConfig [ ] ;
89
+ }
26
90
27
91
/**
28
92
* <code>import { BarChart } from '@ui5/webcomponents-react-charts/lib/next/BarChart';</code>
29
93
* **This component is under active development. The API is not stable yet and might change without further notice.**
30
94
*/
31
95
const BarChart : FC < BarChartProps > = forwardRef ( ( props : BarChartProps , ref : Ref < any > ) => {
32
96
const {
33
- color,
34
97
loading,
35
- labelKey = 'name' ,
36
- secondaryDimensionKey,
37
- dataKeys,
38
- width = '100%' ,
39
- height = '500px' ,
40
98
dataset,
41
99
noLegend = false ,
42
100
onDataPointClick,
43
101
onLegendClick,
44
- labels,
45
- axisInterval,
46
- labelFormatter = ( el ) => formatYAxisTicks ( el ) ,
47
- valueFormatter = ( el ) => el ,
48
- dataLabelCustomElement = undefined ,
49
102
chartConfig = {
50
103
margin : { } ,
51
- yAxisVisible : false ,
104
+ yAxisVisible : true ,
52
105
xAxisVisible : true ,
53
- xAxisUnit : '' ,
54
- yAxisUnit : '' ,
55
106
gridStroke : ThemingParameters . sapList_BorderColor ,
56
107
gridHorizontal : true ,
57
108
gridVertical : false ,
58
109
legendPosition : 'top' ,
59
- barSize : undefined ,
60
110
barGap : 3 ,
61
111
zoomingTool : false ,
62
- strokeOpacity : 1 ,
63
- fillOpacity : 1 ,
64
- stacked : false ,
65
- dataLabel : true ,
66
112
referenceLine : {
67
113
label : undefined ,
68
114
value : undefined ,
@@ -74,22 +120,22 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<a
74
120
tooltip,
75
121
slot
76
122
} = props ;
77
- useInitialize ( ) ;
78
123
79
- const chartRef = useConsolidatedRef < any > ( ref ) ;
124
+ const { dimensions, measures } = usePrepareDimensionsAndMeasures (
125
+ props . dimensions ,
126
+ props . measures ,
127
+ dimensionDefaults ,
128
+ measureDefaults
129
+ ) ;
80
130
81
- const currentDataKeys = useResolveDataKeys ( dataKeys , labelKey , dataset , secondaryDimensionKey ) ;
131
+ const tooltipValueFormatter = useTooltipFormatter ( measures ) ;
82
132
83
- const onItemLegendClick = useLegendItemClick ( onLegendClick ) ;
133
+ const primaryDimension = dimensions [ 0 ] ;
134
+ const primaryMeasure = measures [ 0 ] ;
84
135
85
- const formatYAxisTicks = ( tick ) => {
86
- const splitTick = tick . split ( ' ' ) ;
87
- return splitTick . length > 3
88
- ? `${ splitTick . slice ( 0 , 3 ) . join ( ' ' ) } ...`
89
- : tick . length > 11
90
- ? `${ tick . slice ( 0 , 12 ) } ...`
91
- : tick ;
92
- } ;
136
+ const chartRef = useConsolidatedRef < any > ( ref ) ;
137
+
138
+ const onItemLegendClick = useLegendItemClick ( onLegendClick ) ;
93
139
94
140
const onDataPointClickInternal = useCallback (
95
141
( payload , i , event ) => {
@@ -110,36 +156,24 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<a
110
156
[ onDataPointClick ]
111
157
) ;
112
158
113
- const BarDataLabel = useDataLabel (
114
- chartConfig . dataLabel ,
115
- dataLabelCustomElement ,
116
- valueFormatter ,
117
- chartConfig . stacked ,
118
- true
119
- ) ;
159
+ const isBigDataSet = dataset ?. length > 30 ?? false ;
160
+ const primaryDimensionAccessor = primaryDimension ?. accessor ;
120
161
121
162
const marginChart = useChartMargin (
122
163
dataset ,
123
- labelFormatter ,
124
- labelKey ,
164
+ ( d ) => d ,
165
+ primaryDimensionAccessor ,
125
166
chartConfig . margin ,
126
167
true ,
127
- secondaryDimensionKey ,
168
+ dimensions . length > 1 ,
128
169
chartConfig . zoomingTool
129
170
) ;
130
171
131
- const XAxisLabel = useAxisLabel ( valueFormatter , chartConfig . xAxisUnit ) ;
132
- const YAxisLabel = useAxisLabel ( labelFormatter , chartConfig . yAxisUnit , true ) ;
133
- const SecondaryDimensionLabel = useSecondaryDimensionLabel ( true , labelFormatter ) ;
134
- const bigDataSet = dataset ?. length > 30 ?? false ;
135
-
136
172
return (
137
173
< ChartContainer
138
174
dataset = { dataset }
139
175
loading = { loading }
140
- placeholder = { BarChartPlaceholder }
141
- width = { width }
142
- height = { height }
176
+ Placeholder = { BarChartPlaceholder }
143
177
ref = { chartRef }
144
178
style = { style }
145
179
className = { className }
@@ -152,43 +186,60 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<a
152
186
horizontal = { chartConfig . gridHorizontal }
153
187
stroke = { chartConfig . gridStroke ?? ThemingParameters . sapList_BorderColor }
154
188
/>
155
- { ( chartConfig . xAxisVisible ?? true ) && < XAxis interval = { 0 } type = "number" tick = { XAxisLabel } /> }
156
- < YAxis
157
- unit = { chartConfig . yAxisUnit }
158
- axisLine = { chartConfig . yAxisVisible ?? false }
159
- tickLine = { false }
160
- tick = { YAxisLabel }
161
- type = "category"
162
- dataKey = { labelKey }
163
- interval = { axisInterval ?? bigDataSet ? 2 : 0 }
164
- yAxisId = { 0 }
165
- />
166
- { secondaryDimensionKey && (
167
- < YAxis
189
+ { ( chartConfig . xAxisVisible ?? true ) && (
190
+ < XAxis
168
191
interval = { 0 }
169
- type = { 'category' }
170
- dataKey = { 'dimension' }
171
- tickLine = { false }
172
- tick = { SecondaryDimensionLabel }
173
- axisLine = { false }
174
- yAxisId = { 1 }
192
+ type = "number"
193
+ axisLine = { chartConfig . xAxisVisible ?? true }
194
+ tickFormatter = { primaryMeasure ?. formatter }
175
195
/>
176
196
) }
177
- { currentDataKeys . map ( ( key , index ) => (
178
- < Bar
179
- stackId = { chartConfig . stacked ? 'A' : undefined }
180
- strokeOpacity = { chartConfig . strokeOpacity }
181
- fillOpacity = { chartConfig . fillOpacity }
182
- label = { BarDataLabel }
183
- key = { key }
184
- name = { labels ?. [ key ] || key }
185
- dataKey = { key }
186
- fill = { color ?? `var(--sapUiChartAccent${ ( index % 12 ) + 1 } )` }
187
- stroke = { color ?? `var(--sapUiChartAccent${ ( index % 12 ) + 1 } )` }
188
- barSize = { chartConfig . barSize }
189
- onClick = { onDataPointClickInternal }
190
- />
191
- ) ) }
197
+ { ( chartConfig . yAxisVisible ?? true ) &&
198
+ dimensions . map ( ( dimension , index ) => {
199
+ const YAxisLabel =
200
+ index > 0
201
+ ? useSecondaryDimensionLabel ( true , dimension . formatter )
202
+ : useAxisLabel ( dimension . formatter , true ) ;
203
+ return (
204
+ < YAxis
205
+ type = "category"
206
+ key = { dimension . accessor }
207
+ dataKey = { dimension . accessor }
208
+ xAxisId = { index }
209
+ interval = { dimension . interval ?? isBigDataSet ? 2 : 0 }
210
+ tick = { YAxisLabel }
211
+ tickLine = { index < 1 }
212
+ axisLine = { index < 1 }
213
+ yAxisId = { index }
214
+ />
215
+ ) ;
216
+ } ) }
217
+ { measures . map ( ( element , index ) => {
218
+ const ColumnDataLabel = useDataLabel (
219
+ ! element . hideDataLabel ,
220
+ element . DataLabel ,
221
+ element . formatter ,
222
+ false ,
223
+ true ,
224
+ false
225
+ ) ;
226
+ return (
227
+ < Bar
228
+ stackId = { element . stackId }
229
+ fillOpacity = { element . opacity }
230
+ key = { element . accessor }
231
+ name = { element . label ?? element . accessor }
232
+ strokeOpacity = { element . opacity }
233
+ label = { isBigDataSet ? false : ColumnDataLabel }
234
+ type = "monotone"
235
+ dataKey = { element . accessor }
236
+ fill = { element . color ?? `var(--sapChart_OrderedColor_${ ( index % 11 ) + 1 } )` }
237
+ stroke = { element . color ?? `var(--sapChart_OrderedColor_${ ( index % 11 ) + 1 } )` }
238
+ barSize = { element . width }
239
+ onClick = { onDataPointClickInternal }
240
+ />
241
+ ) ;
242
+ } ) }
192
243
{ ! noLegend && < Legend verticalAlign = { chartConfig . legendPosition ?? 'top' } onClick = { onItemLegendClick } /> }
193
244
{ chartConfig . referenceLine && (
194
245
< ReferenceLine
@@ -197,9 +248,15 @@ const BarChart: FC<BarChartProps> = forwardRef((props: BarChartProps, ref: Ref<a
197
248
label = { chartConfig . referenceLine . label }
198
249
/>
199
250
) }
200
- < Tooltip cursor = { { fillOpacity : 0.3 } } labelFormatter = { valueFormatter } />
251
+ < Tooltip cursor = { { fillOpacity : 0.3 } } formatter = { tooltipValueFormatter } />
201
252
{ chartConfig . zoomingTool && (
202
- < Brush y = { 0 } dataKey = { labelKey } stroke = { `var(--sapUiChartAccent6)` } travellerWidth = { 10 } height = { 20 } />
253
+ < Brush
254
+ y = { 0 }
255
+ dataKey = { primaryDimensionAccessor }
256
+ stroke = { ThemingParameters . sapObjectHeader_BorderColor }
257
+ travellerWidth = { 10 }
258
+ height = { 20 }
259
+ />
203
260
) }
204
261
</ BarChartLib >
205
262
</ ChartContainer >
0 commit comments