From 32f82f4c9f9ca8ff57d75489932b8d88b063fd1a Mon Sep 17 00:00:00 2001 From: Nikas Praninskas Date: Thu, 30 May 2024 02:45:19 +0300 Subject: [PATCH] feat(xychart): improve performance when hovering with tooltip (#1842) --- .../visx-xychart/ExampleControls.tsx | 60 +++++++++++-------- .../series/private/AnimatedPath.tsx | 6 +- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/visx-demo/src/sandboxes/visx-xychart/ExampleControls.tsx b/packages/visx-demo/src/sandboxes/visx-xychart/ExampleControls.tsx index 5fccd96d3..c527ff9a5 100644 --- a/packages/visx-demo/src/sandboxes/visx-xychart/ExampleControls.tsx +++ b/packages/visx-demo/src/sandboxes/visx-xychart/ExampleControls.tsx @@ -16,14 +16,31 @@ import getAnimatedOrUnanimatedComponents from './getAnimatedOrUnanimatedComponen const dateScaleConfig = { type: 'band', paddingInner: 0.3 } as const; const temperatureScaleConfig = { type: 'linear' } as const; const numTicks = 4; -const data = cityTemperature.slice(225, 275); -const dataMissingValues = data.map((d, i) => - i === 10 || i === 11 - ? { ...d, 'San Francisco': 'nope', 'New York': 'notanumber', Austin: 'null' } - : d, -); -const dataSmall = data.slice(0, 15); -const dataSmallMissingValues = dataMissingValues.slice(0, 15); +const withMissingValues = (cityTemperatures: CityTemperature[]) => + cityTemperatures.map((d, i) => + i === 10 || i === 11 + ? { ...d, 'San Francisco': 'nope', 'New York': 'notanumber', Austin: 'null' } + : d, + ); +const addYears = (cityTemperatures: CityTemperature[], years: number) => + cityTemperatures.map((d) => { + const date = new Date(d.date); + date.setFullYear(date.getFullYear() + years); + return { + ...d, + date: date.toISOString().slice(0, 10), + }; + }); +const data = { + small: cityTemperature.slice(225, 240), + regular: cityTemperature.slice(225, 275), + large: [...cityTemperature, ...addYears(cityTemperature, 1), ...addYears(cityTemperature, 2)], +}; +const dataMissingValues = { + small: withMissingValues(data.small), + regular: withMissingValues(data.regular), + large: withMissingValues(data.large), +}; const getDate = (d: CityTemperature) => d.date; const getSfTemperature = (d: CityTemperature) => Number(d['San Francisco']); const getNegativeSfTemperature = (d: CityTemperature) => -getSfTemperature(d); @@ -128,7 +145,7 @@ export default function ExampleControls({ children }: ControlsProps) { const [annotationLabelPosition, setAnnotationLabelPosition] = useState({ dx: -40, dy: -20 }); const [annotationDataIndex, setAnnotationDataIndex] = useState(defaultAnnotationDataIndex); const [negativeValues, setNegativeValues] = useState(false); - const [fewerDatum, setFewerDatum] = useState(false); + const [dataSize, setDataSize] = useState('regular'); const [missingValues, setMissingValues] = useState(false); const [glyphComponent, setGlyphComponent] = useState<'star' | 'cross' | 'circle' | '🍍'>('star'); const [curveType, setCurveType] = useState<'linear' | 'cardinal' | 'step'>('linear'); @@ -302,13 +319,7 @@ export default function ExampleControls({ children }: ControlsProps) { (curveType === 'cardinal' && curveCardinal) || (curveType === 'step' && curveStep) || curveLinear, - data: fewerDatum - ? missingValues - ? dataSmallMissingValues - : dataSmall - : missingValues - ? dataMissingValues - : data, + data: (missingValues ? dataMissingValues : data)[dataSize], editAnnotationLabelPosition, numTicks, renderBarGroup: renderBarStackOrGroup === 'bargroup', @@ -370,14 +381,15 @@ export default function ExampleControls({ children }: ControlsProps) { /> missing values - + +
+ data size + {Object.keys(data).map((size: keyof typeof data) => ( + + ))}
{/** theme */} diff --git a/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx b/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx index a5b9c78f0..b8895bd80 100644 --- a/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx +++ b/packages/visx-xychart/src/components/series/private/AnimatedPath.tsx @@ -1,10 +1,10 @@ -import React, { useCallback, useRef } from 'react'; +import React, { memo, useCallback, useRef } from 'react'; import { animated, useSpring } from '@react-spring/web'; // @ts-expect-error no types import { interpolatePath } from 'd3-interpolate-path'; import debounce from 'lodash/debounce'; -export default function AnimatedPath({ +function AnimatedPath({ d, stroke = 'transparent', fill = 'transparent', @@ -44,3 +44,5 @@ export default function AnimatedPath({ /> ); } + +export default memo(AnimatedPath);