diff --git "a/src/plugins/d3/__stories__/bar-x/\320\241ategoryAxis.stories.tsx" "b/src/plugins/d3/__stories__/bar-x/\320\241ategoryAxis.stories.tsx" index 2fa6c8fd..bc19e978 100644 --- "a/src/plugins/d3/__stories__/bar-x/\320\241ategoryAxis.stories.tsx" +++ "b/src/plugins/d3/__stories__/bar-x/\320\241ategoryAxis.stories.tsx" @@ -13,6 +13,11 @@ const Template: Story = () => { const chartkitRef = React.useRef(); const data: ChartKitWidgetData = { series: { + options: { + 'bar-x': { + barMaxWidth: 10, + }, + }, data: [ { type: 'bar-x', diff --git a/src/plugins/d3/renderer/components/Chart.tsx b/src/plugins/d3/renderer/components/Chart.tsx index d64c46ea..8367bb99 100644 --- a/src/plugins/d3/renderer/components/Chart.tsx +++ b/src/plugins/d3/renderer/components/Chart.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type {ChartKitWidgetData} from '../../../../types/widget-data'; +import type {ChartKitWidgetData} from '../../../../types'; import {block} from '../../../../utils/cn'; import {AxisY} from './AxisY'; @@ -59,6 +59,7 @@ export const Chart = (props: Props) => { boundsWidth, boundsHeight, series: preparedSeries, + seriesOptions: data.series.options, xAxis, xScale, yAxis, diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx b/src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx index bffda88b..4673a373 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx @@ -3,7 +3,7 @@ import type {ScaleBand, ScaleLinear, ScaleTime} from 'd3'; import React from 'react'; import get from 'lodash/get'; -import type {BarXSeriesData} from '../../../../../types'; +import type {BarXSeriesData, ChartKitWidgetSeriesOptions} from '../../../../../types'; import {block} from '../../../../../utils/cn'; import {getDataCategoryValue} from '../../utils'; @@ -11,11 +11,9 @@ import type {ChartScale} from '../useAxisScales'; import type {ChartOptions} from '../useChartOptions/types'; import type {OnSeriesMouseLeave, OnSeriesMouseMove} from '../useTooltip/types'; import type {PreparedBarXSeries} from '../useSeries/types'; +import {DEFAULT_BAR_X_SERIES_OPTIONS} from './defaults'; -const RECT_PADDING = 0.1; const MIN_RECT_GAP = 1; -const MAX_RECT_WIDTH = 50; -const GROUP_PADDING = 0.1; const MIN_GROUP_GAP = 1; const DEFAULT_LABEL_PADDING = 7; @@ -25,6 +23,7 @@ type Args = { top: number; left: number; series: PreparedBarXSeries[]; + seriesOptions?: ChartKitWidgetSeriesOptions; xAxis: ChartOptions['xAxis']; xScale: ChartScale; yAxis: ChartOptions['yAxis']; @@ -45,13 +44,22 @@ type ShapeData = { function prepareData(args: { series: PreparedBarXSeries[]; + seriesOptions?: ChartKitWidgetSeriesOptions; xAxis: ChartOptions['xAxis']; xScale: ChartScale; yAxis: ChartOptions['yAxis']; yScale: ChartScale; }) { - const {series, xAxis, xScale, yScale} = args; + const {series, seriesOptions, xAxis, xScale, yScale} = args; const categories = get(xAxis, 'categories', [] as string[]); + const { + barMaxWidth: defaultBarMaxWidth, + barPadding: defaultBarPadding, + groupPadding: defaultGroupPadding, + } = DEFAULT_BAR_X_SERIES_OPTIONS; + const barMaxWidth = get(seriesOptions, 'bar-x.barMaxWidth', defaultBarMaxWidth); + const barPadding = get(seriesOptions, 'bar-x.barPadding', defaultBarPadding); + const groupPadding = get(seriesOptions, 'bar-x.groupPadding', defaultGroupPadding); const data: Record< string | number, @@ -103,10 +111,10 @@ function prepareData(args: { } const maxGroupSize = max(Object.values(data), (d) => Object.values(d).length) || 1; - const groupGap = Math.max(bandWidth * GROUP_PADDING, MIN_GROUP_GAP); - const maxGroupWidth = bandWidth - groupGap; - const rectGap = Math.max((maxGroupWidth / maxGroupSize) * RECT_PADDING, MIN_RECT_GAP); - const rectWidth = Math.min(maxGroupWidth / maxGroupSize - rectGap, MAX_RECT_WIDTH); + const groupGap = Math.max(bandWidth * groupPadding, MIN_GROUP_GAP); + const groupWidth = bandWidth - groupGap; + const rectGap = Math.max(bandWidth * barPadding, MIN_RECT_GAP); + const rectWidth = Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth); const result: ShapeData[] = []; @@ -154,6 +162,7 @@ export function BarXSeriesShapes(args: Args) { top, left, series, + seriesOptions, xAxis, xScale, yAxis, @@ -175,6 +184,7 @@ export function BarXSeriesShapes(args: Args) { const shapes = prepareData({ series, + seriesOptions, xAxis, xScale, yAxis, diff --git a/src/plugins/d3/renderer/hooks/useShapes/defaults.ts b/src/plugins/d3/renderer/hooks/useShapes/defaults.ts new file mode 100644 index 00000000..a6b8fd4c --- /dev/null +++ b/src/plugins/d3/renderer/hooks/useShapes/defaults.ts @@ -0,0 +1,5 @@ +export const DEFAULT_BAR_X_SERIES_OPTIONS = { + barMaxWidth: 50, + barPadding: 0.1, + groupPadding: 0.2, +}; diff --git a/src/plugins/d3/renderer/hooks/useShapes/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/index.tsx index 0fb0fb41..b0379d76 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {group} from 'd3'; -import type {ScatterSeries} from '../../../../../types/widget-data'; +import type {ChartKitWidgetSeriesOptions, ScatterSeries} from '../../../../../types'; import {getRandomCKId} from '../../../../../utils'; import {getOnlyVisibleSeries} from '../../utils'; @@ -21,6 +21,7 @@ type Args = { boundsWidth: number; boundsHeight: number; series: PreparedSeries[]; + seriesOptions?: ChartKitWidgetSeriesOptions; xAxis: ChartOptions['xAxis']; yAxis: ChartOptions['yAxis']; svgContainer: SVGSVGElement | null; @@ -37,6 +38,7 @@ export const useShapes = (args: Args) => { boundsWidth, boundsHeight, series, + seriesOptions, xAxis, xScale, yAxis, @@ -59,6 +61,7 @@ export const useShapes = (args: Args) => { React.SVGTextElementAttributes; }; + + 'bar-x'?: { + /** The maximum allowed pixel width for a column. + * This prevents the columns from becoming too wide when there is a small number of points in the chart. + * + * @default 50 + */ + barMaxWidth?: number; + + /** Padding between each column or bar, in x axis units. + * + * @default 0.1 + * */ + barPadding?: number; + + /** Padding between each value groups, in x axis units + * + * @default 0.2 + */ + groupPadding?: number; + }; };