From d104736620ff8cf731f194fe738f20b94cb21dbd Mon Sep 17 00:00:00 2001 From: Avinash Dwarapu Date: Fri, 9 Oct 2026 07:19:09 +0200 Subject: [PATCH] fix: Always start y-axis baseline for area chart at 0 --- .../__tests__/area-chart-model-utils.test.ts | 49 ++++++++++++++++--- src/area-chart/model/utils.ts | 5 ++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/area-chart/__tests__/area-chart-model-utils.test.ts b/src/area-chart/__tests__/area-chart-model-utils.test.ts index 757feb13aa..32f806fc1a 100644 --- a/src/area-chart/__tests__/area-chart-model-utils.test.ts +++ b/src/area-chart/__tests__/area-chart-model-utils.test.ts @@ -85,17 +85,28 @@ describe('AreaChart computeDomainY', () => { expect(domain).toHaveLength(0); }); - it('returns min/max domain for linear series', () => { + it('includes zero baseline in linear domain for threshold series', () => { const domain = computeDomainY([{ type: 'threshold', y: 10, title: 'T10' }], 'linear'); - expect(domain).toEqual([10, 10]); + expect(domain).toEqual([0, 10]); }); - it('returns min/max domain for log series', () => { - const domain = computeDomainY([{ type: 'threshold', y: 10, title: 'T10' }], 'linear'); - expect(domain).toEqual([10, 10]); + it('includes zero baseline in linear domain when all values are positive', () => { + const domain = computeDomainY( + [{ type: 'area', data: [50, 75, 100].map((y, x) => ({ x, y })), title: 'A' }], + 'linear' + ); + expect(domain).toEqual([0, 100]); + }); + + it('includes zero baseline in linear domain when all values are negative', () => { + const domain = computeDomainY( + [{ type: 'area', data: [-50, -75, -100].map((y, x) => ({ x, y })), title: 'A' }], + 'linear' + ); + expect(domain).toEqual([-100, 0]); }); - it('replaces lower range bound with 1 for log scale type', () => { + it('keeps zero lower bound for linear scale type', () => { const domain = computeDomainY( [ { type: 'threshold', y: 0, title: 'T0' }, @@ -106,6 +117,28 @@ describe('AreaChart computeDomainY', () => { expect(domain).toEqual([0, 10]); }); + it('replaces zero lower bound with 1 for log scale type', () => { + const domain = computeDomainY( + [ + { type: 'threshold', y: 0, title: 'T0' }, + { type: 'threshold', y: 10, title: 'T10' }, + ], + 'log' + ); + expect(domain).toEqual([1, 10]); + }); + + it('keeps log domain as is when values are below 1', () => { + const domain = computeDomainY( + [ + { type: 'threshold', y: 0.1, title: 'T0.1' }, + { type: 'threshold', y: 0.5, title: 'T0.5' }, + ], + 'log' + ); + expect(domain).toEqual([0.1, 0.5]); + }); + it('computes stacked min/max', () => { const data = [1, 2, 3, 4, 5]; const domain = computeDomainY( @@ -115,7 +148,7 @@ describe('AreaChart computeDomainY', () => { ], 'linear' ); - expect(domain).toEqual([1, 15]); + expect(domain).toEqual([0, 15]); }); it('computes min/max with both series and threshold', () => { @@ -128,7 +161,7 @@ describe('AreaChart computeDomainY', () => { ], 'linear' ); - expect(domain).toEqual([1, 20]); + expect(domain).toEqual([0, 20]); }); }); diff --git a/src/area-chart/model/utils.ts b/src/area-chart/model/utils.ts index 609553479b..d885576572 100644 --- a/src/area-chart/model/utils.ts +++ b/src/area-chart/model/utils.ts @@ -63,6 +63,11 @@ export function computeDomainY(series: readonly AreaChartProps.Series[], s return []; } + // Linear areas are filled from the zero baseline. This is consistent with the bar and line charts. + if (scaleType === 'linear') { + return [Math.min(min, 0), Math.max(max, 0)]; + } + // Log scales can't start from 0, so, if possible, start from 1. if (scaleType === 'log' && min === 0 && max > 1) { return [1, max];