Skip to content

Commit

Permalink
feat: refactor barstack props
Browse files Browse the repository at this point in the history
  • Loading branch information
kristw committed Aug 4, 2020
1 parent b013fc6 commit fd8473c
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 105 deletions.
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/Arc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default function Arc<Datum>({
if (padAngle != null) setNumOrAccessor(arc.padAngle, padAngle);
if (padRadius != null) setNumOrAccessor(arc.padRadius, padRadius);

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ path: arc })}</>;
if (!data) return null;

Expand Down
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/Area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function Area<Datum>({
if (y1) setNumOrAccessor(path.y1, y1);
if (defined) path.defined(defined);
if (curve) path.curve(curve);
// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ path })}</>;
return (
<path ref={innerRef} className={cx('vx-area', className)} d={path(data) || ''} {...restProps} />
Expand Down
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/AreaClosed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function AreaClosed<Datum>({
if (y1 && !y) setNumOrAccessor(path.y1, y1);
if (defined) path.defined(defined);
if (curve) path.curve(curve);
// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ path })}</>;
return (
<path
Expand Down
10 changes: 3 additions & 7 deletions packages/vx-shape/src/shapes/BarGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Bar from './Bar';
import { PositionScale, DatumObject, AnyScaleBand, AddSVGProps } from '../types';
import { BaseBarGroupProps, BarGroup } from '../types/bar';
import { Accessor } from '../types/accessor';
import getBandwidth from '../util/getBandwidth';

export type BarGroupProps<
Datum extends DatumObject,
Expand Down Expand Up @@ -85,13 +86,7 @@ export default function BarGroupComponent<
children,
...restProps
}: AddSVGProps<BarGroupProps<Datum, Key, X0Scale, X1Scale>, SVGRectElement>) {
const x1Range = x1Scale.range();
const x1Domain = x1Scale.domain();

const barWidth =
'bandwidth' in x1Scale && typeof x1Scale.bandwidth === 'function'
? x1Scale.bandwidth()
: Math.abs(x1Range[x1Range.length - 1] - x1Range[0]) / x1Domain.length;
const barWidth = getBandwidth(x1Scale);

const barGroups: BarGroup<Key>[] = data.map((group, i) => ({
index: i,
Expand All @@ -111,6 +106,7 @@ export default function BarGroupComponent<
}),
}));

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children(barGroups)}</>;

return (
Expand Down
9 changes: 3 additions & 6 deletions packages/vx-shape/src/shapes/BarGroupHorizontal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Bar from './Bar';
import { PositionScale, AnyScaleBand, DatumObject, AddSVGProps } from '../types';
import { BarGroupHorizontal, BaseBarGroupProps } from '../types/bar';
import { Accessor } from '../types/accessor';
import getBandwidth from '../util/getBandwidth';

export type BarGroupHorizontalProps<
Datum extends DatumObject,
Expand Down Expand Up @@ -50,12 +51,7 @@ export default function BarGroupHorizontalComponent<
children,
...restProps
}: AddSVGProps<BarGroupHorizontalProps<Datum, Key, Y0Scale, Y1Scale>, SVGRectElement>) {
const y1Range = y1Scale.range();
const y1Domain = y1Scale.domain();
const barHeight =
'bandwidth' in y1Scale && typeof y1Scale.bandwidth === 'function'
? y1Scale.bandwidth()
: Math.abs(y1Range[y1Range.length - 1] - y1Range[0]) / y1Domain.length;
const barHeight = getBandwidth(y1Scale);

const barGroups: BarGroupHorizontal<Key>[] = data.map((group, i) => ({
index: i,
Expand All @@ -75,6 +71,7 @@ export default function BarGroupHorizontalComponent<
}),
}));

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children(barGroups)}</>;

