@@ -32,7 +32,7 @@ export class StackedBar<Datum> extends XYComponentCore<Datum, StackedBarConfigIn
3232 getAccessors = ( ) : NumericAccessor < Datum > [ ] => ( isArray ( this . config . y ) ? this . config . y : [ this . config . y ] )
3333 stacked = true
3434 events = { }
35- private _prevNegative : boolean [ ] | undefined // To help guessing the bar direction when an accessor was set to null or 0
35+ private _prevNegative : boolean [ ] | undefined
3636 private _barData : Datum [ ] = [ ]
3737
3838 constructor ( config ?: StackedBarConfigInterface < Datum > ) {
@@ -124,18 +124,38 @@ export class StackedBar<Datum> extends XYComponentCore<Datum, StackedBarConfigIn
124124 )
125125
126126 // Render Bars
127+ const stackExtents = this . _barData . map ( ( _ , j ) => {
128+ const values = stacked . map ( s => s [ j ] ) // Get all [y0, y1] pairs for stack j
129+ const positiveY1 = values . filter ( v => v [ 1 ] >= v [ 0 ] ) . map ( v => v [ 1 ] )
130+ const negativeY1 = values . filter ( v => v [ 1 ] < v [ 0 ] ) . map ( v => v [ 1 ] )
131+ return {
132+ maxPositive : positiveY1 . length ? max ( positiveY1 ) : undefined ,
133+ minNegative : negativeY1 . length ? min ( negativeY1 ) : undefined ,
134+ }
135+ } )
136+
127137 const bars = barGroupsMerged
128138 . selectAll < SVGPathElement , StackedBarDataRecord < Datum > > ( `.${ s . bar } ` )
129- . data ( ( d , j ) => stacked . map ( ( s , stackIndex ) =>
130- ( {
131- ...d ,
132- _index : j ,
133- _stacked : s [ j ] ,
134- // Ending bar if the next stack is not the same as the current one
135- _ending : ( stackIndex === stacked . length - 1 ) ||
136- ( ( stackIndex <= stacked . length - 1 ) && stacked [ stackIndex + 1 ] [ j ] [ 0 ] !== s [ j ] [ 1 ] ) ,
137- } ) )
138- )
139+ . data ( ( d , j ) => {
140+ const { maxPositive, minNegative } = stackExtents [ j ]
141+ return stacked . map ( ( s ) => {
142+ const y0 = s [ j ] [ 0 ]
143+ const y1 = s [ j ] [ 1 ]
144+ const isSegmentPositive = y1 >= y0
145+
146+ // A bar is "ending" if it's the outermost in its respective direction (positive or negative)
147+ const isEnding = isSegmentPositive
148+ ? y1 === maxPositive
149+ : y1 === minNegative
150+
151+ return {
152+ ...d ,
153+ _index : j ,
154+ _stacked : s [ j ] ,
155+ _ending : isEnding ,
156+ }
157+ } )
158+ } )
139159
140160 const barsEnter = bars . enter ( ) . append ( 'path' )
141161 . attr ( 'class' , s . bar )
@@ -224,27 +244,16 @@ export class StackedBar<Datum> extends XYComponentCore<Datum, StackedBarConfigIn
224244 const stackSpacing = config . stackSpacing || 0
225245 let hWithSpacing = h
226246 let yWithSpacing = y
227- // Always apply spacing between all stacked segments if config.stackSpacing is set
228- // Only apply the zero-axis gap if there are actual negative values in the data
229- const hasNegative = stackSpacing > 0 && this . _barData && this . _barData . length > 0 && this . _barData . some ( barDataItem =>
230- this . getAccessors ( ) . some ( accessor => getNumber ( barDataItem , accessor ) < 0 )
231- )
247+ // For negative bars, shift y position by stackSpacing so the base remains at the correct value
232248 if ( ! isEntering && stackSpacing > 0 ) {
233- if ( this . isVertical ( ) ) {
234- hWithSpacing = Math . max ( 0 , h - stackSpacing )
235- // For negative bars, spacing should be applied in the same direction as positive, but the sign of the offset should be flipped
236- yWithSpacing = y + ( isNegative ? stackSpacing / 2 : stackSpacing / 2 )
237- // Apply gap at zero axis for both positive and negative bars
238- if ( hasNegative && ( d . _stacked [ 0 ] === 0 || d . _stacked [ 1 ] === 0 ) ) {
239- // Always add half the spacing away from zero, regardless of sign
240- yWithSpacing += ( isNegative ? stackSpacing / 2 : - stackSpacing / 2 )
241- }
249+ hWithSpacing = h - stackSpacing
250+ if ( hWithSpacing <= 0 && isFinite ( value ) && ( value !== config . barMinHeightZeroValue ) ) {
251+ hWithSpacing = 1
242252 } else {
243- hWithSpacing = Math . max ( 0 , h - stackSpacing )
244- yWithSpacing = y + ( isNegative ? stackSpacing / 2 : stackSpacing / 2 )
245- if ( hasNegative && ( d . _stacked [ 0 ] === 0 || d . _stacked [ 1 ] === 0 ) ) {
246- yWithSpacing += ( isNegative ? stackSpacing / 2 : - stackSpacing / 2 )
247- }
253+ hWithSpacing = Math . max ( 0 , hWithSpacing )
254+ }
255+ if ( this . isVertical ( ) && isNegative ) {
256+ yWithSpacing = y + stackSpacing
248257 }
249258 }
250259
0 commit comments