From cf4f172ad72379f928a8f41d7bef34f97ef648b9 Mon Sep 17 00:00:00 2001 From: Simon Schippl Date: Tue, 14 May 2024 09:11:39 +1000 Subject: [PATCH 1/4] Remove unused code --- example/src/line-data-gh.json | 18 ---- src/charts/candle/HoverTrap/index.web.tsx | 109 ---------------------- src/charts/candle/utils.ts | 56 ----------- 3 files changed, 183 deletions(-) delete mode 100644 example/src/line-data-gh.json delete mode 100644 src/charts/candle/HoverTrap/index.web.tsx delete mode 100644 src/charts/candle/utils.ts diff --git a/example/src/line-data-gh.json b/example/src/line-data-gh.json deleted file mode 100644 index 8b44f4d..0000000 --- a/example/src/line-data-gh.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "timestamp": 1625945400000, - "value": 33215.25 - }, - { - "timestamp": 1625946300000, - "value": 33545.25 - }, - { - "timestamp": 1625947200000, - "value": 33510.25 - }, - { - "timestamp": 1625948100000, - "value": 33575.25 - } -] diff --git a/src/charts/candle/HoverTrap/index.web.tsx b/src/charts/candle/HoverTrap/index.web.tsx deleted file mode 100644 index 4be0140..0000000 --- a/src/charts/candle/HoverTrap/index.web.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import * as React from 'react'; -import { View, StyleSheet } from 'react-native'; -import { parse } from 'react-native-redash'; - -import { LineChartDimensionsContext } from '../../line/Chart'; -import { useLineChart } from '../../line/useLineChart'; - -import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment'; - -let isEnabled = false; - -// the following logic comes from the creator of react-native-web -// https://gist.github.com/necolas/1c494e44e23eb7f8c5864a2fac66299a -// it's also used by MotiPressable's hover interactions -// https://github.com/nandorojo/moti/blob/master/packages/interactions/src/pressable/hoverable.tsx -if (canUseDOM) { - /** - * Web browsers emulate mouse events (and hover states) after touch events. - * This code infers when the currently-in-use modality supports hover - * (including for multi-modality devices) and considers "hover" to be enabled - * if a mouse movement occurs more than 1 second after the last touch event. - * This threshold is long enough to account for longer delays between the - * browser firing touch and mouse events on low-powered devices. - */ - const HOVER_THRESHOLD_MS = 1000; - let lastTouchTimestamp = 0; - - function enableHover() { - if (isEnabled || Date.now() - lastTouchTimestamp < HOVER_THRESHOLD_MS) { - return; - } - isEnabled = true; - } - - function disableHover() { - lastTouchTimestamp = Date.now(); - if (isEnabled) { - isEnabled = false; - } - } - - document.addEventListener('touchstart', disableHover, true); - document.addEventListener('touchmove', disableHover, true); - document.addEventListener('mousemove', enableHover, true); -} - -function isHoverEnabled(): boolean { - return isEnabled; -} - -export const LineChartHoverTrap = () => { - const { width, path } = React.useContext(LineChartDimensionsContext); - const { currentX, currentIndex, isActive, data } = useLineChart(); - - const parsedPath = React.useMemo( - () => (path ? parse(path) : undefined), - [path] - ); - - const onMouseMove = React.useCallback( - ({ x }: { x: number }) => { - if (isHoverEnabled()) { - if (parsedPath) { - const boundedX = Math.min(x, width); - isActive.value = true; - currentX.value = boundedX; - - // on Web, we could drag the cursor to be negative, breaking it - // so we clamp the index at 0 to fix it - // https://github.com/coinjar/react-native-wagmi-charts/issues/24 - const minIndex = 0; - const boundedIndex = Math.max( - minIndex, - Math.round(boundedX / width / (1 / (data.length - 1))) - ); - - currentIndex.value = boundedIndex; - } - } else { - isActive.value = false; - currentIndex.value = -1; - } - }, - [currentIndex, currentX, data.length, isActive, parsedPath, width] - ); - - const onMouseLeave = React.useCallback(() => { - isActive.value = false; - currentIndex.value = -1; - }, [currentIndex, isActive]); - - return ( - ) => { - let rect = e.currentTarget.getBoundingClientRect(); - let x = e.clientX - rect.left; // x position within the element. - - onMouseMove({ x }); - }, - [onMouseMove] - )} - onMouseLeave={onMouseLeave} - /> - ); -}; diff --git a/src/charts/candle/utils.ts b/src/charts/candle/utils.ts deleted file mode 100644 index 0470e4a..0000000 --- a/src/charts/candle/utils.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { interpolate, Extrapolate } from 'react-native-reanimated'; - -import type { TCandle, TDomain } from './types'; - -export function getDomain(rows: TCandle[]): [min: number, max: number] { - 'worklet'; - const values = rows.map(({ high, low }) => [high, low]).flat(); - const min = Math.min(...values); - const max = Math.max(...values); - return [min - (max - min) * 0.025, max + (max - min) * 0.025]; -} - -export function getY({ - value, - domain, - maxHeight, -}: { - value: number; - domain: TDomain; - maxHeight: number; -}) { - 'worklet'; - return interpolate(value, domain, [maxHeight, 0], Extrapolate.CLAMP); -} - -export function getHeight({ - value, - domain, - maxHeight, -}: { - value: number; - domain: TDomain; - maxHeight: number; -}) { - 'worklet'; - return interpolate( - value, - [0, Math.max(...domain) - Math.min(...domain)], - [0, maxHeight], - Extrapolate.CLAMP - ); -} - -export function getPrice({ - y, - domain, - maxHeight, -}: { - y: number; - domain: TDomain; - maxHeight: number; -}) { - 'worklet'; - if (y === -1) return -1; - return interpolate(y, [0, maxHeight], domain.reverse(), Extrapolate.CLAMP); -} From 51958c23d50beafa61d26dcd33f00692408e5ab6 Mon Sep 17 00:00:00 2001 From: Simon Schippl Date: Tue, 14 May 2024 09:57:30 +1000 Subject: [PATCH 2/4] Format files --- example/README.md | 1 - example/src/App.tsx | 4 +- example/src/CandlestickChart.tsx | 8 +- example/src/LineChart.tsx | 24 +-- example/src/data/candlestick-data2.json | 202 ++++++++++++------------ src/charts/candle/Candle.tsx | 10 +- 6 files changed, 119 insertions(+), 130 deletions(-) diff --git a/example/README.md b/example/README.md index d6809e1..a6be72a 100644 --- a/example/README.md +++ b/example/README.md @@ -28,7 +28,6 @@ For Web: yarn run web ``` - ## Example Charts The following charts are included: diff --git a/example/src/App.tsx b/example/src/App.tsx index f37ef53..3ec3ce6 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -25,9 +25,7 @@ export default function App() { paddingY="major-2" alignY="center" > - - React Native WAGMI Charts 💸 - + React Native WAGMI Charts 💸 {selected ? ( - + + + diff --git a/example/src/LineChart.tsx b/example/src/LineChart.tsx index 82533ab..9735845 100644 --- a/example/src/LineChart.tsx +++ b/example/src/LineChart.tsx @@ -81,7 +81,7 @@ export default function App() { )} @@ -157,8 +157,8 @@ export default function App() { > {chart} - Load Data - + Load Data + @@ -196,25 +196,25 @@ export default function App() { - - + + - + + - {!multiData && ( diff --git a/example/src/data/candlestick-data2.json b/example/src/data/candlestick-data2.json index efb5ddf..4a69596 100644 --- a/example/src/data/candlestick-data2.json +++ b/example/src/data/candlestick-data2.json @@ -1,142 +1,142 @@ [ { - "timestamp": 1625962500000, - "open": 33870.25, - "high": 33930.52, - "low": 33715.12, - "close": 33770.11 + "timestamp": 1625962500000, + "open": 33870.25, + "high": 33930.52, + "low": 33715.12, + "close": 33770.11 }, { - "timestamp": 1625961600000, - "open": 33670.25, - "high": 33835.52, - "low": 33635.12, - "close": 33825.11 + "timestamp": 1625961600000, + "open": 33670.25, + "high": 33835.52, + "low": 33635.12, + "close": 33825.11 }, { - "timestamp": 1625960700000, - "open": 33760.25, - "high": 33785.52, - "low": 33645.12, - "close": 33650.11 + "timestamp": 1625960700000, + "open": 33760.25, + "high": 33785.52, + "low": 33645.12, + "close": 33650.11 }, { - "timestamp": 1625959800000, - "open": 33705.25, - "high": 33760.52, - "low": 33705.12, - "close": 33750.11 + "timestamp": 1625959800000, + "open": 33705.25, + "high": 33760.52, + "low": 33705.12, + "close": 33750.11 }, { - "timestamp": 1625958900000, - "open": 33770.25, - "high": 33770.52, - "low": 33710.12, - "close": 33710.11 + "timestamp": 1625958900000, + "open": 33770.25, + "high": 33770.52, + "low": 33710.12, + "close": 33710.11 }, { - "timestamp": 1625958000000, - "open": 33740.25, - "high": 33780.52, - "low": 33710.12, - "close": 33780.11 + "timestamp": 1625958000000, + "open": 33740.25, + "high": 33780.52, + "low": 33710.12, + "close": 33780.11 }, { - "timestamp": 1625957100000, - "open": 33670.25, - "high": 33785.52, - "low": 33660.12, - "close": 33745.11 + "timestamp": 1625957100000, + "open": 33670.25, + "high": 33785.52, + "low": 33660.12, + "close": 33745.11 }, { - "timestamp": 1625956200000, - "open": 33645.25, - "high": 33670.52, - "low": 33645.12, - "close": 33660.11 + "timestamp": 1625956200000, + "open": 33645.25, + "high": 33670.52, + "low": 33645.12, + "close": 33660.11 }, { - "timestamp": 1625955300000, - "open": 33640.25, - "high": 33665.52, - "low": 33600.12, - "close": 33630.11 + "timestamp": 1625955300000, + "open": 33640.25, + "high": 33665.52, + "low": 33600.12, + "close": 33630.11 }, { - "timestamp": 1625954400000, - "open": 33570.25, - "high": 33645.52, - "low": 33545.12, - "close": 33645.11 + "timestamp": 1625954400000, + "open": 33570.25, + "high": 33645.52, + "low": 33545.12, + "close": 33645.11 }, { - "timestamp": 1625953500000, - "open": 33515.25, - "high": 33550.52, - "low": 33515.12, - "close": 33540.11 + "timestamp": 1625953500000, + "open": 33515.25, + "high": 33550.52, + "low": 33515.12, + "close": 33540.11 }, { - "timestamp": 1625952600000, - "open": 33485.25, - "high": 33520.52, - "low": 33460.12, - "close": 33515.11 + "timestamp": 1625952600000, + "open": 33485.25, + "high": 33520.52, + "low": 33460.12, + "close": 33515.11 }, { - "timestamp": 1625951700000, - "open": 33440.25, - "high": 33545.52, - "low": 33440.12, - "close": 33510.11 + "timestamp": 1625951700000, + "open": 33440.25, + "high": 33545.52, + "low": 33440.12, + "close": 33510.11 }, { - "timestamp": 1625950800000, - "open": 33480.25, - "high": 33480.52, - "low": 33430.12, - "close": 33445.11 + "timestamp": 1625950800000, + "open": 33480.25, + "high": 33480.52, + "low": 33430.12, + "close": 33445.11 }, { - "timestamp": 1625949900000, - "open": 33435.25, - "high": 33465.52, - "low": 33435.12, - "close": 33455.11 + "timestamp": 1625949900000, + "open": 33435.25, + "high": 33465.52, + "low": 33435.12, + "close": 33455.11 }, { - "timestamp": 1625949000000, - "open": 33445.25, - "high": 33520.52, - "low": 33415.12, - "close": 33440.11 + "timestamp": 1625949000000, + "open": 33445.25, + "high": 33520.52, + "low": 33415.12, + "close": 33440.11 }, { - "timestamp": 1625948100000, - "open": 33215.25, - "high": 33430.52, - "low": 33215.12, - "close": 33420.11 + "timestamp": 1625948100000, + "open": 33215.25, + "high": 33430.52, + "low": 33215.12, + "close": 33420.11 }, { - "timestamp": 1625947200000, - "open": 33510.25, - "high": 33515.52, - "low": 33250.12, - "close": 33250.11 + "timestamp": 1625947200000, + "open": 33510.25, + "high": 33515.52, + "low": 33250.12, + "close": 33250.11 }, { - "timestamp": 1625946300000, - "open": 33545.25, - "high": 33560.52, - "low": 33510.12, - "close": 33520.11 + "timestamp": 1625946300000, + "open": 33545.25, + "high": 33560.52, + "low": 33510.12, + "close": 33520.11 }, { - "timestamp": 1625945400000, - "open": 33575.25, - "high": 33600.52, - "low": 33475.12, - "close": 33520.11 + "timestamp": 1625945400000, + "open": 33575.25, + "high": 33600.52, + "low": 33475.12, + "close": 33520.11 } -] \ No newline at end of file +] diff --git a/src/charts/candle/Candle.tsx b/src/charts/candle/Candle.tsx index f06c903..a63f8e1 100644 --- a/src/charts/candle/Candle.tsx +++ b/src/charts/candle/Candle.tsx @@ -1,19 +1,13 @@ import React from 'react'; +import { ColorValue } from 'react-native'; import Animated, { withTiming, useAnimatedProps, } from 'react-native-reanimated'; -import { - Line, - LineProps, - NumberProp, - Rect, - RectProps, -} from 'react-native-svg'; +import { Line, LineProps, NumberProp, Rect, RectProps } from 'react-native-svg'; import type { TCandle, TDomain } from './types'; import { getY, getHeight } from './utils'; -import { ColorValue } from 'react-native'; const AnimatedRect = Animated.createAnimatedComponent(Rect); const AnimatedLine = Animated.createAnimatedComponent(Line); From 5f85fe4a63f5e74188705a10b5491f865ae603d4 Mon Sep 17 00:00:00 2001 From: Simon Schippl Date: Tue, 21 May 2024 11:14:49 +1000 Subject: [PATCH 3/4] Fix type errors --- example/src/LineChart.tsx | 2 +- src/charts/candle/DatetimeText.tsx | 1 - src/charts/candle/Line.tsx | 1 - src/charts/candle/PriceText.tsx | 1 - src/charts/candle/useCandleData.ts | 2 +- src/charts/line/Chart.tsx | 9 ++++----- src/charts/line/Context.tsx | 11 +++++++---- src/charts/line/Cursor.tsx | 6 +++--- src/charts/line/Data.tsx | 2 +- src/charts/line/DatetimeText.tsx | 1 - src/charts/line/Group.tsx | 1 - src/charts/line/HoverTrap/index.tsx | 2 -- src/charts/line/HoverTrap/index.web.tsx | 4 ++-- src/charts/line/PriceText.tsx | 1 - src/charts/line/useDatetime.ts | 9 +++++++-- src/charts/line/usePrice.ts | 10 ++++++++-- src/charts/line/utils/getArea.ts | 2 +- src/charts/line/utils/getPath.ts | 2 +- src/charts/line/utils/getXPositionForCurve.ts | 2 +- src/utils/formatPrice.ts | 2 +- 20 files changed, 38 insertions(+), 33 deletions(-) diff --git a/example/src/LineChart.tsx b/example/src/LineChart.tsx index 9735845..6c6df12 100644 --- a/example/src/LineChart.tsx +++ b/example/src/LineChart.tsx @@ -139,7 +139,7 @@ export default function App() { > { if (currentX.value === -1) { return { timestamp: -1, low: -1, open: -1, high: -1, close: -1 }; } - return data[Math.floor(currentX.value / step)]; + return data[Math.floor(currentX.value / step)] as TCandle; }, [currentX, data, step]); return candle; diff --git a/src/charts/line/Chart.tsx b/src/charts/line/Chart.tsx index afc676b..b137a84 100644 --- a/src/charts/line/Chart.tsx +++ b/src/charts/line/Chart.tsx @@ -55,11 +55,11 @@ export function LineChart({ const pathWidth = React.useMemo(() => { let allowedWidth = width; - if (xLength > data.length) { + if (data && xLength > data.length) { allowedWidth = (width * data.length) / xLength; } return allowedWidth; - }, [data.length, width, xLength]); + }, [data, width, xLength]); const path = React.useMemo(() => { if (data && data.length > 0) { @@ -91,11 +91,10 @@ export function LineChart({ return ''; }, [data, pathWidth, height, yGutter, shape, yDomain, xDomain]); - const dataLength = data.length; const parsedPath = React.useMemo(() => parse(path), [path]); const pointWidth = React.useMemo( - () => width / (dataLength - 1), - [dataLength, width] + () => width / (data ? data.length - 1 : 1), + [data, width] ); const contextValue = React.useMemo( diff --git a/src/charts/line/Context.tsx b/src/charts/line/Context.tsx index d082219..4e8ad22 100644 --- a/src/charts/line/Context.tsx +++ b/src/charts/line/Context.tsx @@ -4,7 +4,7 @@ import { useAnimatedReaction, useSharedValue, } from 'react-native-reanimated'; -import type { TLineChartDataProp } from './types'; +import type { TLineChartData, TLineChartDataProp } from './types'; import { LineChartDataProvider } from './Data'; import type { TLineChartContext, YRangeProp } from './types'; @@ -47,12 +47,16 @@ export function LineChartProvider({ const isActive = useSharedValue(false); const domain = React.useMemo( - () => getDomain(Array.isArray(data) ? data : Object.values(data)[0]), + () => getDomain( + Array.isArray(data) ? data : Object.values(data)[0] as TLineChartData + ), [data] ); const contextValue = React.useMemo(() => { const values = lineChartDataPropToArray(data).map(({ value }) => value); + const domainRows = + Array.isArray(data) ? data : Object.values(data)[0] as TLineChartData; return { currentX, @@ -64,8 +68,7 @@ export function LineChartProvider({ max: yRange?.max ?? Math.max(...values), }, xDomain, - xLength: - xLength ?? (Array.isArray(data) ? data : Object.values(data)[0]).length, + xLength: xLength ?? domainRows.length, }; }, [ currentIndex, diff --git a/src/charts/line/Cursor.tsx b/src/charts/line/Cursor.tsx index 86c2d48..47dd8f6 100644 --- a/src/charts/line/Cursor.tsx +++ b/src/charts/line/Cursor.tsx @@ -39,7 +39,7 @@ export function LineChartCursor({ ); const { currentX, currentIndex, isActive, data, xDomain } = useLineChart(); const xValues = React.useMemo( - () => data.map(({ timestamp }, i) => (xDomain ? timestamp : i)), + () => (data ?? []).map(({ timestamp }, i) => (xDomain ? timestamp : i)), [data, xDomain] ); @@ -70,7 +70,7 @@ export function LineChartCursor({ const newXPosition = ( closestIndex > 0 - ? parsedPath.curves[closestPathCurve].to + ? parsedPath.curves[closestPathCurve]!.to : parsedPath.move ).x; // Update values @@ -92,7 +92,7 @@ export function LineChartCursor({ const minIndex = 0; const boundedIndex = Math.max( minIndex, - Math.round(xPosition / width / (1 / (data.length - 1))) + Math.round(xPosition / width / (1 / (data ? data.length - 1 : 1))) ); if (snapToPoint) { diff --git a/src/charts/line/Data.tsx b/src/charts/line/Data.tsx index ae779a9..8d90f61 100644 --- a/src/charts/line/Data.tsx +++ b/src/charts/line/Data.tsx @@ -1,5 +1,5 @@ import type { TLineChartData } from './types'; -import React, { createContext, useContext, useMemo } from 'react'; +import { createContext, useContext, useMemo } from 'react'; import type { ReactNode } from 'react'; import type { TLineChartDataProp } from './types'; diff --git a/src/charts/line/DatetimeText.tsx b/src/charts/line/DatetimeText.tsx index 3198c9e..3be47cf 100644 --- a/src/charts/line/DatetimeText.tsx +++ b/src/charts/line/DatetimeText.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import type { TextProps as RNTextProps } from 'react-native'; import type Animated from 'react-native-reanimated'; diff --git a/src/charts/line/Group.tsx b/src/charts/line/Group.tsx index 7c44d93..1953781 100644 --- a/src/charts/line/Group.tsx +++ b/src/charts/line/Group.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { ReactNode, Children, cloneElement } from 'react'; import { ViewProps, View } from 'react-native'; import flattenChildren from 'react-keyed-flatten-children'; diff --git a/src/charts/line/HoverTrap/index.tsx b/src/charts/line/HoverTrap/index.tsx index 3dba1a5..a3d1ecb 100644 --- a/src/charts/line/HoverTrap/index.tsx +++ b/src/charts/line/HoverTrap/index.tsx @@ -1,3 +1 @@ -import React from 'react'; - export const LineChartHoverTrap = () => <>; diff --git a/src/charts/line/HoverTrap/index.web.tsx b/src/charts/line/HoverTrap/index.web.tsx index 6d06c70..256759c 100644 --- a/src/charts/line/HoverTrap/index.web.tsx +++ b/src/charts/line/HoverTrap/index.web.tsx @@ -65,7 +65,7 @@ export const LineChartHoverTrap = () => { const minIndex = 0; const boundedIndex = Math.max( minIndex, - Math.round(boundedX / width / (1 / (data.length - 1))) + Math.round(boundedX / width / (1 / (data ? data.length - 1 : 1))) ); currentIndex.value = boundedIndex; @@ -75,7 +75,7 @@ export const LineChartHoverTrap = () => { currentIndex.value = -1; } }, - [currentIndex, currentX, data.length, isActive, parsedPath, width] + [currentIndex, currentX, data, isActive, parsedPath, width] ); const onMouseLeave = React.useCallback(() => { diff --git a/src/charts/line/PriceText.tsx b/src/charts/line/PriceText.tsx index 47fa603..4fc2aa2 100644 --- a/src/charts/line/PriceText.tsx +++ b/src/charts/line/PriceText.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import type { TextProps as RNTextProps } from 'react-native'; import type Animated from 'react-native-reanimated'; diff --git a/src/charts/line/useDatetime.ts b/src/charts/line/useDatetime.ts index 7ce3c56..4059955 100644 --- a/src/charts/line/useDatetime.ts +++ b/src/charts/line/useDatetime.ts @@ -16,9 +16,14 @@ export function useLineChartDatetime({ const { currentIndex, data } = useLineChart(); const timestamp = useDerivedValue(() => { - if (typeof currentIndex.value === 'undefined' || currentIndex.value === -1) + if ( + !data || + typeof currentIndex.value === 'undefined' || + currentIndex.value === -1 + ) { return ''; - return data[currentIndex.value].timestamp; + } + return data[currentIndex.value]?.timestamp ?? ''; }, [currentIndex, data]); const timestampString = useDerivedValue(() => { diff --git a/src/charts/line/usePrice.ts b/src/charts/line/usePrice.ts index 280d31c..ce551ba 100644 --- a/src/charts/line/usePrice.ts +++ b/src/charts/line/usePrice.ts @@ -12,14 +12,20 @@ export function useLineChartPrice({ const { currentIndex, data } = useLineChart(); const float = useDerivedValue(() => { + if (!data) { + return ''; + } + if ( (typeof currentIndex.value === 'undefined' || currentIndex.value === -1) && index == null - ) + ) { return ''; + } + let price = 0; - price = data[Math.min(index ?? currentIndex.value, data.length - 1)].value; + price = data[Math.min(index ?? currentIndex.value, data.length - 1)]!.value; return price.toFixed(precision).toString(); }, [currentIndex, data, precision]); const formatted = useDerivedValue(() => { diff --git a/src/charts/line/utils/getArea.ts b/src/charts/line/utils/getArea.ts index 3e28f38..79e557d 100644 --- a/src/charts/line/utils/getArea.ts +++ b/src/charts/line/utils/getArea.ts @@ -33,7 +33,7 @@ export function getArea({ .range([height - gutter, gutter]); const area = shape .area() - .x((_: unknown, i: number) => scaleX(xDomain ? timestamps[i] : i)) + .x((_: unknown, i: number) => scaleX(xDomain ? timestamps[i] ?? i : i)) .y0((d: { value: unknown }) => scaleY(d.value as number)) .y1(() => height) .curve(_shape)(data); diff --git a/src/charts/line/utils/getPath.ts b/src/charts/line/utils/getPath.ts index f159614..c72b4ca 100644 --- a/src/charts/line/utils/getPath.ts +++ b/src/charts/line/utils/getPath.ts @@ -43,7 +43,7 @@ export function getPath({ .find((item) => item.timestamp === d.timestamp) : true ) - .x((_: unknown, i: number) => scaleX(xDomain ? timestamps[i] : i)) + .x((_: unknown, i: number) => scaleX(xDomain ? timestamps[i] ?? i : i)) .y((d: { value: number }) => scaleY(d.value)) .curve(_shape)(data); return path; diff --git a/src/charts/line/utils/getXPositionForCurve.ts b/src/charts/line/utils/getXPositionForCurve.ts index 6929de0..09bc600 100644 --- a/src/charts/line/utils/getXPositionForCurve.ts +++ b/src/charts/line/utils/getXPositionForCurve.ts @@ -5,5 +5,5 @@ export function getXPositionForCurve(path: Path, index: number) { if (index === 0) { return path.move.x; } - return path.curves[index - 1].to.x; + return path.curves[index - 1]!.to.x; } diff --git a/src/utils/formatPrice.ts b/src/utils/formatPrice.ts index 06b88e4..33d43b0 100644 --- a/src/utils/formatPrice.ts +++ b/src/utils/formatPrice.ts @@ -31,7 +31,7 @@ export function formatPrice({ let res = `${Number(value).toFixed(decimals)}`; const vals = res.split('.'); if (vals.length > 0) { - res = vals[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); + res = vals[0]!.replace(/\B(?=(\d{3})+(?!\d))/g, ','); if (vals.length === 2) { return res + '.' + vals[1]; } From 5e2a115366f8ffd905e167d51169564ee5e9218a Mon Sep 17 00:00:00 2001 From: Simon Schippl Date: Wed, 22 May 2024 11:44:14 +1000 Subject: [PATCH 4/4] Check index in range --- src/charts/line/utils/getXPositionForCurve.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/charts/line/utils/getXPositionForCurve.ts b/src/charts/line/utils/getXPositionForCurve.ts index 09bc600..8931ec6 100644 --- a/src/charts/line/utils/getXPositionForCurve.ts +++ b/src/charts/line/utils/getXPositionForCurve.ts @@ -5,5 +5,15 @@ export function getXPositionForCurve(path: Path, index: number) { if (index === 0) { return path.move.x; } - return path.curves[index - 1]!.to.x; + + const point = path.curves[index - 1]; + + if (point === undefined) { + throw new Error( + `Index out of bounds: ${index}. ` + + `Expected an integer in the range [0, ${path.curves.length}]` + ); + } + + return point.to.x; }