From ceb608f814dc7aab488e6954e20e2e13f21bcc80 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 15 Oct 2020 15:10:25 -0700 Subject: [PATCH 1/5] internal(xychart): LineSeries => private/BaseLineSeries --- .../series/{LineSeries.tsx => private/BaseLineSeries.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/visx-xychart/src/components/series/{LineSeries.tsx => private/BaseLineSeries.tsx} (100%) diff --git a/packages/visx-xychart/src/components/series/LineSeries.tsx b/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx similarity index 100% rename from packages/visx-xychart/src/components/series/LineSeries.tsx rename to packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx From 3825d9314311d52449c02a49136794769546de6f Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 15 Oct 2020 15:12:16 -0700 Subject: [PATCH 2/5] new(xychart): add AnimatedLineSeries, LineSeries, AnimatedPath --- .../components/series/AnimatedLineSeries.tsx | 12 +++++++ .../src/components/series/LineSeries.tsx | 11 +++++++ .../series/private/AnimatedPath.tsx | 11 +++++++ .../series/private/BaseLineSeries.tsx | 33 +++++++++++-------- packages/visx-xychart/src/index.ts | 1 + .../src/utils/getScaledValueFactory.ts | 2 +- 6 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 packages/visx-xychart/src/components/series/AnimatedLineSeries.tsx create mode 100644 packages/visx-xychart/src/components/series/LineSeries.tsx create mode 100644 packages/visx-xychart/src/components/series/private/AnimatedPath.tsx diff --git a/packages/visx-xychart/src/components/series/AnimatedLineSeries.tsx b/packages/visx-xychart/src/components/series/AnimatedLineSeries.tsx new file mode 100644 index 000000000..c904dc29e --- /dev/null +++ b/packages/visx-xychart/src/components/series/AnimatedLineSeries.tsx @@ -0,0 +1,12 @@ +import { AxisScale } from '@visx/axis'; +import React from 'react'; +import BaseLineSeries, { BaseLineSeriesProps } from './private/BaseLineSeries'; +import AnimatedPath from './private/AnimatedPath'; + +export default function AnimatedLineSeries< + XScale extends AxisScale, + YScale extends AxisScale, + Datum extends object +>({ ...props }: Omit, 'PathComponent'>) { + return {...props} PathComponent={AnimatedPath} />; +} diff --git a/packages/visx-xychart/src/components/series/LineSeries.tsx b/packages/visx-xychart/src/components/series/LineSeries.tsx new file mode 100644 index 000000000..b3f6d9341 --- /dev/null +++ b/packages/visx-xychart/src/components/series/LineSeries.tsx @@ -0,0 +1,11 @@ +import { AxisScale } from '@visx/axis'; +import React from 'react'; +import BaseLineSeries, { BaseLineSeriesProps } from './private/BaseLineSeries'; + +export default function LineSeries< + XScale extends AxisScale, + YScale extends AxisScale, + Datum extends object +>({ ...props }: Omit, 'PathComponent'>) { + return {...props} />; +} diff --git a/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx b/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx new file mode 100644 index 000000000..dbd519cf0 --- /dev/null +++ b/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { animated, useSpring } from 'react-spring'; + +export default function AnimatedPath({ + d, + stroke, + ...lineProps +}: Omit, 'ref'>) { + const tweened = useSpring({ d, stroke, config: { precision: 0.01 } }); + return ; +} diff --git a/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx b/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx index b66d8e02a..571726117 100644 --- a/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx +++ b/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx @@ -1,25 +1,27 @@ import React, { useContext, useCallback } from 'react'; import LinePath from '@visx/shape/lib/shapes/LinePath'; import { AxisScale } from '@visx/axis'; -import DataContext from '../../context/DataContext'; -import { SeriesProps } from '../../types'; -import withRegisteredData, { WithRegisteredDataProps } from '../../enhancers/withRegisteredData'; -import getScaledValueFactory from '../../utils/getScaledValueFactory'; -import useEventEmitter, { HandlerParams } from '../../hooks/useEventEmitter'; -import findNearestDatumX from '../../utils/findNearestDatumX'; -import TooltipContext from '../../context/TooltipContext'; -import findNearestDatumY from '../../utils/findNearestDatumY'; +import DataContext from '../../../context/DataContext'; +import { SeriesProps } from '../../../types'; +import withRegisteredData, { WithRegisteredDataProps } from '../../../enhancers/withRegisteredData'; +import getScaledValueFactory from '../../../utils/getScaledValueFactory'; +import useEventEmitter, { HandlerParams } from '../../../hooks/useEventEmitter'; +import findNearestDatumX from '../../../utils/findNearestDatumX'; +import TooltipContext from '../../../context/TooltipContext'; +import findNearestDatumY from '../../../utils/findNearestDatumY'; -type LineSeriesProps< +export type BaseLineSeriesProps< XScale extends AxisScale, YScale extends AxisScale, Datum extends object > = SeriesProps & { /** Whether line should be rendered horizontally instead of vertically. */ horizontal?: boolean; + /** Rendered component which is passed path props by BaseLineSeries after processing. */ + PathComponent?: React.FC, 'ref'>> | 'path'; }; -function LineSeries({ +function BaseLineSeries({ data, dataKey, xAccessor, @@ -27,8 +29,9 @@ function LineSeries & WithRegisteredDataProps) { +}: BaseLineSeriesProps & WithRegisteredDataProps) { const { colorScale, theme, width, height } = useContext(DataContext); const { showTooltip, hideTooltip } = useContext(TooltipContext) ?? {}; const getScaledX = useCallback(getScaledValueFactory(xScale, xAccessor), [xScale, xAccessor]); @@ -71,8 +74,12 @@ function LineSeries + > + {({ path }) => ( + + )} + ); } -export default withRegisteredData(LineSeries); +export default withRegisteredData(BaseLineSeries); diff --git a/packages/visx-xychart/src/index.ts b/packages/visx-xychart/src/index.ts index 3354fa667..7e36c152f 100644 --- a/packages/visx-xychart/src/index.ts +++ b/packages/visx-xychart/src/index.ts @@ -16,6 +16,7 @@ export { default as LineSeries } from './components/series/LineSeries'; export { default as AnimatedBarSeries } from './components/series/AnimatedBarSeries'; export { default as AnimatedBarStack } from './components/series/AnimatedBarStack'; export { default as AnimatedBarGroup } from './components/series/AnimatedBarGroup'; +export { default as AnimatedLineSeries } from './components/series/AnimatedLineSeries'; // context export { default as DataContext } from './context/DataContext'; diff --git a/packages/visx-xychart/src/utils/getScaledValueFactory.ts b/packages/visx-xychart/src/utils/getScaledValueFactory.ts index 92a744437..4513f4461 100644 --- a/packages/visx-xychart/src/utils/getScaledValueFactory.ts +++ b/packages/visx-xychart/src/utils/getScaledValueFactory.ts @@ -16,6 +16,6 @@ export default function getScaledValueFactory( (align === 'start' ? 0 : getScaleBandwidth(scale)) / (align === 'center' ? 2 : 1); return scaledValue + bandwidthOffset; } - return NaN; + return null; }; } From 09875854ad5e3d529058ef02348a1da6b379e4dc Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 15 Oct 2020 15:12:59 -0700 Subject: [PATCH 3/5] new(demo/xychart): use AnimatedLineSeries --- .../visx-demo/src/sandboxes/visx-xychart/Example.tsx | 10 +++++----- .../src/components/series/private/BaseBarGroup.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/visx-demo/src/sandboxes/visx-xychart/Example.tsx b/packages/visx-demo/src/sandboxes/visx-xychart/Example.tsx index 3ec17ddd9..365e26c78 100644 --- a/packages/visx-demo/src/sandboxes/visx-xychart/Example.tsx +++ b/packages/visx-demo/src/sandboxes/visx-xychart/Example.tsx @@ -2,12 +2,12 @@ import React from 'react'; import { CityTemperature } from '@visx/mock-data/lib/mocks/cityTemperature'; import { AnimatedAxis, - AnimatedGrid, - DataProvider, AnimatedBarGroup, AnimatedBarSeries, AnimatedBarStack, - LineSeries, + AnimatedGrid, + AnimatedLineSeries, + DataProvider, Tooltip, XYChart, } from '@visx/xychart'; @@ -112,14 +112,14 @@ export default function Example({ height }: Props) { )} {renderLineSeries && ( <> - - number; - /** Rendered component which is passed BarsProps by BaseBarSeries after processing. */ + /** Rendered component which is passed BarsProps by BaseBarGroup after processing. */ BarsComponent: React.FC>; }; From 5b887336e57d5ddb97921a1dfd307972f6f3e45d Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 15 Oct 2020 15:13:24 -0700 Subject: [PATCH 4/5] test(xychart): add Animated(BarGroup, BarStack, BarSeries, LineSeries) tests --- .../test/components/BarGroup.test.tsx | 24 ++++++++++++-- .../test/components/BarSeries.test.tsx | 19 +++++++++++- .../test/components/BarStack.test.tsx | 31 +++++++++++++++++-- .../test/components/LineSeries.test.tsx | 19 +++++++++++- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/packages/visx-xychart/test/components/BarGroup.test.tsx b/packages/visx-xychart/test/components/BarGroup.test.tsx index a492b53d5..f7b64decc 100644 --- a/packages/visx-xychart/test/components/BarGroup.test.tsx +++ b/packages/visx-xychart/test/components/BarGroup.test.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from 'react'; +import { animated } from 'react-spring'; import { mount } from 'enzyme'; -import { BarGroup, BarSeries, DataProvider, useEventEmitter } from '../../src'; +import { AnimatedBarGroup, BarGroup, BarSeries, DataProvider, useEventEmitter } from '../../src'; import setupTooltipTest from '../mocks/setupTooltipTest'; const providerProps = { @@ -77,7 +78,7 @@ describe('', () => { setupTooltipTest( <> - + @@ -87,3 +88,22 @@ describe('', () => { ); }); }); + +describe('', () => { + it('should be defined', () => { + expect(AnimatedBarGroup).toBeDefined(); + }); + it('should render an animated.rect', () => { + const wrapper = mount( + + + + + + + + , + ); + expect(wrapper.find(animated.rect)).toHaveLength(4); + }); +}); diff --git a/packages/visx-xychart/test/components/BarSeries.test.tsx b/packages/visx-xychart/test/components/BarSeries.test.tsx index e6633ad56..19b9bf5d9 100644 --- a/packages/visx-xychart/test/components/BarSeries.test.tsx +++ b/packages/visx-xychart/test/components/BarSeries.test.tsx @@ -1,6 +1,7 @@ import React, { useContext, useEffect } from 'react'; +import { animated } from 'react-spring'; import { mount } from 'enzyme'; -import { DataContext, BarSeries, useEventEmitter } from '../../src'; +import { DataContext, AnimatedBarSeries, BarSeries, useEventEmitter } from '../../src'; import getDataContext from '../mocks/getDataContext'; import setupTooltipTest from '../mocks/setupTooltipTest'; @@ -62,3 +63,19 @@ describe('', () => { ); }); }); + +describe('', () => { + it('should be defined', () => { + expect(AnimatedBarSeries).toBeDefined(); + }); + it('should render an animated.rect', () => { + const wrapper = mount( + + + + + , + ); + expect(wrapper.find(animated.rect)).toHaveLength(series.data.length); + }); +}); diff --git a/packages/visx-xychart/test/components/BarStack.test.tsx b/packages/visx-xychart/test/components/BarStack.test.tsx index a34edaafa..ec50b9414 100644 --- a/packages/visx-xychart/test/components/BarStack.test.tsx +++ b/packages/visx-xychart/test/components/BarStack.test.tsx @@ -1,6 +1,14 @@ import React, { useContext, useEffect } from 'react'; import { mount } from 'enzyme'; -import { BarStack, BarSeries, DataProvider, DataContext, useEventEmitter } from '../../src'; +import { animated } from 'react-spring'; +import { + BarStack, + BarSeries, + DataProvider, + DataContext, + useEventEmitter, + AnimatedBarStack, +} from '../../src'; import setupTooltipTest from '../mocks/setupTooltipTest'; const providerProps = { @@ -108,7 +116,7 @@ describe('', () => { setupTooltipTest( <> - + @@ -118,3 +126,22 @@ describe('', () => { ); }); }); + +describe('', () => { + it('should be defined', () => { + expect(AnimatedBarStack).toBeDefined(); + }); + it('should render an animated.rect', () => { + const wrapper = mount( + + + + + + + + , + ); + expect(wrapper.find(animated.rect)).toHaveLength(4); + }); +}); diff --git a/packages/visx-xychart/test/components/LineSeries.test.tsx b/packages/visx-xychart/test/components/LineSeries.test.tsx index 7a0ab8890..928ae7116 100644 --- a/packages/visx-xychart/test/components/LineSeries.test.tsx +++ b/packages/visx-xychart/test/components/LineSeries.test.tsx @@ -1,7 +1,8 @@ import React, { useContext, useEffect } from 'react'; +import { animated } from 'react-spring'; import { mount } from 'enzyme'; import { LinePath } from '@visx/shape'; -import { DataContext, LineSeries, useEventEmitter } from '../../src'; +import { AnimatedLineSeries, DataContext, LineSeries, useEventEmitter } from '../../src'; import getDataContext from '../mocks/getDataContext'; import setupTooltipTest from '../mocks/setupTooltipTest'; @@ -64,3 +65,19 @@ describe('', () => { ); }); }); + +describe('', () => { + it('should be defined', () => { + expect(AnimatedLineSeries).toBeDefined(); + }); + it('should render an animated.path', () => { + const wrapper = mount( + + + + + , + ); + expect(wrapper.find(animated.path)).toHaveLength(1); + }); +}); From 81044b866fa476dfdfeb17d7a3706ca586003c04 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Thu, 15 Oct 2020 21:49:07 -0700 Subject: [PATCH 5/5] fix(xychart/getScaledValueFactory): return NaN instead of null --- packages/visx-xychart/src/utils/getScaledValueFactory.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/visx-xychart/src/utils/getScaledValueFactory.ts b/packages/visx-xychart/src/utils/getScaledValueFactory.ts index 4513f4461..579a80564 100644 --- a/packages/visx-xychart/src/utils/getScaledValueFactory.ts +++ b/packages/visx-xychart/src/utils/getScaledValueFactory.ts @@ -16,6 +16,10 @@ export default function getScaledValueFactory( (align === 'start' ? 0 : getScaleBandwidth(scale)) / (align === 'center' ? 2 : 1); return scaledValue + bandwidthOffset; } - return null; + // @TODO: NaNs cause react-spring to throw, but the return value of this must be number + // this currently causes issues in vertical <> horizontal transitions because + // x/yAccessors from context are out of sync with props.horizontal + // horizontal should be moved to context + return NaN; }; }