blob: d2e0e41303684aa0af7690fe7e742f1bf9d5ff2c [file] [log] [blame]
import React from 'react';
import PropTypes from 'prop-types';
import { Row, Col } from 'react-bootstrap';
import Mousetrap from 'mousetrap';
import 'bootstrap-slider/dist/css/bootstrap-slider.min.css';
import ReactBootstrapSlider from 'react-bootstrap-slider';
import './PlaySlider.css';
import { t } from '../javascripts/locales';
const propTypes = {
start: PropTypes.number.isRequired,
step: PropTypes.number.isRequired,
end: PropTypes.number.isRequired,
values: PropTypes.array.isRequired,
onChange: PropTypes.func,
loopDuration: PropTypes.number,
maxFrames: PropTypes.number,
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
reversed: PropTypes.bool,
disabled: PropTypes.bool,
};
const defaultProps = {
onChange: () => {},
loopDuration: 15000,
maxFrames: 100,
orientation: 'horizontal',
reversed: false,
disabled: false,
};
export default class PlaySlider extends React.PureComponent {
constructor(props) {
super(props);
this.state = { intervalId: null };
const range = props.end - props.start;
const frames = Math.min(props.maxFrames, range / props.step);
const width = range / frames;
this.intervalMilliseconds = props.loopDuration / frames;
this.increment = width < props.step ? props.step : width - (width % props.step);
this.onChange = this.onChange.bind(this);
this.play = this.play.bind(this);
this.pause = this.pause.bind(this);
this.step = this.step.bind(this);
this.getPlayClass = this.getPlayClass.bind(this);
this.formatter = this.formatter.bind(this);
}
componentDidMount() {
Mousetrap.bind(['space'], this.play);
}
componentWillUnmount() {
Mousetrap.unbind(['space']);
}
onChange(event) {
this.props.onChange(event.target.value);
if (this.state.intervalId != null) {
this.pause();
}
}
getPlayClass() {
if (this.state.intervalId == null) {
return 'fa fa-play fa-lg slider-button';
}
return 'fa fa-pause fa-lg slider-button';
}
play() {
if (this.props.disabled) {
return;
}
if (this.state.intervalId != null) {
this.pause();
} else {
const id = setInterval(this.step, this.intervalMilliseconds);
this.setState({ intervalId: id });
}
}
pause() {
clearInterval(this.state.intervalId);
this.setState({ intervalId: null });
}
step() {
if (this.props.disabled) {
return;
}
let values = this.props.values.map(value => value + this.increment);
if (values[1] > this.props.end) {
const cr = values[0] - this.props.start;
values = values.map(value => value - cr);
}
this.props.onChange(values);
}
formatter(values) {
if (this.props.disabled) {
return t('Data has no time steps');
}
let parts = values;
if (!Array.isArray(values)) {
parts = [values];
} else if (values[0] === values[1]) {
parts = [values[0]];
}
return parts.map(value => (new Date(value)).toUTCString()).join(' : ');
}
render() {
return (
<Row className="play-slider">
<Col md={1} className="padded">
<i className={this.getPlayClass()} onClick={this.play} />
<i className="fa fa-step-forward fa-lg slider-button " onClick={this.step} />
</Col>
<Col md={11} className="padded">
<ReactBootstrapSlider
value={this.props.values}
formatter={this.formatter}
change={this.onChange}
min={this.props.start}
max={this.props.end}
step={this.props.step}
orientation={this.props.orientation}
reversed={this.props.reversed}
disabled={this.props.disabled ? 'disabled' : 'enabled'}
/>
</Col>
</Row>
);
}
}
PlaySlider.propTypes = propTypes;
PlaySlider.defaultProps = defaultProps;