Intermediate.tsx 10.4 KB
Newer Older
1
import * as React from 'react';
2
import { Stack, PrimaryButton, Toggle, IStackTokens } from '@fluentui/react';
3
import { TooltipForIntermediate, EventMap, allTrialsIntermediateChart } from '@static/interface';
Lijiaoa's avatar
Lijiaoa committed
4
import { reformatRetiariiParameter } from '@static/function';
5
import ReactEcharts from 'echarts-for-react';
6
7
8
9
10
11
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';

const stackTokens: IStackTokens = {
    childrenGap: 20
};
12
13

interface IntermediateState {
14
    detailSource: allTrialsIntermediateChart[];
15
    interSource: object;
16
    filterSource: allTrialsIntermediateChart[];
17
18
    eachIntermediateNum: number; // trial's intermediate number count
    isLoadconfirmBtn: boolean;
19
    isFilter?: boolean | undefined;
20
    length: number;
Lijiao's avatar
Lijiao committed
21
22
    startMediaY: number;
    endMediaY: number;
23
24
25
}

interface IntermediateProps {
26
    source: allTrialsIntermediateChart[];
27
28
29
30
}

class Intermediate extends React.Component<IntermediateProps, IntermediateState> {
    static intervalMediate = 1;
31
32
33
    public pointInput!: HTMLInputElement | null;
    public minValInput!: HTMLInputElement | null;
    public maxValInput!: HTMLInputElement | null;
34
35
36
37

    constructor(props: IntermediateProps) {
        super(props);
        this.state = {
38
            detailSource: [],
39
40
41
42
            interSource: {},
            filterSource: [],
            eachIntermediateNum: 1,
            isLoadconfirmBtn: false,
43
44
            isFilter: false,
            length: 100000,
Lijiao's avatar
Lijiao committed
45
46
            startMediaY: 0,
            endMediaY: 100
47
48
49
        };
    }

50
    drawIntermediate = (source: allTrialsIntermediateChart[]): void => {
51
        if (source.length > 0) {
52
53
54
55
            this.setState({
                length: source.length,
                detailSource: source
            });
Lijiao's avatar
Lijiao committed
56
            const { startMediaY, endMediaY } = this.state;
Lijiao's avatar
Lijiao committed
57
            const xAxis: number[] = [];
58
59
60
            // find having most intermediate number
            source.sort((a, b) => {
                return b.data.length - a.data.length;
61
            });
62
            for (let i = 1; i <= source[0].data.length; i++) {
63
64
65
66
67
68
                xAxis.push(i);
            }
            const option = {
                tooltip: {
                    trigger: 'item',
                    enterable: true,
69
                    confine: true,
70
                    formatter: function (data: TooltipForIntermediate): React.ReactNode {
71
                        const trialId = data.seriesName;
72
73
74
75
76
77
78
                        // parameter and trialNo need to have the init value otherwise maybe cause page broke down
                        let parameter = {};
                        let trialNo = 0;
                        const renderTrial = source.find(key => key.name === trialId);
                        if (renderTrial !== undefined) {
                            parameter = renderTrial.parameter;
                            trialNo = renderTrial.sequenceId;
79
                        }
80
81
                        return `
                            <div class="tooldetailAccuracy">
82
                                <div>Trial No.: ${trialNo}</div> 
83
84
                                <div>Trial ID: ${trialId}</div>
                                <div>Intermediate: ${data.data}</div>
85
                                <div>Parameters: <pre>${JSON.stringify(
86
                                    reformatRetiariiParameter(parameter),
87
88
89
                                    null,
                                    4
                                )}</pre>
90
91
92
                                </div>
                            </div>
                        `;
93
94
95
96
97
98
99
100
101
                    }
                },
                grid: {
                    left: '5%',
                    top: 40,
                    containLabel: true
                },
                xAxis: {
                    type: 'category',
102
                    // name: '# Intermediate',
103
104
105
106
107
                    boundaryGap: false,
                    data: xAxis
                },
                yAxis: {
                    type: 'value',
108
                    name: 'Metric',
109
                    scale: true
110
                },
Lijiao's avatar
Lijiao committed
111
112
113
114
115
                dataZoom: [
                    {
                        id: 'dataZoomY',
                        type: 'inside',
                        yAxisIndex: [0],
116
                        filterMode: 'none',
Lijiao's avatar
Lijiao committed
117
118
119
120
                        start: startMediaY,
                        end: endMediaY
                    }
                ],
121
                series: source
122
            };
123
124
125
            this.setState({
                interSource: option
            });
126
        } else {
127
128
129
130
131
132
133
134
            const nullData = {
                grid: {
                    left: '5%',
                    top: 40,
                    containLabel: true
                },
                xAxis: {
                    type: 'category',
135
                    boundaryGap: false
136
137
138
                },
                yAxis: {
                    type: 'value',
139
                    name: 'Metric'
140
141
                }
            };
142
            this.setState({ interSource: nullData });
143
        }
144
    };
145
146

