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 && (
<>
-
- ({ ...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
index b66d8e02a..b3f6d9341 100644
--- a/packages/visx-xychart/src/components/series/LineSeries.tsx
+++ b/packages/visx-xychart/src/components/series/LineSeries.tsx
@@ -1,78 +1,11 @@
-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 React from 'react';
+import BaseLineSeries, { BaseLineSeriesProps } from './private/BaseLineSeries';
-type LineSeriesProps<
+export default function LineSeries<
XScale extends AxisScale,
YScale extends AxisScale,
Datum extends object
-> = SeriesProps & {
- /** Whether line should be rendered horizontally instead of vertically. */
- horizontal?: boolean;
-};
-
-function LineSeries({
- data,
- dataKey,
- xAccessor,
- xScale,
- yAccessor,
- yScale,
- horizontal = true,
- ...lineProps
-}: LineSeriesProps & WithRegisteredDataProps) {
- const { colorScale, theme, width, height } = useContext(DataContext);
- const { showTooltip, hideTooltip } = useContext(TooltipContext) ?? {};
- const getScaledX = useCallback(getScaledValueFactory(xScale, xAccessor), [xScale, xAccessor]);
- const getScaledY = useCallback(getScaledValueFactory(yScale, yAccessor), [yScale, yAccessor]);
- const color = colorScale?.(dataKey) ?? theme?.colors?.[0] ?? '#222';
-
- const handleMouseMove = useCallback(
- (params?: HandlerParams) => {
- const { svgPoint } = params || {};
- if (svgPoint && width && height && showTooltip) {
- const datum = (horizontal ? findNearestDatumX : findNearestDatumY)({
- point: svgPoint,
- data,
- xScale,
- yScale,
- xAccessor,
- yAccessor,
- width,
- height,
- });
- if (datum) {
- showTooltip({
- key: dataKey,
- ...datum,
- svgPoint,
- });
- }
- }
- },
- [dataKey, data, xScale, yScale, xAccessor, yAccessor, width, height, showTooltip, horizontal],
- );
- useEventEmitter('mousemove', handleMouseMove);
- useEventEmitter('mouseout', hideTooltip);
-
- return (
-
- );
+>({ ...props }: Omit, 'PathComponent'>) {
+ return {...props} />;
}
-
-export default withRegisteredData(LineSeries);
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/BaseBarGroup.tsx b/packages/visx-xychart/src/components/series/private/BaseBarGroup.tsx
index afc63ad7d..1175bde42 100644
--- a/packages/visx-xychart/src/components/series/private/BaseBarGroup.tsx
+++ b/packages/visx-xychart/src/components/series/private/BaseBarGroup.tsx
@@ -21,7 +21,7 @@ export type BaseBarGroupProps number;
- /** Rendered component which is passed BarsProps by BaseBarSeries after processing. */
+ /** Rendered component which is passed BarsProps by BaseBarGroup after processing. */
BarsComponent: React.FC>;
};
diff --git a/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx b/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx
new file mode 100644
index 000000000..571726117
--- /dev/null
+++ b/packages/visx-xychart/src/components/series/private/BaseLineSeries.tsx
@@ -0,0 +1,85 @@
+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';
+
+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 BaseLineSeries({
+ data,
+ dataKey,
+ xAccessor,
+ xScale,
+ yAccessor,
+ yScale,
+ horizontal = true,
+ PathComponent = 'path',
+ ...lineProps
+}: BaseLineSeriesProps & WithRegisteredDataProps) {
+ const { colorScale, theme, width, height } = useContext(DataContext);
+ const { showTooltip, hideTooltip } = useContext(TooltipContext) ?? {};
+ const getScaledX = useCallback(getScaledValueFactory(xScale, xAccessor), [xScale, xAccessor]);
+ const getScaledY = useCallback(getScaledValueFactory(yScale, yAccessor), [yScale, yAccessor]);
+ const color = colorScale?.(dataKey) ?? theme?.colors?.[0] ?? '#222';
+
+ const handleMouseMove = useCallback(
+ (params?: HandlerParams) => {
+ const { svgPoint } = params || {};
+ if (svgPoint && width && height && showTooltip) {
+ const datum = (horizontal ? findNearestDatumX : findNearestDatumY)({
+ point: svgPoint,
+ data,
+ xScale,
+ yScale,
+ xAccessor,
+ yAccessor,
+ width,
+ height,
+ });
+ if (datum) {
+ showTooltip({
+ key: dataKey,
+ ...datum,
+ svgPoint,
+ });
+ }
+ }
+ },
+ [dataKey, data, xScale, yScale, xAccessor, yAccessor, width, height, showTooltip, horizontal],
+ );
+ useEventEmitter('mousemove', handleMouseMove);
+ useEventEmitter('mouseout', hideTooltip);
+
+ return (
+
+ {({ path }) => (
+
+ )}
+
+ );
+}
+
+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..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;
}
+ // @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;
};
}
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);
+ });
+});