visx icon indicating copy to clipboard operation
visx copied to clipboard

xychart BarSeries has no way to specify roundness based on datum or bar height etc

Open rickymcgeehan opened this issue 7 months ago • 1 comments

I'm using BarSeries from @visx/xychart and I'm rounding the corners of each bar. However, I'd like to only round the top corners for positive values and the bottom corners for negative values (i.e. only round the outermost corners of each bar).

From looking at the API and having a quick look at the source code, it seems that there's no way to achieve this and instead one can only specify radiusTop or radiusBottom to be applied to the entire series.

I tried separating the data into 2 separate series - one for positive and one for negative - though this didn't play well with regards to tooltips and spacing of each bar.

Ideally we would be able to specify a function for each of the radius props in the BarSeries component. I believe it would require making the following changes:

  1. Add datum to the Bar object.
  2. Allow function that takes a Bar object to be passed into each radius prop
/** Bar shape. */
export type Bar<Datum extends object> = {
  /** Datum being represented. */
  datum: Datum;
  /** Unique key for Bar (not dataKey). */
  key: string;
  /** X coordinate of Bar. */
  x: number;
  /** Y coordinate of Bar. */
  y: number;
  /** Width of Bar. */
  width: number;
  /** Height of Bar. */
  height: number;
  /** Fill color of Bar */
  fill?: string;
};

/** Props for base Bars components */
export type BarsProps<XScale extends AxisScale, YScale extends AxisScale, <Datum extends object>> = {
  bars: Bar<Datum>[];
  xScale: XScale;
  yScale: YScale;
  horizontal?: boolean;
  /** Optional radius to apply to bar corners. */
  radius?: number | ((bar: Bar<Datum>) => number);
  /** Whether to apply radius to all corners. */
  radiusAll?: boolean | ((bar: Bar<Datum>) => boolean);
  /** Whether to apply radius to top corners. */
  radiusTop?: boolean | ((bar: Bar<Datum>) => boolean);
  /** Whether to apply radius to right corners. */
  radiusRight?: boolean | ((bar: Bar<Datum>) => boolean);
  /** Whether to apply radius to bottom corners. */
  radiusBottom?: boolean | ((bar: Bar<Datum>) => boolean);
  /** Whether to apply radius to left corners. */
  radiusLeft?: boolean | ((bar: Bar<Datum>) => boolean);
} & Omit<
  SVGProps<SVGRectElement | SVGPathElement>,
  'x' | 'y' | 'width' | 'height' | 'ref' | 'children'
>;

rickymcgeehan avatar May 08 '25 15:05 rickymcgeehan

I've submitted a PR: 1910

rickymcgeehan avatar May 08 '25 17:05 rickymcgeehan