Duration.tsx 5.85 KB
Newer Older
Lijiao's avatar
Lijiao committed
1
2
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
3
4
5
import { EventMap } from '@static/interface';
import { Trial } from '@model/trial';
import { convertDuration } from '@static/function';
6
7
8
import 'echarts/lib/chart/bar';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
Lijiao's avatar
Lijiao committed
9
10

interface Runtrial {
11
    trialId: number[];
Lijiao's avatar
Lijiao committed
12
    trialTime: number[];
Lijiao's avatar
Lijiao committed
13
14
}

15
interface DurationProps {
16
    source: Trial[];
17
18
}

Lijiao's avatar
Lijiao committed
19
interface DurationState {
Lijiao's avatar
Lijiao committed
20
21
    startDuration: number; // for record data zoom
    endDuration: number;
22
    durationSource: {};
Lijiao's avatar
Lijiao committed
23
24
}

25
26
27
class Duration extends React.Component<DurationProps, DurationState> {
    constructor(props: DurationProps) {
        super(props);
Lijiao's avatar
Lijiao committed
28
        this.state = {
Lijiao's avatar
Lijiao committed
29
30
            startDuration: 0, // for record data zoom
            endDuration: 100,
31
            durationSource: this.initDuration(this.props.source)
32
33
34
        };
    }

35
    initDuration = (source: Trial[]): any => {
36
37
        const trialId: number[] = [];
        const trialTime: number[] = [];
38
        source.forEach(item => {
39
40
41
42
43
44
45
46
            trialId.push(item.sequenceId);
            trialTime.push(item.duration);
        });
        return {
            tooltip: {
                trigger: 'axis',
                axisPointer: {
                    type: 'shadow'
47
                },
48
                formatter: (data: any): React.ReactNode =>
49
                    '<div>' +
50
51
52
53
54
55
                    '<div>Trial No.: ' +
                    data[0].dataIndex +
                    '</div>' +
                    '<div>Duration: ' +
                    convertDuration(data[0].data) +
                    '</div>' +
56
                    '</div>'
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
            },
            grid: {
                bottom: '3%',
                containLabel: true,
                left: '1%',
                right: '5%'
            },
            dataZoom: [
                {
                    id: 'dataZoomY',
                    type: 'inside',
                    yAxisIndex: [0],
                    filterMode: 'empty',
                    start: 0,
                    end: 100
72
                }
73
74
75
            ],
            xAxis: {
                name: 'Time/s',
76
                type: 'value'
77
78
79
80
81
82
83
84
85
            },
            yAxis: {
                name: 'Trial No.',
                type: 'category',
                data: trialId,
                nameTextStyle: {
                    padding: [0, 0, 0, 30]
                }
            },
86
87
88
89
90
91
            series: [
                {
                    type: 'bar',
                    data: trialTime
                }
            ]
92
        };
93
    };
94

Lijiao's avatar
Lijiao committed
95
    getOption = (dataObj: Runtrial): any => {
Lijiao's avatar
Lijiao committed
96
        const { startDuration, endDuration } = this.state;
97
        return {
Lijiao's avatar
Lijiao committed
98
99
100
101
            tooltip: {
                trigger: 'axis',
                axisPointer: {
                    type: 'shadow'
102
                },
103
                enterable: true,
104
                formatter: (data: any): React.ReactNode =>
105
106
107
108
109
                    `<div class="tooldetailAccuracy">
                        <div>Trial No.: ${data[0].dataIndex}</div>
                        <div>Duration: ${convertDuration(data[0].data)}</div>
                    </div>
                    `
Lijiao's avatar
Lijiao committed
110
111
112
113
114
            },
            grid: {
                bottom: '3%',
                containLabel: true,
                left: '1%',
115
                right: '5%'
Lijiao's avatar
Lijiao committed
116
            },
Lijiao's avatar
Lijiao committed
117
118
119
120
121
122
123
124
            dataZoom: [
                {
                    id: 'dataZoomY',
                    type: 'inside',
                    yAxisIndex: [0],
                    filterMode: 'empty',
                    start: startDuration,
                    end: endDuration
125
                }
Lijiao's avatar
Lijiao committed
126
            ],
Lijiao's avatar
Lijiao committed
127
128
            xAxis: {
                name: 'Time',
129
                type: 'value'
Lijiao's avatar
Lijiao committed
130
131
132
133
            },
            yAxis: {
                name: 'Trial',
                type: 'category',
134
135
136
137
                data: dataObj.trialId,
                nameTextStyle: {
                    padding: [0, 0, 0, 30]
                }
Lijiao's avatar
Lijiao committed
138
            },
139
140
141
142
143
144
            series: [
                {
                    type: 'bar',
                    data: dataObj.trialTime
                }
            ]
Lijiao's avatar
Lijiao committed
145
        };
146
    };
Lijiao's avatar
Lijiao committed
147

148
    drawDurationGraph = (source: Trial[]): void => {
149
        // why this function run two times when props changed?
150
        const trialId: number[] = [];
Lijiao's avatar
Lijiao committed
151
        const trialTime: number[] = [];
152
        const trialRun: Runtrial[] = [];
153
154
155
        source.forEach(item => {
            trialId.push(item.sequenceId);
            trialTime.push(item.duration);
156
        });
157

158
159
160
161
        trialRun.push({
            trialId: trialId,
            trialTime: trialTime
        });
162
163
164
        this.setState({
            durationSource: this.getOption(trialRun[0])
        });
165
    };
166
167
168
169
170
171

    componentDidMount(): void {
        const { source } = this.props;
        this.drawDurationGraph(source);
    }

172
173
174
    componentDidUpdate(prevProps: DurationProps): void {
        // add this if to prevent endless loop
        if (this.props.source !== prevProps.source) {
175
            this.drawDurationGraph(this.props.source);
176
177
178
        }
    }

Lijiao's avatar
Lijiao committed
179
    render(): React.ReactNode {
180
        const { durationSource } = this.state;
181
        const onEvents = { dataZoom: this.durationDataZoom };
182

Lijiao's avatar
Lijiao committed
183
        return (
184
            <div className='graph'>
Lijiao's avatar
Lijiao committed
185
                <ReactEcharts
186
187
                    option={durationSource}
                    style={{ width: '94%', height: 412, margin: '0 auto', marginTop: 15 }}
188
                    theme='nni_theme'
189
                    notMerge={true} // update now
Lijiao's avatar
Lijiao committed
190
                    onEvents={onEvents}
Lijiao's avatar
Lijiao committed
191
192
193
194
                />
            </div>
        );
    }
Lijiao's avatar
Lijiao committed
195

Lijiao's avatar
Lijiao committed
196
    private durationDataZoom = (e: EventMap): void => {
Lijiao's avatar
Lijiao committed
197
198
        if (e.batch !== undefined) {
            this.setState(() => ({
199
200
                startDuration: e.batch[0].start !== null ? e.batch[0].start : 0,
                endDuration: e.batch[0].end !== null ? e.batch[0].end : 100
Lijiao's avatar
Lijiao committed
201
202
            }));
        }
203
    };
Lijiao's avatar
Lijiao committed
204
205
}

206
export default Duration;