    // confirm btn function [filter data]
Lijiao's avatar
Lijiao committed
147
    filterLines = (): void => {
148
        const filterSource: allTrialsIntermediateChart[] = [];
149
150
151
152
153
154
155
156
157
158
159
160
161
        this.setState({ isLoadconfirmBtn: true }, () => {
            const { source } = this.props;
            // get input value
            const pointVal = this.pointInput !== null ? this.pointInput.value : '';
            const minVal = this.minValInput !== null ? this.minValInput.value : '';
            const maxVal = this.maxValInput !== null ? this.maxValInput.value : '';
            // user not input message
            if (pointVal === '' || minVal === '') {
                alert('Please input filter message');
            } else {
                const position = JSON.parse(pointVal);
                const min = JSON.parse(minVal);
                if (maxVal === '') {
162
163
164
                    // user not input max value
                    for (const item of source) {
                        const val = item.data[position - 1];
165
                        if (val >= min) {
166
                            filterSource.push(item);
167
                        }
168
                    }
169
                } else {
170
                    const max = JSON.parse(maxVal);
171
172
                    for (const item of source) {
                        const val = item.data[position - 1];
173
                        if (val >= min && val <= max) {
174
                            filterSource.push(item);
175
                        }
176
                    }
177
                }
178
179
180
                this.setState({ filterSource: filterSource });
                this.drawIntermediate(filterSource);
            }
181
            this.setState({ isLoadconfirmBtn: false });
182
        });
183
    };
184

185
    switchTurn = (ev: React.MouseEvent<HTMLElement>, checked?: boolean): void => {
186
        this.setState({ isFilter: checked });
187
188
189
        if (checked === false) {
            this.drawIntermediate(this.props.source);
        }
190
    };
191

Lijiao's avatar
Lijiao committed
192
    componentDidMount(): void {
193
194
195
196
        const { source } = this.props;
        this.drawIntermediate(source);
    }

197
198
199
    componentDidUpdate(prevProps: IntermediateProps, prevState: any): void {
        if (this.props.source !== prevProps.source || this.state.isFilter !== prevState.isFilter) {
            const { isFilter, filterSource } = this.state;
200
            const { source } = this.props;
201

202
203
204
205
            if (isFilter === true) {
                const pointVal = this.pointInput !== null ? this.pointInput.value : '';
                const minVal = this.minValInput !== null ? this.minValInput.value : '';
                if (pointVal === '' && minVal === '') {
206
                    this.drawIntermediate(source);
207
208
                } else {
                    this.drawIntermediate(filterSource);
209
                }
210
211
            } else {
                this.drawIntermediate(source);
212
213
214
215
            }
        }
    }

Lijiao's avatar
Lijiao committed
216
    render(): React.ReactNode {
217
        const { interSource, isLoadconfirmBtn, isFilter } = this.state;
218
        const IntermediateEvents = { dataZoom: this.intermediateDataZoom };
219

220
221
222
        return (
            <div>
                {/* style in para.scss */}
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
                <Stack horizontal horizontalAlign='end' tokens={stackTokens} className='meline intermediate'>
                    {isFilter ? (
                        <div>
                            <span className='filter-x'># Intermediate result</span>
                            <input
                                // placeholder="point"
                                ref={(input): any => (this.pointInput = input)}
                                className='strange'
                            />
                            <span>Metric range</span>
                            <input
                                // placeholder="range"
                                ref={(input): any => (this.minValInput = input)}
                            />
                            <span className='hyphen'>-</span>
                            <input
                                // placeholder="range"
                                ref={(input): any => (this.maxValInput = input)}
                            />
242
243
244
245
246
247
                            <PrimaryButton
                                className='intermeidateconfirm'
                                text='Confirm'
                                onClick={this.filterLines}
                                disabled={isLoadconfirmBtn}
                            />
248
249
                        </div>
                    ) : null}
Lijiao's avatar
Lijiao committed
250
                    {/* filter message */}
251
                    <Toggle label='Filter' inlineLabel onChange={this.switchTurn} />
252
                </Stack>
253
                <div className='intermediate-graph graph'>
254
255
                    <ReactEcharts
                        option={interSource}
256
                        style={{ width: '100%', height: 400, margin: '0 auto' }}
257
                        notMerge={true} // update now
Lijiao's avatar
Lijiao committed
258
                        onEvents={IntermediateEvents}
259
                    />
260
                    <div className='fontColor333 xAxis'># Intermediate result</div>
261
                </div>
262
263
264
            </div>
        );
    }
Lijiao's avatar
Lijiao committed
265

Lijiao's avatar
Lijiao committed
266
    private intermediateDataZoom = (e: EventMap): void => {
Lijiao's avatar
Lijiao committed
267
268
        if (e.batch !== undefined) {
            this.setState(() => ({
269
270
                startMediaY: e.batch[0].start !== null ? e.batch[0].start : 0,
                endMediaY: e.batch[0].end !== null ? e.batch[0].end : 100
Lijiao's avatar
Lijiao committed
271
272
            }));
        }
273
    };
274
275
}

v-liguo's avatar
v-liguo committed
276
export default Intermediate;