From c95178374f242b770c00c7e0f3f1053a51968e58 Mon Sep 17 00:00:00 2001 From: Jim Risen Date: Mon, 10 Jun 2024 22:22:08 +0300 Subject: [PATCH] feat: allow returning a cleanup callback from onInit --- demos/features/chart-group/src/App.tsx | 46 +++++++++++++++++++------- src/SciChart.tsx | 11 ++++-- src/types.ts | 5 ++- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/demos/features/chart-group/src/App.tsx b/demos/features/chart-group/src/App.tsx index 9d50c66..c72d684 100644 --- a/demos/features/chart-group/src/App.tsx +++ b/demos/features/chart-group/src/App.tsx @@ -2,6 +2,7 @@ import { EAutoRange, EAxisType, EThemeProviderType, + FastLineRenderableSeries, NumberRange, SciChartDefaults, SciChartSurface, @@ -15,7 +16,7 @@ import "./styles.css"; // SciChart core lib requires asynchronously loaded WASM module. // It could be loaded from CDN or by specified path. // check out SciChart.JS Docs for configuration info -SciChartSurface.useWasmFromCDN(); +SciChartSurface.loadWasmFromCDN(); SciChartDefaults.performanceWarnings = false; export function App() { @@ -29,12 +30,18 @@ export function App() { console.log("Group onDelete", initResults); }} > - + > style={{ width: 600, height: 300 }} fallback={
Data fetching & Chart Initialization in progress
} initChart={chartInitializationFunction} onInit={(initResult: TResolvedReturnType) => { console.log("Chart 1 onInit"); + + const token = setInterval(initResult.updateData, 500); + return () => { + console.log("Chart 1 destructor for onInit"); + clearInterval(token); + }; }} onDelete={(initResult: TResolvedReturnType) => { console.log("Chart 1 onDelete"); @@ -65,13 +72,13 @@ const chartInitializationFunction = async (rootElement: string | HTMLDivElement) xAxes: { type: EAxisType.NumericAxis, options: { - autoRange: EAutoRange.Once, + autoRange: EAutoRange.Always, growBy: new NumberRange(0.2, 0.2) } }, yAxes: { type: EAxisType.NumericAxis, - options: { autoRange: EAutoRange.Never } + options: { autoRange: EAutoRange.Always } }, surface: { theme: { type: EThemeProviderType.Dark }, @@ -85,27 +92,42 @@ const chartInitializationFunction = async (rootElement: string | HTMLDivElement) return sciChartSurface; }; + const generateData = (offset: number) => { + const xValues = Array.from(Array(20).keys()).map(x => x + offset); + const yValues = xValues.map(() => Math.abs(Math.random() * 10)); + return { xValues, yValues }; + }; + // a function that simulates an async data fetching - const getData = async () => { + const getData = async (offset: number = 0) => { await new Promise(resolve => { setTimeout(() => resolve({}), 1500); }); - return { xValues: [0, 1, 2, 3, 4], yValues: [3, 6, 1, 5, 2] }; + return generateData(offset); }; const [sciChartSurface, data] = await Promise.all([createChart(), getData()]); const wasmContext = sciChartSurface.webAssemblyContext2D; - + const dataSeries = new XyDataSeries(wasmContext, { + fifoCapacity: 100, + ...data + }); sciChartSurface.renderableSeries.add( - new XyScatterRenderableSeries(wasmContext, { - dataSeries: new XyDataSeries(wasmContext, { - ...data - }), + new FastLineRenderableSeries(wasmContext, { + dataSeries, strokeThickness: 4, stroke: "#216939" }) ); - return { sciChartSurface }; + + let lastX = data.xValues.length; + const updateData = () => { + const { xValues, yValues } = generateData(lastX); + dataSeries.appendRange(xValues, yValues); + lastX += xValues.length; + }; + + return { sciChartSurface, updateData }; }; diff --git a/src/SciChart.tsx b/src/SciChart.tsx index 8950e17..4a6aad1 100644 --- a/src/SciChart.tsx +++ b/src/SciChart.tsx @@ -3,7 +3,7 @@ import { useRef, useState, useEffect, useContext, JSX, CSSProperties } from "react"; import { ISciChartSurfaceBase, SciChart3DSurface, SciChartSurface, generateGuid } from "scichart"; import { SciChartSurfaceContext } from "./SciChartSurfaceContext"; -import { IInitResult, TChartComponentProps, TInitFunction } from "./types"; +import { IInitResult, TChartComponentProps, TCleanupCallback, TInitFunction } from "./types"; import { useIsMountedRef, createChartRoot, createChartFromConfig } from "./utils"; import { SciChartGroupContext } from "./SciChartGroupContext"; import { DefaultFallback } from "./DefaultFallback"; @@ -39,6 +39,8 @@ function SciChartComponent< const [chartRoot] = useState(createChartRoot); + const cleanupCallbackRef = useRef(); + useEffect(() => { // generate guid to distinguish between effect calls in StrictMode const chartId = generateGuid(); @@ -65,7 +67,7 @@ function SciChartComponent< setIsInitialized(true); if (onInit) { - onInit(result); + cleanupCallbackRef.current = onInit(result); } } else { cancelled = true; @@ -79,6 +81,11 @@ function SciChartComponent< initPromiseRef.current = initPromise; const performCleanup = (initResult: TInitResult) => { + if (!cancelled && cleanupCallbackRef.current) { + cleanupCallbackRef.current(); + cleanupCallbackRef.current = undefined; + } + if (!cancelled && onDelete) { onDelete(initResult); } diff --git a/src/types.ts b/src/types.ts index ca96077..519de6a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,9 @@ export type TInitFunction< /** @ignore */ export type TDivProps = DetailedHTMLProps, HTMLDivElement>; +/** @ignore */ +export type TCleanupCallback = () => void; + /** @ignore */ export interface IChartComponentPropsCore< TSurface extends ISciChartSurfaceBase, @@ -27,7 +30,7 @@ export interface IChartComponentPropsCore< /** a component that would be rendered while the chart is being initialized */ fallback?: ReactNode | undefined; /** a callback function used after the chart is initialized */ - onInit?: (initResult: TInitResult) => void; + onInit?: (initResult: TInitResult) => TCleanupCallback | void; /** a callback function used when the component with initialized chart is unmounted */ onDelete?: (initResult: TInitResult) => void; /** props passed to the inner container of the chart */