return (
Expand Down
48 changes: 24 additions & 24 deletions packages/vx-shape/src/shapes/BarStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,39 @@ import cx from 'classnames';
import { Group } from '@vx/group';
import { stack as d3stack, SeriesPoint } from 'd3-shape';

import { ScaleInput } from '@vx/scale';
import stackOrder from '../util/stackOrder';
import stackOffset from '../util/stackOffset';
import Bar from './Bar';
import { StackProps } from './Stack';
import { StackKey, $TSFIXME, PositionScale, AddSVGProps } from '../types';
import setNumOrAccessor from '../util/setNumberOrNumberAccessor';
import { BarStack } from '../types/bar';
import { BarStack, BaseBarStackProps } from '../types/stack';
import getBandwidth from '../util/getBandwidth';

type PickProps = 'data' | 'className' | 'top' | 'left' | 'keys' | 'order' | 'offset' | 'value';

export type BarStackProps<Datum, Key> = Pick<StackProps<Datum, Key>, PickProps> & {
export type BarStackProps<
Datum,
Key,
XScale extends PositionScale = PositionScale,
YScale extends PositionScale = PositionScale
> = BaseBarStackProps<Datum, Key> & {
/** Returns the value mapped to the x of a bar. */
x: (d: Datum) => $TSFIXME;
x: (d: Datum) => ScaleInput<XScale>;
/** Returns the value mapped to the y0 of a bar. */
y0?: (d: SeriesPoint<Datum>) => $TSFIXME;
y0?: (d: SeriesPoint<Datum>) => ScaleInput<YScale>;
/** Returns the value mapped to the y1 of a bar. */
y1?: (d: SeriesPoint<Datum>) => $TSFIXME;
y1?: (d: SeriesPoint<Datum>) => ScaleInput<YScale>;
/** @vx/scale or d3-scale that takes an x value and maps it to an x axis position. */
xScale: PositionScale;
xScale: XScale;
/** @vx/scale or d3-scale that takes a y value and maps it to an y axis position. */
yScale: PositionScale;
/** Returns the desired color for a bar with a given key and index. */
color: (key: Key, index: number) => string;
/** Override render function which is passed the configured arc generator as input. */
children?: (stacks: BarStack<Datum, Key>[]) => React.ReactNode;
yScale: YScale;
};

export default function BarStackComponent<Datum, Key extends StackKey = StackKey>({
export default function BarStackComponent<
Datum,
Key extends StackKey = StackKey,
XScale extends PositionScale = PositionScale,
YScale extends PositionScale = PositionScale
>({
data,
className,
top,
Expand All @@ -47,21 +52,15 @@ export default function BarStackComponent<Datum, Key extends StackKey = StackKey
offset,
children,
...restProps
}: AddSVGProps<BarStackProps<Datum, Key>, SVGRectElement>) {
}: AddSVGProps<BarStackProps<Datum, Key, XScale, YScale>, SVGRectElement>) {
const stack = d3stack<Datum, Key>();
if (keys) stack.keys(keys);
if (value) setNumOrAccessor(stack.value, value);
if (order) stack.order(stackOrder(order));
if (offset) stack.offset(stackOffset(offset));

const stacks = stack(data);

const xRange = xScale.range();
const xDomain = xScale.domain();
const barWidth =
'bandwidth' in xScale && typeof xScale.bandwidth === 'function'
? xScale.bandwidth()
: Math.abs(xRange[xRange.length - 1] - xRange[0]) / xDomain.length;
const barWidth = getBandwidth(xScale);

const barStacks: BarStack<Datum, Key>[] = stacks.map((barStack, i) => {
const { key } = barStack;
Expand All @@ -72,7 +71,7 @@ export default function BarStackComponent<Datum, Key extends StackKey = StackKey
const barHeight = (yScale(y0(bar)) || 0) - (yScale(y1(bar)) || 0);
const barY = yScale(y1(bar));
const barX =
'bandwidth' in xScale && typeof xScale.bandwidth === 'function'
'bandwidth' in xScale
? xScale(x(bar.data))
: Math.max((xScale(x(bar.data)) || 0) - barWidth / 2);

Expand All @@ -90,6 +89,7 @@ export default function BarStackComponent<Datum, Key extends StackKey = StackKey
};
});

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children(barStacks)}</>;

return (
Expand Down
58 changes: 27 additions & 31 deletions packages/vx-shape/src/shapes/BarStackHorizontal.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
/* eslint-disable @typescript-eslint/unbound-method */
import React from 'react';
import cx from 'classnames';
import { Group } from '@vx/group';
import { stack as d3stack, SeriesPoint } from 'd3-shape';

import { ScaleInput } from '@vx/scale';
import stackOrder from '../util/stackOrder';
import stackOffset from '../util/stackOffset';
import Bar from './Bar';
import { BarStackProps } from './BarStack';
import { StackKey, $TSFIXME, AddSVGProps } from '../types';
import { StackKey, $TSFIXME, AddSVGProps, PositionScale } from '../types';
import setNumOrAccessor from '../util/setNumberOrNumberAccessor';
import { BaseBarStackProps } from '../types/stack';
import getBandwidth from '../util/getBandwidth';

type PickProps =
| 'data'
| 'className'
| 'top'
| 'left'
| 'keys'
| 'order'
| 'offset'
| 'value'
| 'xScale'
| 'yScale'
| 'color'
| 'children';

export type BarStackHorizontalProps<Datum, Key> = Pick<BarStackProps<Datum, Key>, PickProps> & {
export type BarStackHorizontalProps<
Datum,
Key,
XScale extends PositionScale = PositionScale,
YScale extends PositionScale = PositionScale
> = BaseBarStackProps<Datum, Key> & {
/** Returns the value mapped to the x0 of a bar. */
x0?: (d: SeriesPoint<Datum>) => $TSFIXME;
x0?: (d: SeriesPoint<Datum>) => ScaleInput<XScale>;
/** Returns the value mapped to the x1 of a bar. */
x1?: (d: SeriesPoint<Datum>) => $TSFIXME;
x1?: (d: SeriesPoint<Datum>) => ScaleInput<XScale>;
/** Returns the value mapped to the y of a bar. */
y: (d: Datum) => $TSFIXME;
y: (d: Datum) => ScaleInput<YScale>;
/** @vx/scale or d3-scale that takes an x value and maps it to an x axis position. */
xScale: XScale;
/** @vx/scale or d3-scale that takes a y value and maps it to an y axis position. */
yScale: YScale;
};

export default function BarStackHorizontal<Datum, Key extends StackKey = StackKey>({
export default function BarStackHorizontal<
Datum,
Key extends StackKey = StackKey,
XScale extends PositionScale = PositionScale,
YScale extends PositionScale = PositionScale
>({
data,
className,
top,
Expand All @@ -51,21 +52,15 @@ export default function BarStackHorizontal<Datum, Key extends StackKey = StackKe
offset,
children,
...restProps
}: AddSVGProps<BarStackHorizontalProps<Datum, Key>, SVGRectElement>) {
}: AddSVGProps<BarStackHorizontalProps<Datum, Key, XScale, YScale>, SVGRectElement>) {
const stack = d3stack<Datum, Key>();
if (keys) stack.keys(keys);
if (value) setNumOrAccessor(stack.value, value);
if (order) stack.order(stackOrder(order));
if (offset) stack.offset(stackOffset(offset));

const stacks = stack(data);

const yRange = yScale.range();
const yDomain = yScale.domain();
const barHeight =
'bandwidth' in yScale && typeof yScale.bandwidth === 'function'
? yScale.bandwidth()
: Math.abs(yRange[yRange.length - 1] - yRange[0]) / yDomain.length;
const barHeight = getBandwidth(yScale);

const barStacks = stacks.map((barStack, i) => {
const { key } = barStack;
Expand All @@ -76,7 +71,7 @@ export default function BarStackHorizontal<Datum, Key extends StackKey = StackKe
const barWidth = (xScale(x1(bar)) || 0) - (xScale(x0(bar)) || 0);
const barX = xScale(x0(bar));
const barY =
'bandwidth' in yScale && typeof yScale.bandwidth === 'function'
'bandwidth' in yScale
? yScale(y(bar.data))
: Math.max((yScale(y(bar.data)) || 0) - barWidth / 2);
return {
Expand All @@ -93,6 +88,7 @@ export default function BarStackHorizontal<Datum, Key extends StackKey = StackKe
};
});

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children(barStacks)}</>;

return (
Expand Down
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/LinePath.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function LinePath<Datum>({
if (y) path.y(y);
if (defined) path.defined(defined);
if (curve) path.curve(curve);
// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ path })}</>;
return (
<path
Expand Down
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/LineRadial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default function LineRadial<Datum>({
if (radius) setNumberOrNumberAccessor(path.radius, radius);
if (defined) path.defined(defined);
if (curve) path.curve(curve);
// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ path })}</>;
return (
<path
Expand Down
2 changes: 1 addition & 1 deletion packages/vx-shape/src/shapes/Pie.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/unbound-method */
import React from 'react';
import cx from 'classnames';
import { Group } from '@vx/group';
Expand Down Expand Up @@ -96,6 +95,7 @@ export default function Pie<Datum>({
if (endAngle != null) setNumOrAccessor<Accessor<Datum, number>>(pie.endAngle, endAngle);

const arcs = pie(data);
// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ arcs, path, pie })}</>;

return (
Expand Down
1 change: 1 addition & 0 deletions packages/vx-shape/src/shapes/Polygon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default function Polygon({
rotate,
}).map(({ x, y }) => [x, y]);

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ points })}</>;

return (
Expand Down
25 changes: 5 additions & 20 deletions packages/vx-shape/src/shapes/Stack.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/unbound-method */
import React from 'react';
import cx from 'classnames';
import { Group } from '@vx/group';
Expand All @@ -13,26 +12,17 @@ import {
} from 'd3-shape';

import setNumOrAccessor from '../util/setNumberOrNumberAccessor';
import stackOrder, { STACK_ORDERS } from '../util/stackOrder';
import stackOffset, { STACK_OFFSETS } from '../util/stackOffset';
import stackOrder from '../util/stackOrder';
import stackOffset from '../util/stackOffset';
import { StackKey, $TSFIXME, AddSVGProps } from '../types';
import { AccessorForArrayItem } from '../types/accessor';
import { BaseStackProps } from '../types/stack';

export type StackProps<Datum, Key> = {
/** Array of data for which to generate a stack. */
data: Datum[];
/** className applied to path element. */
className?: string;
/** Top offset of rendered Stack. */
top?: number;
/** Left offset of rendered Stack. */
left?: number;
export type StackProps<Datum, Key> = BaseStackProps<Datum, Key> & {
/** Sets the curve factory (from @vx/curve or d3-curve) for the area generator. Defaults to curveLinear. */
curve?: CurveFactory;
/** Returns a color for a given stack key and index. */
color?: (key: Key, index: number) => string;
/** Array of keys corresponding to stack layers. */
keys?: Key[];
/** Override render function which is passed the configured arc generator as input. */
children?: (args: {
stacks: Series<Datum, Key>[];
Expand All @@ -49,14 +39,8 @@ export type StackProps<Datum, Key> = {
y0?: AccessorForArrayItem<SeriesPoint<Datum>, number>;
/** Specifies the y1 accessor function which defaults to d => d[1]. */
y1?: AccessorForArrayItem<SeriesPoint<Datum>, number>;
/** Sets the value accessor for a Datum, which defaults to d[key]. */
value?: number | ((d: Datum, key: Key) => number);
/** The defined accessor for the shape. The final area shape includes all points for which this function returns true. By default all points are defined. */
defined?: AccessorForArrayItem<SeriesPoint<Datum>, boolean>;
/** Sets the stack order to the pre-defined d3 function, see https://github.com/d3/d3-shape#stack_order. */
order?: keyof typeof STACK_ORDERS;
/** Sets the stack offset to the pre-defined d3 offset, see https://github.com/d3/d3-shape#stack_offset. */
offset?: keyof typeof STACK_OFFSETS;
};

export default function Stack<Datum, Key = StackKey>({
Expand Down Expand Up @@ -96,6 +80,7 @@ export default function Stack<Datum, Key = StackKey>({

const stacks = stack(data);

// eslint-disable-next-line react/jsx-no-useless-fragment
if (children) return <>{children({ stacks, path, stack })}</>;

return (
Expand Down
Loading

0 comments on commit fd8473c

Please sign in to comment.