@@ -110,14 +110,8 @@ function applyGapStrategy(
110110 groups . get ( key ) ! . push ( d )
111111 }
112112
113- // Sort each group by x for stable gap detection.
114- for ( const [ , pts ] of groups ) {
115- pts . sort ( ( a , b ) => {
116- const ax = Number ( a [ xKey ] )
117- const bx = Number ( b [ xKey ] )
118- return ( Number . isFinite ( ax ) ? ax : 0 ) - ( Number . isFinite ( bx ) ? bx : 0 )
119- } )
120- }
113+ // Preserve input order (matches client LineChart gapStrategy behavior,
114+ // which never sorts by x — it assumes rows already arrive in series order).
121115
122116 if ( gapStrategy === "interpolate" ) {
123117 const out : Datum [ ] = [ ]
@@ -340,6 +334,15 @@ export function prepareLineSeriesForSsr(input: LineSeriesSsrInput): LineSeriesSs
340334
341335 // ── Gap strategy ───────────────────────────────────────────────────
342336 if ( input . gapStrategy ) {
337+ // Mirror client behavior: gap processing runs per-series even when
338+ // lineBy/groupAccessor is a function — materialize it onto each row so
339+ // applyGapStrategy can group by a stable string key instead of
340+ // collapsing every series into one "__single" bucket.
341+ if ( typeof groupAccessor === "function" ) {
342+ const resolveGroup = groupAccessor
343+ rows = rows . map ( ( d ) => ( { ...d , __semiotic_gapGroup : resolveGroup ( d ) } ) )
344+ groupAccessor = "__semiotic_gapGroup"
345+ }
343346 const groupKey = typeof groupAccessor === "string" ? groupAccessor : undefined
344347 const gapped = applyGapStrategy ( rows , input . gapStrategy , xKey , yKey , groupKey )
345348 rows = gapped . rows
0 commit comments