UNPKG

translation-waveform-audio

Version:
177 lines (168 loc) 6.68 kB
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;