diff options
Diffstat (limited to 'animism-align/frontend/views/align/containers/timeline.container.js')
| -rw-r--r-- | animism-align/frontend/views/align/containers/timeline.container.js | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/animism-align/frontend/views/align/containers/timeline.container.js b/animism-align/frontend/views/align/containers/timeline.container.js new file mode 100644 index 0000000..3795751 --- /dev/null +++ b/animism-align/frontend/views/align/containers/timeline.container.js @@ -0,0 +1,129 @@ +import React, { Component } from 'react' +// import { Link } from 'react-router-dom' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import actions from '../../../actions' +// import * as alignActions from '../align.actions' + +import Annotations from '../containers/annotations.container' +import Waveform from '../components/timeline/waveform.component' +import Ticks from '../components/timeline/ticks.component' +import Cursor from '../components/timeline/cursor.component' +import PlayButton from '../components/timeline/playButton.component' +import PlayCursor from '../components/timeline/playCursor.component' + +import { WAVEFORM_SIZE, ZOOM_STEPS } from '../constants' +import { clamp } from '../../../util' +import { positionToTime } from '../align.util' + +class Timeline extends Component { + constructor(props){ + super(props) + this.handleKeydown = this.handleKeydown.bind(this) + this.handleMouseMove = this.handleMouseMove.bind(this) + this.handleWheel = this.handleWheel.bind(this) + this.handleClick = this.handleClick.bind(this) + } + componentDidMount() { + this.bind() + } + componentWillUnmount() { + this.unbind() + } + bind() { + document.addEventListener('keydown', this.handleKeydown) + } + unbind() { + document.removeEventListener('keydown', this.handleKeydown) + } + handleKeydown(e) { + if (document.activeElement !== document.body) { + return + } + if (e.shiftKey) { + switch (e.keyCode) { + case 187: // plus + actions.align.setZoom(this.props.timeline.zoom - 1) + break + case 189: // minus + actions.align.setZoom(this.props.timeline.zoom + 1) + break + } + } else { + // console.log(e.keyCode) + switch (e.keyCode) { + case 32: // spacebar + actions.audio.toggle() + break + case 38: // up + actions.audio.jump(- ZOOM_STEPS[this.props.timeline.zoom] * 0.1) + break + case 40: // down + actions.audio.jump(ZOOM_STEPS[this.props.timeline.zoom] * 0.1) + break + } + } + } + handleWheel(e) { + let { start_ts, zoom, duration } = this.props.timeline + let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step + let widthTimeDuration = window.innerHeight * secondsPerPixel // secs per pixel + + start_ts = clamp(start_ts + e.deltaY * ZOOM_STEPS[zoom], 0, Math.max(0, duration - widthTimeDuration / 2)) + if (e.shiftKey) { + if (Math.abs(e.deltaY) < 2) return + if (e.deltaY > 0) { + actions.align.throttledSetZoom(this.props.timeline.zoom + 1) + } else { + actions.align.throttledSetZoom(this.props.timeline.zoom - 1) + } + } else if (e.altKey) { + actions.audio.jump(e.deltaY * ZOOM_STEPS[zoom]) + } else { + actions.align.setScrollPosition(start_ts) + } + } + handleMouseMove(e) { + const cursor_ts = positionToTime(e.pageY, this.props.timeline) + actions.align.setCursor(cursor_ts) + } + handleClick(e) { + const play_ts = positionToTime(e.pageY, this.props.timeline) + if (e.pageX > WAVEFORM_SIZE * 0.67) { + actions.align.showNewTimestampForm(play_ts, this.props.text) + } else { + actions.audio.seek(play_ts) + } + } + render() { + return ( + <div + className='timeline' + onWheel={this.handleWheel} + onMouseMove={this.handleMouseMove} + > + <div className='timelineColumn'> + <Waveform onClick={this.handleClick} /> + <Ticks timeline={this.props.timeline} /> + <Cursor timeline={this.props.timeline} annotation={this.props.annotation} /> + </div> + <Annotations timeline={this.props.timeline} /> + <PlayCursor /> + <PlayButton /> + </div> + ) + } +} + +const mapStateToProps = state => ({ + timeline: state.align.timeline, + annotation: state.align.annotation, + text: state.site.text, +}) + +const mapDispatchToProps = dispatch => ({ + // alignActions: bindActionCreators({ ...alignActions }, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Timeline) |
