Skip to content

Commit c9ff70b

Browse files
committed
fix(ChartState): Don't filter explicit x1Domain/y1Domain by visible series when no series are configured. Restores grouped layout for composable <Chart> usage (e.g. <Bars> with x1/x1Domain/x1Range) where the visible-series filter previously emptied the secondary band scale domain, collapsing all bars to a single category position.
1 parent 6b15467 commit c9ff70b

4 files changed

Lines changed: 81 additions & 11 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': patch
3+
---
4+
5+
fix(ChartState): Don't filter explicit `x1Domain`/`y1Domain` by visible series when no series are configured. Restores grouped layout for composable `<Chart>` usage (e.g. `<Bars>` with `x1`/`x1Domain`/`x1Range`) where the visible-series filter previously emptied the secondary band scale domain, collapsing all bars to a single category position.

docs/src/routes/docs/screenshot/[component]/+layout.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@ export const load = async ({ params }) => {
1414
if (match && match[1] === componentName) {
1515
const [, comp, exampleName] = match;
1616

17-
const component = (await componentExamples[path]()) as Component;
18-
const source = (await componentSources[path]()) as string;
17+
try {
18+
const component = (await componentExamples[path]()) as Component;
19+
const source = (await componentSources[path]()) as string;
1920

20-
// Remove `export { data };`
21-
const cleanupSource = source.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n');
21+
// Remove `export { data };`
22+
const cleanupSource = source.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n');
2223

23-
if (!examples[comp]) {
24-
examples[comp] = {};
24+
if (!examples[comp]) {
25+
examples[comp] = {};
26+
}
27+
examples[comp][exampleName] = { component, source: cleanupSource, module: {} };
28+
} catch (err) {
29+
// Skip broken examples so one failure doesn't kill the whole batch load
30+
console.warn(`Failed to load example ${comp}/${exampleName}:`, err);
2531
}
26-
examples[comp][exampleName] = { component, source: cleanupSource, module: {} };
2732
}
2833
}
2934

packages/layerchart/src/lib/states/chart.svelte.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,3 +1579,53 @@ describe('ChartState group layout auto-derives x1/y1', () => {
15791579
}
15801580
});
15811581
});
1582+
1583+
describe('ChartState x1Domain/y1Domain without series', () => {
1584+
type LongData = { year: number; fruit: string; value: number };
1585+
const longData: LongData[] = [
1586+
{ year: 2019, fruit: 'apples', value: 3840 },
1587+
{ year: 2019, fruit: 'bananas', value: 1920 },
1588+
{ year: 2018, fruit: 'apples', value: 1600 },
1589+
{ year: 2018, fruit: 'bananas', value: 1440 },
1590+
];
1591+
1592+
it('should pass through explicit x1Domain when no series are configured', () => {
1593+
const { state, cleanup } = createChartState<LongData>({
1594+
data: longData,
1595+
x: 'year',
1596+
xScale: scaleBand(),
1597+
y: 'value',
1598+
x1: 'fruit',
1599+
x1Domain: ['apples', 'bananas'],
1600+
x1Range: ({ xScale }) => [0, (xScale as any).bandwidth()],
1601+
});
1602+
1603+
try {
1604+
expect(state.seriesState.series).toHaveLength(0);
1605+
expect(state.x1Domain).toEqual(['apples', 'bananas']);
1606+
expect(state.x1Scale!.domain()).toEqual(['apples', 'bananas']);
1607+
} finally {
1608+
cleanup();
1609+
}
1610+
});
1611+
1612+
it('should pass through explicit y1Domain when no series are configured', () => {
1613+
const { state, cleanup } = createChartState<LongData>({
1614+
data: longData,
1615+
y: 'year',
1616+
yScale: scaleBand(),
1617+
x: 'value',
1618+
y1: 'fruit',
1619+
y1Domain: ['apples', 'bananas'],
1620+
y1Range: ({ yScale }) => [0, (yScale as any).bandwidth()],
1621+
});
1622+
1623+
try {
1624+
expect(state.seriesState.series).toHaveLength(0);
1625+
expect(state.y1Domain).toEqual(['apples', 'bananas']);
1626+
expect(state.y1Scale!.domain()).toEqual(['apples', 'bananas']);
1627+
} finally {
1628+
cleanup();
1629+
}
1630+
});
1631+
});

packages/layerchart/src/lib/states/chart.svelte.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -867,8 +867,13 @@ export class ChartState<
867867

868868
x1Domain = $derived.by(() => {
869869
if (this.props.x1Domain) {
870-
const visibleKeys = new Set(this.seriesState.visibleSeries.map((s) => s.key));
871-
return this.props.x1Domain.filter((key: any) => visibleKeys.has(key));
870+
// Only filter by visible series when series are configured — otherwise the
871+
// full x1Domain is used as-is (composable charts without series).
872+
if (this.seriesState.series.length > 0) {
873+
const visibleKeys = new Set(this.seriesState.visibleSeries.map((s) => s.key));
874+
return this.props.x1Domain.filter((key: any) => visibleKeys.has(key));
875+
}
876+
return this.props.x1Domain;
872877
}
873878
// Auto-derive for grouped series when x is the category axis
874879
if (this.props.seriesLayout === 'group' && this.valueAxis === 'y') {
@@ -881,8 +886,13 @@ export class ChartState<
881886
});
882887
y1Domain = $derived.by(() => {
883888
if (this.props.y1Domain) {
884-
const visibleKeys = new Set(this.seriesState.visibleSeries.map((s) => s.key));
885-
return this.props.y1Domain.filter((key: any) => visibleKeys.has(key));
889+
// Only filter by visible series when series are configured — otherwise the
890+
// full y1Domain is used as-is (composable charts without series).
891+
if (this.seriesState.series.length > 0) {
892+
const visibleKeys = new Set(this.seriesState.visibleSeries.map((s) => s.key));
893+
return this.props.y1Domain.filter((key: any) => visibleKeys.has(key));
894+
}
895+
return this.props.y1Domain;
886896
}
887897
// Auto-derive for grouped series when y is the category axis
888898
if (this.props.seriesLayout === 'group' && this.valueAxis === 'x') {

0 commit comments

Comments
 (0)