Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | import React from 'react';
import {Chart} from '@gravity-ui/charts';
import type {ChartProps, ChartRef} from '@gravity-ui/charts';
import afterFrame from 'afterframe';
import {settings} from '../../../libs';
import type {ChartKitProps, ChartKitWidgetRef} from '../../../types';
import {measurePerformance} from '../../../utils';
import {vaildateData} from './utils';
import {withSplitPane} from './withSplitPane/withSplitPane';
const ChartWithSplitPane = withSplitPane(Chart);
export const GravityChartsWidget = React.forwardRef<
ChartKitWidgetRef | undefined,
ChartKitProps<'gravity-charts'>
>(function GravityChartsWidget(props, forwardedRef) {
const {data, tooltip, onLoad, onRender, onChartLoad} = props;
vaildateData(props);
const lang = settings.get('lang');
const performanceMeasure = React.useRef<ReturnType<typeof measurePerformance> | null>(
measurePerformance(),
);
const chartRef = React.useRef<ChartRef>(null);
const [reflowFailure, setReflowFailure] = React.useState<{error: unknown}>();
const ChartComponent = tooltip?.splitted ? ChartWithSplitPane : Chart;
const handleReflowError = React.useCallback((error: unknown) => {
// shortcut: Match lifecycle messages until charts exposes a cancellation error type.
if (
error instanceof Error &&
[
'Chart host is unavailable',
'Chart host has zero size',
'Chart is unmounted',
'Chart unmounted before reflow completed',
].includes(error.message)
) {
return;
}
setReflowFailure({error});
}, []);
const handleChartReady: NonNullable<ChartProps['onReady']> = React.useCallback(() => {
if (!performanceMeasure.current) {
performanceMeasure.current = measurePerformance();
}
afterFrame(() => {
const renderTime = performanceMeasure.current?.end();
onRender?.({
renderTime,
});
onLoad?.({
widgetRendering: renderTime,
});
performanceMeasure.current = null;
});
}, [onRender, onLoad]);
React.useImperativeHandle(
forwardedRef,
() => ({
reflow(details) {
const options =
details &&
typeof details === 'object' &&
'immediate' in details &&
typeof details.immediate === 'boolean'
? {immediate: details.immediate}
: undefined;
const completion = chartRef.current?.reflow(options);
completion?.catch(handleReflowError);
return completion;
},
}),
[handleReflowError],
);
React.useLayoutEffect(() => {
if (onChartLoad) {
onChartLoad({});
}
}, [onChartLoad]);
if (reflowFailure) {
throw reflowFailure.error;
}
return (
<ChartComponent
ref={chartRef}
data={data}
lang={lang}
onReady={handleChartReady}
onReflowError={handleReflowError}
/>
);
});
|