@@ -19,7 +19,7 @@ import type { BarSeriesStyle, DisplayValueStyle } from '../../../utils/themes/th
1919import { IndexedGeometryMap } from '../utils/indexed_geometry_map' ;
2020import type { DataSeries , DataSeriesDatum , XYChartSeriesIdentifier } from '../utils/series' ;
2121import { getSeriesIdentifierFromDataSeries } from '../utils/series' ;
22- import type { BarStyleAccessor , DisplayValueSpec , StackMode } from '../utils/specs' ;
22+ import type { BarStyleAccessor , DisplayValueSpec , StackMode , TickFormatter } from '../utils/specs' ;
2323import { LabelOverflowConstraint } from '../utils/specs' ;
2424
2525const PADDING = 1 ; // default padding for now
@@ -30,6 +30,11 @@ type BarTuple = {
3030 indexedGeometryMap : IndexedGeometryMap ;
3131} ;
3232
33+ /** @internal */
34+ type DisplayValueSpecWithValueFormatter = Omit < DisplayValueSpec , 'valueFormatter' > & {
35+ valueFormatter : TickFormatter ;
36+ } ;
37+
3338/** @internal */
3439export function renderBars (
3540 measureText : TextMeasure ,
@@ -43,17 +48,17 @@ export function renderBars(
4348 color : Color ,
4449 isBandedSpec : boolean ,
4550 sharedSeriesStyle : BarSeriesStyle ,
46- displayValueSettings ?: DisplayValueSpec ,
51+ displayValueSettings ?: DisplayValueSpecWithValueFormatter ,
4752 styleAccessor ?: BarStyleAccessor ,
4853 stackMode ?: StackMode ,
4954) : BarTuple {
50- const { fontSize, fontFamily } = sharedSeriesStyle . displayValue ;
5155 const initialBarTuple : BarTuple = { barGeometries : [ ] , indexedGeometryMap : new IndexedGeometryMap ( ) } as BarTuple ;
5256 const y1Fn = getY1ScaledValueFn ( yScale ) ;
5357 const y0Fn = getY0ScaledValueFn ( yScale ) ;
54-
58+ const seriesIdentifier = getSeriesIdentifierFromDataSeries ( dataSeries ) ;
5559 return dataSeries . data . reduce ( ( barTuple : BarTuple , datum ) => {
5660 const xScaled = xScale . scale ( datum . x ) ;
61+
5762 if ( ! xScale . isValueInDomain ( datum . x ) || Number . isNaN ( xScaled ) ) {
5863 return barTuple ; // don't create a bar if not within the xScale domain
5964 }
@@ -77,7 +82,6 @@ export function renderBars(
7782 // the actual height of the bar
7883 const height = yDiff + addedMinBarHeight ;
7984
80- const seriesIdentifier : XYChartSeriesIdentifier = getSeriesIdentifierFromDataSeries ( dataSeries ) ;
8185 const seriesStyle = getBarStyleOverrides ( datum , seriesIdentifier , sharedSeriesStyle , styleAccessor ) ;
8286
8387 const maxPixelWidth = clamp ( seriesStyle . rect . widthRatio ?? 1 , 0 , 1 ) * xScale . bandwidth ;
@@ -87,52 +91,15 @@ export function renderBars(
8791 const x = xScaled + xScale . bandwidth * orderIndex + xScale . bandwidth / 2 - width / 2 ;
8892
8993 const y1Value = getDatumYValue ( datum , false , isBandedSpec , stackMode ) ;
90- const formattedDisplayValue = displayValueSettings ?. valueFormatter ?.( y1Value ) ;
91-
92- // only show displayValue for even bars if showOverlappingValue
93- const displayValueText =
94- displayValueSettings ?. isAlternatingValueLabel && barGeometries . length % 2 ? undefined : formattedDisplayValue ;
95-
96- const { displayValueWidth, fixedFontScale } = computeBoxWidth ( displayValueText ?? '' , {
97- padding : PADDING ,
98- fontSize,
99- fontFamily,
100- measureText,
101- } ) ;
102-
103- const isHorizontalRotation = chartRotation % 180 === 0 ;
104- // Pick the right side of the label's box to use as factor reference
105- const referenceWidth = Math . max ( isHorizontalRotation ? displayValueWidth : fixedFontScale , 1 ) ;
106-
107- const textScalingFactor = getFinalFontScalingFactor (
108- ( width * FONT_SIZE_FACTOR ) / referenceWidth ,
109- fixedFontScale ,
110- fontSize ,
111- ) ;
112- const overflowConstraints : Set < LabelOverflowConstraint > = new Set (
113- displayValueSettings ?. overflowConstraints ?? [
114- LabelOverflowConstraint . ChartEdges ,
115- LabelOverflowConstraint . BarGeometry ,
116- ] ,
117- ) ;
118-
119- // Based on rotation scale the width of the text box
120- const bboxWidthFactor = isHorizontalRotation ? textScalingFactor : 1 ;
121-
122- const displayValue : BarGeometry [ 'displayValue' ] | undefined =
123- displayValueText && displayValueSettings ?. showValueLabel
124- ? {
125- fontScale : textScalingFactor ,
126- fontSize : fixedFontScale ,
127- text : displayValueText ,
128- width : bboxWidthFactor * displayValueWidth ,
129- height : textScalingFactor * fixedFontScale ,
130- overflowConstraints,
131- }
132- : undefined ;
13394
95+ const shouldDisplayValue =
96+ displayValueSettings ?. showValueLabel &&
97+ // only show displayValue for even bars if isAlternatingValueLabel
98+ ! ( displayValueSettings ?. isAlternatingValueLabel && barGeometries . length % 2 ) ;
13499 const barGeometry : BarGeometry = {
135- displayValue,
100+ displayValue : shouldDisplayValue
101+ ? computeDisplayValue ( y1Value , sharedSeriesStyle , measureText , chartRotation , width , displayValueSettings )
102+ : undefined ,
136103 x,
137104 y : yScreenSpaceCoord ,
138105 transform : { x : 0 , y : 0 } ,
@@ -169,6 +136,57 @@ export function renderBars(
169136 } , initialBarTuple ) ;
170137}
171138
139+ function computeDisplayValue (
140+ y1Value : number | null ,
141+ sharedSeriesStyle : BarSeriesStyle ,
142+ measureText : TextMeasure ,
143+ chartRotation : number ,
144+ width : number ,
145+ displayValueSettings : DisplayValueSpecWithValueFormatter ,
146+ ) : BarGeometry [ 'displayValue' ] | undefined {
147+ const { fontSize, fontFamily } = sharedSeriesStyle . displayValue ;
148+ const displayValueText = displayValueSettings . valueFormatter ( y1Value ) ;
149+
150+ if ( displayValueText . length === 0 ) {
151+ return ;
152+ }
153+
154+ const { displayValueWidth, fixedFontScale } = computeBoxWidth ( displayValueText , {
155+ padding : PADDING ,
156+ fontSize,
157+ fontFamily,
158+ measureText,
159+ } ) ;
160+
161+ const isHorizontalRotation = chartRotation % 180 === 0 ;
162+ // Pick the right side of the label's box to use as factor reference
163+ const referenceWidth = Math . max ( isHorizontalRotation ? displayValueWidth : fixedFontScale , 1 ) ;
164+
165+ const textScalingFactor = getFinalFontScalingFactor (
166+ ( width * FONT_SIZE_FACTOR ) / referenceWidth ,
167+ fixedFontScale ,
168+ fontSize ,
169+ ) ;
170+ const overflowConstraints : Set < LabelOverflowConstraint > = new Set (
171+ displayValueSettings ?. overflowConstraints ?? [
172+ LabelOverflowConstraint . ChartEdges ,
173+ LabelOverflowConstraint . BarGeometry ,
174+ ] ,
175+ ) ;
176+
177+ // Based on rotation scale the width of the text box
178+ const bboxWidthFactor = isHorizontalRotation ? textScalingFactor : 1 ;
179+
180+ return {
181+ fontScale : textScalingFactor ,
182+ fontSize : fixedFontScale ,
183+ text : displayValueText ,
184+ width : bboxWidthFactor * displayValueWidth ,
185+ height : textScalingFactor * fixedFontScale ,
186+ overflowConstraints,
187+ } ;
188+ }
189+
172190/**
173191 * Workout the text box size and fixedFontSize based on a collection of options
174192 * @internal
@@ -189,6 +207,10 @@ function computeBoxWidth(
189207) : { fixedFontScale : number ; displayValueWidth : number } {
190208 const fixedFontScale = Math . max ( typeof fontSize === 'number' ? fontSize : fontSize . min , 1 ) ;
191209
210+ if ( text . length === 0 ) {
211+ return { fixedFontScale, displayValueWidth : 0 } ;
212+ }
213+
192214 const computedDisplayValueWidth = measureText (
193215 text ,
194216 { fontFamily, fontWeight : 'normal' , fontStyle : 'normal' , fontVariant : 'normal' } ,
0 commit comments