All files / src/plugins/highcharts/renderer/components HighchartsReact.tsx

0% Statements 0/38
0% Branches 0/22
0% Functions 0/9
0% Lines 0/38

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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                                                                                                                                                                                                                                                     
/* eslint no-console: ["error", { allow: ["warn", "error"]}] */
 
import React from 'react';
 
import afterFrame from 'afterframe';
import Highcharts from 'highcharts';
 
import type {ChartKitProps} from '../../../../types';
import {measurePerformance} from '../../../../utils';
 
import {useElementSize} from './useElementSize';
 
interface HighchartsReactRefObject {
    chart: Highcharts.Chart | null | undefined;
    container: React.RefObject<HTMLDivElement | undefined>;
}
 
interface HighchartsReactProps {
    [key: string]: any;
    constructorType?: keyof typeof Highcharts;
    containerProps?: {[key: string]: any};
    highcharts?: typeof Highcharts;
    options: Highcharts.Options;
    callback?: Highcharts.ChartCallbackFunction;
    onRender?: ChartKitProps<any>['onRender'];
}
 
const useIsomorphicLayoutEffect =
    typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect;
 
export const HighchartsReact = React.memo(
    React.forwardRef<HighchartsReactRefObject, HighchartsReactProps>(
        function HighchartsReact(props, ref) {
            const {onRender} = props;
            const containerRef = React.useRef<HTMLDivElement | null>(null);
            const chartRef = React.useRef<Highcharts.Chart | null>();
            const {width, height} = useElementSize(containerRef);
            const performanceMeasure = React.useRef<ReturnType<typeof measurePerformance> | null>(
                measurePerformance(),
            );
 
            useIsomorphicLayoutEffect(() => {
                function createChart() {
                    const {highcharts: HighchartsComponent} = props;
                    const constructorType = props.constructorType || 'chart';
 
                    if (!HighchartsComponent) {
                        console.warn('The "highcharts" property was not passed.');
                    } else if (!HighchartsComponent[constructorType]) {
                        console.warn(
                            'The "constructorType" property is incorrect or some ' +
                                'required module is not imported.',
                        );
                    } else if (props.options) {
                        // @ts-ignore
                        chartRef.current = HighchartsComponent[constructorType](
                            containerRef.current,
                            props.options,
                            props.callback,
                        );
                    } else {
                        console.warn('The "options" property was not passed.');
                    }
                }
 
                if (!chartRef.current) {
                    createChart();
                }
            }, [
                props.options,
                props.allowChartUpdate,
                props.containerProps,
                props.highcharts,
                props.constructorType,
            ]);
 
            useIsomorphicLayoutEffect(() => {
                return () => {
                    if (chartRef.current) {
                        chartRef.current.destroy();
                        chartRef.current = null;
                    }
                };
            }, []);
 
            React.useImperativeHandle(
                ref,
                () => ({
                    get chart() {
                        return chartRef.current;
                    },
                    container: containerRef,
                }),
                [],
            );
 
            React.useLayoutEffect(() => {
                if (width && height) {
                    if (!performanceMeasure.current) {
                        performanceMeasure.current = measurePerformance();
                    }
 
                    afterFrame(() => {
                        const renderTime = performanceMeasure.current?.end();
                        if (typeof renderTime === 'number') {
                            onRender?.({renderTime});
                        }
                        performanceMeasure.current = null;
                    });
                }
            }, [width, height, onRender]);
 
            return <div {...props.containerProps} ref={containerRef} />;
        },
    ),
) as React.ForwardRefExoticComponent<
    React.PropsWithoutRef<HighchartsReactProps> & React.RefAttributes<HighchartsReactRefObject>
>;
 
HighchartsReact.displayName = 'HighchartsReact';
 
export default HighchartsReact;