From ce424c3a24df28ad8cb7d53083024f678b0eb47a Mon Sep 17 00:00:00 2001 From: Nikita Rokotyan Date: Tue, 28 Jul 2026 12:57:46 -0700 Subject: [PATCH 1/5] Component | RadialBar: Don't render bars with missing values The `value` accessor result was coerced with `?? 0`, making a missing value indistinguishable from a real `0`. Keep it as `null` instead, so the arc stays collapsed and hidden, and let `0` be rendered as an actual data point. `RadialBarArcDatum.value` is now `number | null` accordingly. Also make the default `id` accessor null-safe: with gaps in the data, the record itself can be `null`, which used to throw when reading `d.id`. Co-Authored-By: Claude Opus 5 --- packages/ts/src/components/radial-bar/config.ts | 7 +++++-- packages/ts/src/components/radial-bar/index.ts | 10 +++++++--- packages/ts/src/components/radial-bar/types.ts | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/ts/src/components/radial-bar/config.ts b/packages/ts/src/components/radial-bar/config.ts index 094c022d0..4b03f403b 100644 --- a/packages/ts/src/components/radial-bar/config.ts +++ b/packages/ts/src/components/radial-bar/config.ts @@ -7,7 +7,9 @@ import { ColorAccessor, NumericAccessor } from '@/types/accessor' export interface RadialBarConfigInterface extends ComponentConfigInterface { /** Accessor function for getting the unique data record id. Used for more persistent data updates. Default: `(d, i) => d.id ?? i` */ id?: ((d: Datum, i: number, ...any: unknown[]) => string | number); - /** Value accessor function. Default: `undefined` */ + /** Value accessor function. Returning `null` or `undefined` marks the value as missing, + * and the corresponding bar will not be rendered. Default: `undefined` + */ value: NumericAccessor; /** Maximum value accessor or an array of maximums (indexed by each datum's original position in `data` before sorting). * Used to scale each bar's arc length: each bar fills `(value / maxValue) * (angleRange[1] - angleRange[0])`. @@ -53,7 +55,8 @@ export interface RadialBarConfigInterface extends ComponentConfigInterfac export const RadialBarDefaultConfig: RadialBarConfigInterface = { ...ComponentDefaultConfig, - id: (d: unknown, i: number): string | number => (d as { id: string }).id ?? i, + // Optional chaining because a data record itself can be `null` when the data has gaps + id: (d: unknown, i: number): string | number => (d as { id: string })?.id ?? i, value: undefined, maxValue: undefined, angleRange: [0, 2 * Math.PI], diff --git a/packages/ts/src/components/radial-bar/index.ts b/packages/ts/src/components/radial-bar/index.ts index 2d3f4880c..7d05f24c5 100644 --- a/packages/ts/src/components/radial-bar/index.ts +++ b/packages/ts/src/components/radial-bar/index.ts @@ -109,8 +109,12 @@ export class RadialBar extends ComponentCore getNumber(d.datum, config.value, d.index) ?? 0) + // Resolve per-bar value and max. `null` and `undefined` are treated as missing data: + // such bars are not rendered at all. + const values = wrapped.map((d) => { + const value = getNumber(d.datum, config.value, d.index) + return isNumber(value) && isFinite(value) ? value : null + }) const dataMax = max(values) ?? 0 const maxValues = wrapped.map((d) => { const mv = config.maxValue @@ -130,7 +134,7 @@ export class RadialBar extends ComponentCore { index: number; /** Index of the ring counted from the outermost (`0` = outermost). */ ringIndex: number; - value: number; + /** Resolved value. `null` when the `value` accessor returned `null`, `undefined` or a non-finite number */ + value: number | null; startAngle: number; endAngle: number; innerRadius: number; From 249e425c5a1f53370a892e31600d4593e69e167e Mon Sep 17 00:00:00 2001 From: Nikita Rokotyan Date: Tue, 28 Jul 2026 12:58:08 -0700 Subject: [PATCH 2/5] Component | RadialBar: Add `barMinAngle` config property Bars representing tiny values were collapsing into an invisible hairline. `barMinAngle` sets the minimum angular extent of a bar in radians, `0` values included, so that they stay on screen. It defaults to `0.01`, which is about one pixel wide on a ring of a 100 pixel radius, and it's clamped to the length of `angleRange`. Bars with missing values are unaffected: they're never drawn. The minimum is applied along the sweep direction, so reversed angle ranges, e.g. `[0, -2 * Math.PI]`, keep rendering counter-clockwise. Co-Authored-By: Claude Opus 5 --- packages/ts/src/components/radial-bar/config.ts | 7 +++++++ packages/ts/src/components/radial-bar/index.ts | 12 ++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/ts/src/components/radial-bar/config.ts b/packages/ts/src/components/radial-bar/config.ts index 4b03f403b..b0ab6ec8d 100644 --- a/packages/ts/src/components/radial-bar/config.ts +++ b/packages/ts/src/components/radial-bar/config.ts @@ -20,6 +20,12 @@ export interface RadialBarConfigInterface extends ComponentConfigInterfac angleRange?: [number, number]; /** Pad angle in radians applied between the bar and its end. Default: `0` */ padAngle?: number; + /** Minimum bar angle in radians. Bars with small values, `0` included, will be extended to that angle, + * so that they remain visible. The value is clamped to the length of `angleRange`. + * Bars with missing values (see `value`) are not affected: they're never rendered. + * Set it to `0` to disable. Default: `0.01` (about 1 pixel wide on a ring of a 100 pixel radius) + */ + barMinAngle?: number; /** Custom sort function. Default: `undefined` */ sortFunction?: (a: Datum, b: Datum) => number; /** Corner Radius. Default: `0` */ @@ -61,6 +67,7 @@ export const RadialBarDefaultConfig: RadialBarConfigInterface = { maxValue: undefined, angleRange: [0, 2 * Math.PI], padAngle: 0, + barMinAngle: 0.01, sortFunction: undefined, cornerRadius: 0, color: undefined, diff --git a/packages/ts/src/components/radial-bar/index.ts b/packages/ts/src/components/radial-bar/index.ts index 7d05f24c5..b9b8b205f 100644 --- a/packages/ts/src/components/radial-bar/index.ts +++ b/packages/ts/src/components/radial-bar/index.ts @@ -86,6 +86,10 @@ export class RadialBar extends ComponentCore extends ComponentCore { const value = getNumber(d.datum, config.value, d.index) return isNumber(value) && isFinite(value) ? value : null @@ -136,13 +140,17 @@ export class RadialBar extends ComponentCore