LineChart.tsx 3.8 KB
Newer Older
1 2
import * as chart from '~/utils/chart';

P
Peter Pan 已提交
3
import React, {useEffect, useImperativeHandle} from 'react';
P
Peter Pan 已提交
4
import {WithStyled, primaryColor} from '~/utils/style';
5
import useECharts, {Options, Wrapper} from '~/hooks/useECharts';
6

7
import type {EChartOption} from 'echarts';
8
import GridLoader from 'react-spinners/GridLoader';
P
Peter Pan 已提交
9
import defaultsDeep from 'lodash/defaultsDeep';
10
import {formatTime} from '~/utils';
11
import {useTranslation} from 'react-i18next';
12 13

type LineChartProps = {
P
Peter Pan 已提交
14
    options?: EChartOption;
15 16 17
    title?: string;
    data?: Partial<NonNullable<EChartOption<EChartOption.SeriesLine>['series']>>;
    loading?: boolean;
P
Peter Pan 已提交
18
    zoom?: boolean;
19
    onInit?: Options['onInit'];
20 21
};

P
Peter Pan 已提交
22 23 24 25 26 27 28 29 30 31 32
export enum XAxisType {
    value = 'value',
    log = 'log',
    time = 'time'
}

export enum YAxisType {
    value = 'value',
    log = 'log'
}

33 34 35
export type LineChartRef = {
    restore(): void;
    saveAsImage(): void;
36 37
};

38
const LineChart = React.forwardRef<LineChartRef, LineChartProps & WithStyled>(
39
    ({options, data, title, loading, zoom, className, onInit}, ref) => {
40 41
        const {i18n} = useTranslation();

P
Peter Pan 已提交
42
        const {ref: echartRef, echart, wrapper, saveAsImage} = useECharts<HTMLDivElement>({
43
            loading: !!loading,
P
Peter Pan 已提交
44
            zoom,
45 46
            autoFit: true,
            onInit
47 48 49 50
        });

        useImperativeHandle(ref, () => ({
            restore: () => {
P
Peter Pan 已提交
51
                echart?.dispatchAction({
52 53 54 55
                    type: 'restore'
                });
            },
            saveAsImage: () => {
P
Peter Pan 已提交
56
                saveAsImage(title);
57 58 59 60
            }
        }));

        useEffect(() => {
61 62
            // eslint-disable-next-line @typescript-eslint/no-unused-vars
            const {color, colorAlt, series, ...defaults} = chart;
P
Peter Pan 已提交
63

64 65 66 67 68 69 70 71 72 73 74 75 76 77
            let chartOptions: EChartOption = defaultsDeep(
                {
                    title: {
                        text: title ?? ''
                    },
                    series: data?.map(item =>
                        defaultsDeep(
                            {
                                // show symbol if there is only one point
                                showSymbol: (item?.data?.length ?? 0) <= 1,
                                type: 'line'
                            },
                            item,
                            series
P
Peter Pan 已提交
78
                        )
79 80 81 82 83 84 85 86 87 88 89 90 91
                    )
                },
                options,
                defaults
            );
            if ((chartOptions?.xAxis as EChartOption.XAxis).type === 'time') {
                chartOptions = defaultsDeep(
                    {
                        xAxis: {
                            axisLabel: {
                                formatter: (value: number) => formatTime(value, i18n.language, 'LTS')
                            }
                        }
P
Peter Pan 已提交
92
                    },
93
                    chartOptions
P
Peter Pan 已提交
94
                );
95 96 97 98 99 100 101
            }
            if ((chartOptions?.yAxis as EChartOption.YAxis).type === 'time') {
                chartOptions = defaultsDeep(
                    {
                        yAxis: {
                            axisLabel: {
                                formatter: (value: number) => formatTime(value, i18n.language, 'LTS')
P
Peter Pan 已提交
102
                            }
103 104 105 106
                        }
                    },
                    chartOptions
                );
107
            }
108
            echart?.setOption(chartOptions, {notMerge: true});
P
Peter Pan 已提交
109
        }, [options, data, title, i18n.language, echart]);
110 111

        return (
P
Peter Pan 已提交
112
            <Wrapper ref={wrapper} className={className}>
113 114 115 116 117 118 119 120 121 122 123
                {!echart && (
                    <div className="loading">
                        <GridLoader color={primaryColor} size="10px" />
                    </div>
                )}
                <div className="echarts" ref={echartRef}></div>
            </Wrapper>
        );
    }
);

124
export default LineChart;