Skip to content

Commit 3e7d03d

Browse files
authored
Merge pull request #766 from c9s/feature/time-range-picker
backtest-report: add time range slider
2 parents 0ad63b5 + 94ad8a5 commit 3e7d03d

File tree

13 files changed

+777
-41
lines changed

13 files changed

+777
-41
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import PropTypes from 'prop-types'
2+
import React from 'react'
3+
4+
const Handle = ({
5+
error,
6+
domain: [min, max],
7+
handle: { id, value, percent = 0 },
8+
disabled,
9+
getHandleProps,
10+
}) => {
11+
const leftPosition = `${percent}%`
12+
13+
return (
14+
<>
15+
<div className='react_time_range__handle_wrapper' style={{ left: leftPosition }} {...getHandleProps(id)} />
16+
<div
17+
role='slider'
18+
aria-valuemin={min}
19+
aria-valuemax={max}
20+
aria-valuenow={value}
21+
className={`react_time_range__handle_container${disabled ? '__disabled' : ''}`}
22+
style={{ left: leftPosition }}
23+
>
24+
<div className={`react_time_range__handle_marker${error ? '__error' : ''}`} />
25+
</div>
26+
</>
27+
)
28+
}
29+
30+
Handle.propTypes = {
31+
domain: PropTypes.array.isRequired,
32+
handle: PropTypes.shape({
33+
id: PropTypes.string.isRequired,
34+
value: PropTypes.number.isRequired,
35+
percent: PropTypes.number.isRequired
36+
}).isRequired,
37+
getHandleProps: PropTypes.func.isRequired,
38+
disabled: PropTypes.bool,
39+
style: PropTypes.object,
40+
}
41+
42+
Handle.defaultProps = { disabled: false }
43+
44+
export default Handle
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import PropTypes from 'prop-types'
2+
import React from 'react'
3+
4+
const KeyboardHandle = ({ domain: [min, max], handle: { id, value, percent = 0 }, disabled, getHandleProps }) => (
5+
<button
6+
role='slider'
7+
aria-valuemin={min}
8+
aria-valuemax={max}
9+
aria-valuenow={value}
10+
className='react_time_range__keyboard_handle'
11+
style={{
12+
left: `${percent}%`,
13+
backgroundColor: disabled ? '#666' : '#ffc400'
14+
}}
15+
{...getHandleProps(id)}
16+
/>
17+
)
18+
19+
KeyboardHandle.propTypes = {
20+
domain: PropTypes.array.isRequired,
21+
handle: PropTypes.shape({
22+
id: PropTypes.string.isRequired,
23+
value: PropTypes.number.isRequired,
24+
percent: PropTypes.number.isRequired
25+
}).isRequired,
26+
getHandleProps: PropTypes.func.isRequired,
27+
disabled: PropTypes.bool
28+
}
29+
30+
KeyboardHandle.defaultProps = { disabled: false }
31+
32+
export default KeyboardHandle
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
4+
export const SliderRail = ({ getRailProps }) => (
5+
<>
6+
<div className='react_time_range__rail__outer' {...getRailProps()} />
7+
<div className='react_time_range__rail__inner' />
8+
</>
9+
)
10+
11+
SliderRail.propTypes = { getRailProps: PropTypes.func.isRequired }
12+
13+
export default SliderRail
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { getMinutes } from 'date-fns'
2+
import PropTypes from 'prop-types'
3+
import React from 'react'
4+
5+
const Tick = ({ tick, count, format }) => {
6+
const isFullHour = !getMinutes(tick.value)
7+
8+
const tickLabelStyle = {
9+
marginLeft: `${-(100 / count) / 2}%`,
10+
width: `${100 / count}%`,
11+
left: `${tick.percent}%`,
12+
}
13+
14+
return (
15+
<>
16+
<div
17+
className={`react_time_range__tick_marker${isFullHour ? '__large' : ''}`}
18+
style={{ left: `${tick.percent}%` }}
19+
/>
20+
{isFullHour && (
21+
<div className='react_time_range__tick_label' style={tickLabelStyle}>
22+
{format(tick.value)}
23+
</div>
24+
)}
25+
</>
26+
)
27+
}
28+
29+
Tick.propTypes = {
30+
tick: PropTypes.shape({
31+
id: PropTypes.string.isRequired,
32+
value: PropTypes.number.isRequired,
33+
percent: PropTypes.number.isRequired
34+
}).isRequired,
35+
count: PropTypes.number.isRequired,
36+
format: PropTypes.func.isRequired
37+
}
38+
39+
Tick.defaultProps = { format: d => d }
40+
41+
export default Tick
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import PropTypes from 'prop-types'
2+
import React from 'react'
3+
4+
const getTrackConfig = ({ error, source, target, disabled }) => {
5+
const basicStyle = {
6+
left: `${source.percent}%`,
7+
width: `calc(${target.percent - source.percent}% - 1px)`,
8+
}
9+
10+
if (disabled) return basicStyle
11+
12+
const coloredTrackStyle = error
13+
? {
14+
backgroundColor: 'rgba(214,0,11,0.5)',
15+
borderLeft: '1px solid rgba(214,0,11,0.5)',
16+
borderRight: '1px solid rgba(214,0,11,0.5)',
17+
}
18+
: {
19+
backgroundColor: 'rgba(98, 203, 102, 0.5)',
20+
borderLeft: '1px solid #62CB66',
21+
borderRight: '1px solid #62CB66',
22+
}
23+
24+
return { ...basicStyle, ...coloredTrackStyle }
25+
}
26+
27+
const Track = ({ error, source, target, getTrackProps, disabled }) => (
28+
<div
29+
className={`react_time_range__track${disabled ? '__disabled' : ''}`}
30+
style={getTrackConfig({ error, source, target, disabled })}
31+
{...getTrackProps()}
32+
/>
33+
)
34+
35+
Track.propTypes = {
36+
source: PropTypes.shape({
37+
id: PropTypes.string.isRequired,
38+
value: PropTypes.number.isRequired,
39+
percent: PropTypes.number.isRequired
40+
}).isRequired,
41+
target: PropTypes.shape({
42+
id: PropTypes.string.isRequired,
43+
value: PropTypes.number.isRequired,
44+
percent: PropTypes.number.isRequired
45+
}).isRequired,
46+
getTrackProps: PropTypes.func.isRequired,
47+
disabled: PropTypes.bool
48+
}
49+
50+
Track.defaultProps = { disabled: false }
51+
52+
export default Track

0 commit comments

Comments
 (0)