Skip to content

Commit

Permalink
feat(D3 plugin): bar-x series options (#280)
Browse files Browse the repository at this point in the history
* feat(D3 plugin): bar-x series options

* fix
  • Loading branch information
kuzmadom authored Sep 7, 2023
1 parent 8dae886 commit 637a64e
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/plugins/d3/__stories__/bar-x/СategoryAxis.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ const Template: Story = () => {
const chartkitRef = React.useRef<ChartKitRef>();
const data: ChartKitWidgetData = {
series: {
options: {
'bar-x': {
barMaxWidth: 10,
},
},
data: [
{
type: 'bar-x',
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/d3/renderer/components/Chart.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -59,6 +59,7 @@ export const Chart = (props: Props) => {
boundsWidth,
boundsHeight,
series: preparedSeries,
seriesOptions: data.series.options,
xAxis,
xScale,
yAxis,
Expand Down
28 changes: 19 additions & 9 deletions src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ 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';
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;

Expand All @@ -25,6 +23,7 @@ type Args = {
top: number;
left: number;
series: PreparedBarXSeries[];
seriesOptions?: ChartKitWidgetSeriesOptions;
xAxis: ChartOptions['xAxis'];
xScale: ChartScale;
yAxis: ChartOptions['yAxis'];
Expand All @@ -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,
Expand Down Expand Up @@ -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[] = [];

Expand Down Expand Up @@ -154,6 +162,7 @@ export function BarXSeriesShapes(args: Args) {
top,
left,
series,
seriesOptions,
xAxis,
xScale,
yAxis,
Expand All @@ -175,6 +184,7 @@ export function BarXSeriesShapes(args: Args) {

const shapes = prepareData({
series,
seriesOptions,
xAxis,
xScale,
yAxis,
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/d3/renderer/hooks/useShapes/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const DEFAULT_BAR_X_SERIES_OPTIONS = {
barMaxWidth: 50,
barPadding: 0.1,
groupPadding: 0.2,
};
5 changes: 4 additions & 1 deletion src/plugins/d3/renderer/hooks/useShapes/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -21,6 +21,7 @@ type Args = {
boundsWidth: number;
boundsHeight: number;
series: PreparedSeries[];
seriesOptions?: ChartKitWidgetSeriesOptions;
xAxis: ChartOptions['xAxis'];
yAxis: ChartOptions['yAxis'];
svgContainer: SVGSVGElement | null;
Expand All @@ -37,6 +38,7 @@ export const useShapes = (args: Args) => {
boundsWidth,
boundsHeight,
series,
seriesOptions,
xAxis,
xScale,
yAxis,
Expand All @@ -59,6 +61,7 @@ export const useShapes = (args: Args) => {
<BarXSeriesShapes
key="bar-x"
series={chartSeries as PreparedBarXSeries[]}
seriesOptions={seriesOptions}
xAxis={xAxis}
xScale={xScale}
yAxis={yAxis}
Expand Down
21 changes: 21 additions & 0 deletions src/types/widget-data/series.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,25 @@ export type ChartKitWidgetSeriesOptions = {
/** Callback function to render the data label */
renderer?: (args: DataLabelRendererData) => React.SVGTextElementAttributes<SVGTextElement>;
};

'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;
};
};

0 comments on commit 637a64e

Please sign in to comment.