translation-waveform-audio
Version:
Waveform react audioplayer
177 lines (168 loc) • 6.68 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import ProgressBar from './ProgressBar';
import ProgressBarHandler from './ProgressBarHandler';
import style from '../styles/audioElements.css';
import Marker from './Marker';
import WaveForm from './Waveform';
class Timeline extends React.Component {
static propTypes = {
appWidth: PropTypes.number.isRequired,
duration: PropTypes.number.isRequired,
playAudio: PropTypes.bool
};
constructor(props) {
super(props);
this.state = {
showHandler: false,
barWidth: (props.appWidth < 300) ? 300 : props.appWidth,
translate: 0,
duration:0
};
this.holding = false;
this.shouldTogglePlayPause = this.props.playing;
this.changeTranslate = this.changeTranslate.bind(this);
this.receiveTime = this.receiveTime.bind(this);
this.durationTime = this.durationTime.bind(this);
this._onMouseDownProgressBar = this._onMouseDownProgressBar.bind(this);
this._onMouseOverProgressBar = this._onMouseOverProgressBar.bind(this);
this._onMouseOutProgressBar = this._onMouseOutProgressBar.bind(this);
this._onMouseDownProgressBarHandler = this._onMouseDownProgressBarHandler.bind(this);
this._onMouseUp = this._onMouseUp.bind(this);
this.finishedPlaying = this.finishedPlaying.bind(this);
this.onMouseMoveFunctionRef = null;
}
componentWillReceiveProps(nextProps) {
if (nextProps.duration !== 0 && !this.holding) {
const lengthPerSecond = this.state.barWidth / nextProps.duration;
const length = nextProps.progress * lengthPerSecond;
this.changeTranslate(length);
this.shouldTogglePlayPause = nextProps.playing;
}
}
_onMouseOverProgressBar() {
this.setState({ showHandler: true });
}
_onMouseOutProgressBar() {
this.setState({ showHandler: false });
}
_onMouseDownProgressBar(e) {
e.stopPropagation();
// console.log('Timeline: _onMouseDownProgressBar');
if (this.shouldTogglePlayPause) { this.props.togglePlayPause(); }
const timelineDisToLeft = e.target.parentNode.getBoundingClientRect().left;
const newTranslate = e.pageX - timelineDisToLeft;
this.changeTranslate(newTranslate);
this.holding = true;
this.onMouseMoveFunctionRef = this._onMouseMove(e.pageX, newTranslate);
document.addEventListener('mousemove', this.onMouseMoveFunctionRef);
document.addEventListener('mouseup', this._onMouseUp);
}
_onMouseDownProgressBarHandler(e) {
e.stopPropagation();
this.holding = true;
// console.log('Timeline: _onMouseDownProgressBarHandler');
if (this.shouldTogglePlayPause) { this.props.togglePlayPause(); }
this.onMouseMoveFunctionRef = this._onMouseMove(e.pageX, this.state.translate);
document.addEventListener('mousemove', this.onMouseMoveFunctionRef);
document.addEventListener('mouseup', this._onMouseUp);
}
_onMouseMove(mouseDownX, startTranslate) {
return (event) => {
if (this.holding) {
const translate = (event.pageX - mouseDownX) + startTranslate;
this.changeTranslate(translate);
this.props.updateProgressTime((this.state.translate / this.state.barWidth) * this.props.duration);
}
};
}
_onMouseUp() {
// console.log('Timeline: _onMouseUp()');
/* When the _onMouseUp() event happen really quick after the _onMouseDownProgressBar(),
i.e. React hasn't called setState, enqueue a togglePlayPause() to the loop. */
if (this.shouldTogglePlayPause && this.props.playing) { setTimeout(() => this.props.togglePlayPause(), 0); }
// Normally, when this.shouldTogglePlayPause is true, this.props.playing should be false, except the case above.
if (this.shouldTogglePlayPause && !this.props.playing) { this.props.togglePlayPause(); }
this.holding = false;
this.props.setProgress((this.state.translate / this.state.barWidth) * this.props.duration);
document.removeEventListener('mousemove', this.onMouseMoveFunctionRef);
document.removeEventListener('mouseup', this._onMouseUp);
}
changeTranslate(newTranslate) {
let translate = newTranslate;
const max = this.state.barWidth;
if (translate < 0) { translate = 0; }
if (translate > max) { translate = max; }
this.setState({ translate });
}
receiveTime(time) {
this.props.updateTime(time);
}
durationTime(time) {
this.props.updateDurationTime(time);
this.setState({ duration: time});
}
finishedPlaying(state){
this.props.finishedPlaying(state);
}
callMarker() {
const markerArray = [];
// console.log('Timeline props', this.props.markers);
// console.log('local props', markerObj.markers);
const receivedMarkerObject = this.props.markers;
for (const key in receivedMarkerObject) {
// normalization position = (time/duration)* barwidth
const position = ((receivedMarkerObject[key] / 44100) / (this.state.duration)) * this.state.barWidth;
markerArray.push(<Marker
style={{ overflow: 'visible' }}
visibility={true}
translate={`translate(${position})`}
text={key}
/>);
}
return (
markerArray
);
}
render() {
const handlerWidth = 12;
const handlerHeight = 12; //
const containerWidth = 950;
const containerHeight = 100;
const barHeight = 4;
const handlerHeight2 = 112; //
const containerWidth2 = this.state.barWidth;
const containerHeight2 = 10;
const overflow = 'visible';
return (
<div style={{ overflow: 'visible' }} >
<div style={{ height: containerHeight2, width: containerWidth2, transform: 'translateY(-45px)', overflow: 'visible' }}>
<ProgressBar
overflow={overflow}
width={containerWidth2}
height={handlerHeight2}
barHeight={0}
handlerWidth={handlerWidth}
translate={this.state.translate}
duration={this.props.duration}
onMouseDown={this._onMouseDownProgressBar}
onMouseOver={this._onMouseOverProgressBar}
onMouseOut={this._onMouseOutProgressBar}
>
{this.props.showMarkers ? this.callMarker() : ''}
</ProgressBar>
</div>
<div className={style.timeLine} style={{ height: containerHeight, width: containerWidth, transform: 'translateY(-4px)' }}>
<WaveForm
src={this.props.src}
pos={this.receiveTime}
durationTime={this.durationTime}
playAudio={this.props.playAudio}
finishedPlaying={this.finishedPlaying}
/>
</div>
</div>
);
}
}
export default Timeline;